ngx-recaptcha-v3 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/fesm2022/ngx-recaptcha-v3-core.mjs +102 -0
- package/fesm2022/ngx-recaptcha-v3-core.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-enterprise.mjs +44 -0
- package/fesm2022/ngx-recaptcha-v3-enterprise.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-forms.mjs +96 -0
- package/fesm2022/ngx-recaptcha-v3-forms.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-signals.mjs +47 -0
- package/fesm2022/ngx-recaptcha-v3-signals.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-testing.mjs +55 -0
- package/fesm2022/ngx-recaptcha-v3-testing.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-v2.mjs +222 -0
- package/fesm2022/ngx-recaptcha-v3-v2.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3-v3.mjs +89 -0
- package/fesm2022/ngx-recaptcha-v3-v3.mjs.map +1 -0
- package/fesm2022/ngx-recaptcha-v3.mjs +11 -0
- package/fesm2022/ngx-recaptcha-v3.mjs.map +1 -0
- package/package.json +1 -5
- package/types/ngx-recaptcha-v3-core.d.ts +30 -0
- package/types/ngx-recaptcha-v3-enterprise.d.ts +17 -0
- package/types/ngx-recaptcha-v3-forms.d.ts +32 -0
- package/types/ngx-recaptcha-v3-signals.d.ts +18 -0
- package/types/ngx-recaptcha-v3-testing.d.ts +27 -0
- package/types/ngx-recaptcha-v3-v2.d.ts +63 -0
- package/types/ngx-recaptcha-v3-v3.d.ts +23 -0
- package/types/ngx-recaptcha-v3.d.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.5] - 2026-06-05
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Fixed npm package issue where only README.md and CHANGELOG.md were published by removing restrictive `files` field from `package.json`.
|
|
9
|
+
- Added null/undefined token check in RecaptchaV3Service to properly handle cases where Google returns no token.
|
|
10
|
+
- Added debug console logs to RecaptchaV3Service for better troubleshooting.
|
|
11
|
+
|
|
5
12
|
## [1.0.1] - 2026-06-05
|
|
6
13
|
|
|
7
14
|
### Added
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, PLATFORM_ID, Injectable } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { BehaviorSubject, of } from 'rxjs';
|
|
5
|
+
import { shareReplay } from 'rxjs/operators';
|
|
6
|
+
|
|
7
|
+
const RECAPTCHA_CONFIG = new InjectionToken('RECAPTCHA_CONFIG');
|
|
8
|
+
|
|
9
|
+
class RecaptchaLoaderService {
|
|
10
|
+
config = inject(RECAPTCHA_CONFIG, { optional: true });
|
|
11
|
+
platformId = inject(PLATFORM_ID);
|
|
12
|
+
scriptLoaded$ = new BehaviorSubject(false);
|
|
13
|
+
isBrowser = isPlatformBrowser(this.platformId);
|
|
14
|
+
/**
|
|
15
|
+
* Loads the reCAPTCHA script.
|
|
16
|
+
* Returns an Observable emitting true when loaded, or false if not in browser.
|
|
17
|
+
*/
|
|
18
|
+
loadScript() {
|
|
19
|
+
if (!this.isBrowser) {
|
|
20
|
+
return of(false);
|
|
21
|
+
}
|
|
22
|
+
if (this.scriptLoaded$.value) {
|
|
23
|
+
return of(true);
|
|
24
|
+
}
|
|
25
|
+
this.injectScript();
|
|
26
|
+
return this.scriptLoaded$.asObservable().pipe(shareReplay(1));
|
|
27
|
+
}
|
|
28
|
+
injectScript() {
|
|
29
|
+
if (!this.isBrowser || typeof window === 'undefined')
|
|
30
|
+
return;
|
|
31
|
+
// Check if script already exists to prevent duplicate script injection
|
|
32
|
+
const existingScript = document.getElementById('ngx-recaptcha-v3-script');
|
|
33
|
+
if (existingScript) {
|
|
34
|
+
// Script is already in DOM; check if global grecaptcha is available
|
|
35
|
+
const windowRef = window;
|
|
36
|
+
if (windowRef.grecaptcha) {
|
|
37
|
+
this.scriptLoaded$.next(true);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// If script is injected but not ready, intercept load callback
|
|
41
|
+
const prevCallback = windowRef.ngRecaptchaLoaded;
|
|
42
|
+
windowRef.ngRecaptchaLoaded = () => {
|
|
43
|
+
if (prevCallback)
|
|
44
|
+
prevCallback();
|
|
45
|
+
this.scriptLoaded$.next(true);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const conf = this.config || {};
|
|
51
|
+
const useEnterprise = conf.useEnterprise || false;
|
|
52
|
+
const siteKeyQuery = conf.v3SiteKey ? `&render=${conf.v3SiteKey}` : '';
|
|
53
|
+
const hl = conf.language ? `&hl=${conf.language}` : '';
|
|
54
|
+
// Explicit domain configuration (google.com default, recaptcha.net fallback)
|
|
55
|
+
const domain = conf.recaptchaDomain || (useEnterprise ? 'recaptcha.net' : 'google.com');
|
|
56
|
+
const apiPath = useEnterprise ? 'enterprise.js' : 'api.js';
|
|
57
|
+
const script = document.createElement('script');
|
|
58
|
+
script.id = 'ngx-recaptcha-v3-script';
|
|
59
|
+
script.src = `https://www.${domain}/recaptcha/${apiPath}?onload=ngRecaptchaLoaded${siteKeyQuery}${hl}`;
|
|
60
|
+
script.async = true;
|
|
61
|
+
script.defer = true;
|
|
62
|
+
// Handle isolated unique callback
|
|
63
|
+
const windowRef = window;
|
|
64
|
+
windowRef.ngRecaptchaLoaded = () => {
|
|
65
|
+
this.scriptLoaded$.next(true);
|
|
66
|
+
};
|
|
67
|
+
let retryCount = 0;
|
|
68
|
+
const maxRetries = 3;
|
|
69
|
+
script.onerror = () => {
|
|
70
|
+
if (retryCount < maxRetries) {
|
|
71
|
+
retryCount++;
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
document.head.removeChild(script);
|
|
74
|
+
this.injectScript();
|
|
75
|
+
}, retryCount * 1000); // Linear backoff retry
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.scriptLoaded$.error(new Error('Failed to load Google reCAPTCHA script after multiple retries.'));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
document.head.appendChild(script);
|
|
82
|
+
}
|
|
83
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
84
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaLoaderService, providedIn: 'root' });
|
|
85
|
+
}
|
|
86
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaLoaderService, decorators: [{
|
|
87
|
+
type: Injectable,
|
|
88
|
+
args: [{
|
|
89
|
+
providedIn: 'root'
|
|
90
|
+
}]
|
|
91
|
+
}] });
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* Public API Surface of ngx-recaptcha-v3/core
|
|
95
|
+
*/
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generated bundle index. Do not edit.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
export { RECAPTCHA_CONFIG, RecaptchaLoaderService };
|
|
102
|
+
//# sourceMappingURL=ngx-recaptcha-v3-core.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-core.mjs","sources":["../../../projects/ngx-recaptcha-v3/core/src/tokens.ts","../../../projects/ngx-recaptcha-v3/core/src/loader.service.ts","../../../projects/ngx-recaptcha-v3/core/src/public-api.ts","../../../projects/ngx-recaptcha-v3/core/src/ngx-recaptcha-v3-core.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport interface RecaptchaConfig {\n v2SiteKey?: string;\n v3SiteKey?: string;\n language?: string;\n useEnterprise?: boolean;\n recaptchaDomain?: 'google.com' | 'recaptcha.net';\n}\n\nexport const RECAPTCHA_CONFIG = new InjectionToken<RecaptchaConfig>('RECAPTCHA_CONFIG');\n","import { inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { BehaviorSubject, Observable, of } from 'rxjs';\nimport { shareReplay } from 'rxjs/operators';\nimport { RECAPTCHA_CONFIG } from './tokens';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaLoaderService {\n private config = inject(RECAPTCHA_CONFIG, { optional: true });\n private platformId = inject(PLATFORM_ID);\n \n private scriptLoaded$ = new BehaviorSubject<boolean>(false);\n private isBrowser = isPlatformBrowser(this.platformId);\n\n /**\n * Loads the reCAPTCHA script.\n * Returns an Observable emitting true when loaded, or false if not in browser.\n */\n public loadScript(): Observable<boolean> {\n if (!this.isBrowser) {\n return of(false);\n }\n\n if (this.scriptLoaded$.value) {\n return of(true);\n }\n\n this.injectScript();\n return this.scriptLoaded$.asObservable().pipe(\n shareReplay(1)\n );\n }\n\n private injectScript(): void {\n if (!this.isBrowser || typeof window === 'undefined') return;\n\n // Check if script already exists to prevent duplicate script injection\n const existingScript = document.getElementById('ngx-recaptcha-v3-script');\n if (existingScript) {\n // Script is already in DOM; check if global grecaptcha is available\n const windowRef = window as any;\n if (windowRef.grecaptcha) {\n this.scriptLoaded$.next(true);\n } else {\n // If script is injected but not ready, intercept load callback\n const prevCallback = windowRef.ngRecaptchaLoaded;\n windowRef.ngRecaptchaLoaded = () => {\n if (prevCallback) prevCallback();\n this.scriptLoaded$.next(true);\n };\n }\n return;\n }\n\n const conf = this.config || {};\n const useEnterprise = conf.useEnterprise || false;\n const siteKeyQuery = conf.v3SiteKey ? `&render=${conf.v3SiteKey}` : '';\n const hl = conf.language ? `&hl=${conf.language}` : '';\n \n // Explicit domain configuration (google.com default, recaptcha.net fallback)\n const domain = conf.recaptchaDomain || (useEnterprise ? 'recaptcha.net' : 'google.com');\n const apiPath = useEnterprise ? 'enterprise.js' : 'api.js';\n\n const script = document.createElement('script');\n script.id = 'ngx-recaptcha-v3-script';\n script.src = `https://www.${domain}/recaptcha/${apiPath}?onload=ngRecaptchaLoaded${siteKeyQuery}${hl}`;\n script.async = true;\n script.defer = true;\n\n // Handle isolated unique callback\n const windowRef = window as any;\n windowRef.ngRecaptchaLoaded = () => {\n this.scriptLoaded$.next(true);\n };\n\n let retryCount = 0;\n const maxRetries = 3;\n\n script.onerror = () => {\n if (retryCount < maxRetries) {\n retryCount++;\n setTimeout(() => {\n document.head.removeChild(script);\n this.injectScript();\n }, retryCount * 1000); // Linear backoff retry\n } else {\n this.scriptLoaded$.error(new Error('Failed to load Google reCAPTCHA script after multiple retries.'));\n }\n };\n\n document.head.appendChild(script);\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/core\n */\n\nexport * from './tokens';\nexport * from './loader.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, PLATFORM_ID, Injectable } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { of } from 'rxjs';
|
|
5
|
+
import { RecaptchaV3Service } from 'ngx-recaptcha-v3/v3';
|
|
6
|
+
import { RECAPTCHA_CONFIG } from 'ngx-recaptcha-v3/core';
|
|
7
|
+
|
|
8
|
+
class EnterpriseRecaptchaService {
|
|
9
|
+
v3Service = inject(RecaptchaV3Service);
|
|
10
|
+
platformId = inject(PLATFORM_ID);
|
|
11
|
+
config = inject(RECAPTCHA_CONFIG, { optional: true });
|
|
12
|
+
isBrowser = isPlatformBrowser(this.platformId);
|
|
13
|
+
/**
|
|
14
|
+
* Executes score-based action verification using Google reCAPTCHA Enterprise.
|
|
15
|
+
*/
|
|
16
|
+
executeAction(action) {
|
|
17
|
+
if (!this.isBrowser) {
|
|
18
|
+
return of('');
|
|
19
|
+
}
|
|
20
|
+
if (!this.config?.useEnterprise) {
|
|
21
|
+
console.warn('RECAPTCHA_CONFIG has useEnterprise set to false. Ensure this is configured.');
|
|
22
|
+
}
|
|
23
|
+
return this.v3Service.execute(action);
|
|
24
|
+
}
|
|
25
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EnterpriseRecaptchaService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
26
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EnterpriseRecaptchaService, providedIn: 'root' });
|
|
27
|
+
}
|
|
28
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: EnterpriseRecaptchaService, decorators: [{
|
|
29
|
+
type: Injectable,
|
|
30
|
+
args: [{
|
|
31
|
+
providedIn: 'root'
|
|
32
|
+
}]
|
|
33
|
+
}] });
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Public API Surface of ngx-recaptcha-v3/enterprise
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generated bundle index. Do not edit.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export { EnterpriseRecaptchaService };
|
|
44
|
+
//# sourceMappingURL=ngx-recaptcha-v3-enterprise.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-enterprise.mjs","sources":["../../../projects/ngx-recaptcha-v3/enterprise/src/enterprise-recaptcha.service.ts","../../../projects/ngx-recaptcha-v3/enterprise/src/public-api.ts","../../../projects/ngx-recaptcha-v3/enterprise/src/ngx-recaptcha-v3-enterprise.ts"],"sourcesContent":["import { Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { Observable, of } from 'rxjs';\nimport { RecaptchaV3Service } from 'ngx-recaptcha-v3/v3';\nimport { RECAPTCHA_CONFIG } from 'ngx-recaptcha-v3/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class EnterpriseRecaptchaService {\n private v3Service = inject(RecaptchaV3Service);\n private platformId = inject(PLATFORM_ID);\n private config = inject(RECAPTCHA_CONFIG, { optional: true });\n\n private isBrowser = isPlatformBrowser(this.platformId);\n\n /**\n * Executes score-based action verification using Google reCAPTCHA Enterprise.\n */\n public executeAction(action: string): Observable<string> {\n if (!this.isBrowser) {\n return of('');\n }\n\n if (!this.config?.useEnterprise) {\n console.warn('RECAPTCHA_CONFIG has useEnterprise set to false. Ensure this is configured.');\n }\n\n return this.v3Service.execute(action);\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/enterprise\n */\n\nexport * from './enterprise-recaptcha.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;MASa,0BAA0B,CAAA;AAC7B,IAAA,SAAS,GAAG,MAAM,CAAC,kBAAkB,CAAC;AACtC,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;IAChC,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAErD,IAAA,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;AAEtD;;AAEG;AACI,IAAA,aAAa,CAAC,MAAc,EAAA;AACjC,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AACnB,YAAA,OAAO,EAAE,CAAC,EAAE,CAAC;QACf;AAEA,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE;AAC/B,YAAA,OAAO,CAAC,IAAI,CAAC,6EAA6E,CAAC;QAC7F;QAEA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC;uGApBW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,0BAA0B,cAFzB,MAAM,EAAA,CAAA;;2FAEP,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAHtC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACRD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, DestroyRef, forwardRef, Directive } from '@angular/core';
|
|
3
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { RecaptchaV2Component } from 'ngx-recaptcha-v3/v2';
|
|
6
|
+
|
|
7
|
+
class RecaptchaValueAccessorDirective {
|
|
8
|
+
host = inject(RecaptchaV2Component, { host: true, optional: true });
|
|
9
|
+
destroyRef = inject(DestroyRef);
|
|
10
|
+
onChange = () => { };
|
|
11
|
+
onTouched = () => { };
|
|
12
|
+
constructor() {
|
|
13
|
+
if (this.host) {
|
|
14
|
+
// Connect callbacks to Form, protected against memory leaks via takeUntilDestroyed
|
|
15
|
+
this.host.resolved
|
|
16
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
17
|
+
.subscribe((token) => {
|
|
18
|
+
this.onChange(token);
|
|
19
|
+
this.onTouched();
|
|
20
|
+
});
|
|
21
|
+
this.host.expired
|
|
22
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
23
|
+
.subscribe(() => {
|
|
24
|
+
this.onChange(null);
|
|
25
|
+
this.onTouched();
|
|
26
|
+
});
|
|
27
|
+
this.host.error
|
|
28
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
29
|
+
.subscribe(() => {
|
|
30
|
+
this.onChange(null);
|
|
31
|
+
this.onTouched();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Writes value from the form model.
|
|
37
|
+
* If value is empty, resets the recaptcha widget.
|
|
38
|
+
*/
|
|
39
|
+
writeValue(value) {
|
|
40
|
+
if (!value && this.host) {
|
|
41
|
+
this.host.reset();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Registers a callback function to be triggered when the value changes.
|
|
46
|
+
*/
|
|
47
|
+
registerOnChange(fn) {
|
|
48
|
+
this.onChange = fn;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Registers a callback function to be triggered when the control is touched.
|
|
52
|
+
*/
|
|
53
|
+
registerOnTouched(fn) {
|
|
54
|
+
this.onTouched = fn;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Sets disabled state. reCAPTCHA does not have a native disabled state,
|
|
58
|
+
* but we can hook this if required.
|
|
59
|
+
*/
|
|
60
|
+
setDisabledState(isDisabled) {
|
|
61
|
+
// reCAPTCHA does not support disabling natively.
|
|
62
|
+
}
|
|
63
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaValueAccessorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
64
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.0", type: RecaptchaValueAccessorDirective, isStandalone: true, selector: "ngx-recaptcha-v3[formControlName],ngx-recaptcha-v3[formControl],ngx-recaptcha-v3[ngModel]", providers: [
|
|
65
|
+
{
|
|
66
|
+
provide: NG_VALUE_ACCESSOR,
|
|
67
|
+
useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
|
|
68
|
+
multi: true
|
|
69
|
+
}
|
|
70
|
+
], ngImport: i0 });
|
|
71
|
+
}
|
|
72
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaValueAccessorDirective, decorators: [{
|
|
73
|
+
type: Directive,
|
|
74
|
+
args: [{
|
|
75
|
+
selector: 'ngx-recaptcha-v3[formControlName],ngx-recaptcha-v3[formControl],ngx-recaptcha-v3[ngModel]',
|
|
76
|
+
providers: [
|
|
77
|
+
{
|
|
78
|
+
provide: NG_VALUE_ACCESSOR,
|
|
79
|
+
useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
|
|
80
|
+
multi: true
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
standalone: true
|
|
84
|
+
}]
|
|
85
|
+
}], ctorParameters: () => [] });
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
* Public API Surface of ngx-recaptcha-v3/forms
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generated bundle index. Do not edit.
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
export { RecaptchaValueAccessorDirective };
|
|
96
|
+
//# sourceMappingURL=ngx-recaptcha-v3-forms.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-forms.mjs","sources":["../../../projects/ngx-recaptcha-v3/forms/src/recaptcha-value-accessor.directive.ts","../../../projects/ngx-recaptcha-v3/forms/src/public-api.ts","../../../projects/ngx-recaptcha-v3/forms/src/ngx-recaptcha-v3-forms.ts"],"sourcesContent":["import { Directive, forwardRef, inject, DestroyRef } from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { RecaptchaV2Component } from 'ngx-recaptcha-v3/v2';\n\n@Directive({\n selector: 'ngx-recaptcha-v3[formControlName],ngx-recaptcha-v3[formControl],ngx-recaptcha-v3[ngModel]',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => RecaptchaValueAccessorDirective),\n multi: true\n }\n ],\n standalone: true\n})\nexport class RecaptchaValueAccessorDirective implements ControlValueAccessor {\n private host = inject(RecaptchaV2Component, { host: true, optional: true });\n private destroyRef = inject(DestroyRef);\n\n private onChange: (value: string | null) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor() {\n if (this.host) {\n // Connect callbacks to Form, protected against memory leaks via takeUntilDestroyed\n this.host.resolved\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((token) => {\n this.onChange(token);\n this.onTouched();\n });\n\n this.host.expired\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.onChange(null);\n this.onTouched();\n });\n\n this.host.error\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.onChange(null);\n this.onTouched();\n });\n }\n }\n\n /**\n * Writes value from the form model.\n * If value is empty, resets the recaptcha widget.\n */\n public writeValue(value: string | null): void {\n if (!value && this.host) {\n this.host.reset();\n }\n }\n\n /**\n * Registers a callback function to be triggered when the value changes.\n */\n public registerOnChange(fn: (value: string | null) => void): void {\n this.onChange = fn;\n }\n\n /**\n * Registers a callback function to be triggered when the control is touched.\n */\n public registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n /**\n * Sets disabled state. reCAPTCHA does not have a native disabled state,\n * but we can hook this if required.\n */\n public setDisabledState?(isDisabled: boolean): void {\n // reCAPTCHA does not support disabling natively.\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/forms\n */\n\nexport * from './recaptcha-value-accessor.directive';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;MAgBa,+BAA+B,CAAA;AAClC,IAAA,IAAI,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACnE,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE/B,IAAA,QAAQ,GAAmC,MAAK,EAAE,CAAC;AACnD,IAAA,SAAS,GAAe,MAAK,EAAE,CAAC;AAExC,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE;;YAEb,IAAI,CAAC,IAAI,CAAC;AACP,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,iBAAA,SAAS,CAAC,CAAC,KAAK,KAAI;AACnB,gBAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACpB,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,CAAC,CAAC;YAEJ,IAAI,CAAC,IAAI,CAAC;AACP,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;iBACxC,SAAS,CAAC,MAAK;AACd,gBAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnB,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,CAAC,CAAC;YAEJ,IAAI,CAAC,IAAI,CAAC;AACP,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;iBACxC,SAAS,CAAC,MAAK;AACd,gBAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnB,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,CAAC,CAAC;QACN;IACF;AAEA;;;AAGG;AACI,IAAA,UAAU,CAAC,KAAoB,EAAA;AACpC,QAAA,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE;AACvB,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;QACnB;IACF;AAEA;;AAEG;AACI,IAAA,gBAAgB,CAAC,EAAkC,EAAA;AACxD,QAAA,IAAI,CAAC,QAAQ,GAAG,EAAE;IACpB;AAEA;;AAEG;AACI,IAAA,iBAAiB,CAAC,EAAc,EAAA;AACrC,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;IACrB;AAEA;;;AAGG;AACI,IAAA,gBAAgB,CAAE,UAAmB,EAAA;;IAE5C;uGA/DW,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA/B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2FAAA,EAAA,SAAA,EAT/B;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;AAC1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,+BAA+B,CAAC;AAC9D,gBAAA,KAAK,EAAE;AACR;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAGU,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAX3C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,2FAA2F;AACrG,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;AAC1B,4BAAA,WAAW,EAAE,UAAU,CAAC,qCAAqC,CAAC;AAC9D,4BAAA,KAAK,EAAE;AACR;AACF,qBAAA;AACD,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACfD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { signal, computed, Injectable } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
class RecaptchaSignalService {
|
|
5
|
+
_token = signal(null, /* @ts-ignore */
|
|
6
|
+
...(ngDevMode ? [{ debugName: "_token" }] : /* istanbul ignore next */ []));
|
|
7
|
+
_loading = signal(false, /* @ts-ignore */
|
|
8
|
+
...(ngDevMode ? [{ debugName: "_loading" }] : /* istanbul ignore next */ []));
|
|
9
|
+
_error = signal(null, /* @ts-ignore */
|
|
10
|
+
...(ngDevMode ? [{ debugName: "_error" }] : /* istanbul ignore next */ []));
|
|
11
|
+
// Simplified Signals API (No redundant computed wraps)
|
|
12
|
+
token = this._token.asReadonly();
|
|
13
|
+
loading = this._loading.asReadonly();
|
|
14
|
+
error = this._error.asReadonly();
|
|
15
|
+
verified = computed(() => !!this._token(), /* @ts-ignore */
|
|
16
|
+
...(ngDevMode ? [{ debugName: "verified" }] : /* istanbul ignore next */ []));
|
|
17
|
+
setToken(token) {
|
|
18
|
+
this._token.set(token);
|
|
19
|
+
this._error.set(null);
|
|
20
|
+
}
|
|
21
|
+
setError(errorMsg) {
|
|
22
|
+
this._token.set(null);
|
|
23
|
+
this._error.set(errorMsg);
|
|
24
|
+
}
|
|
25
|
+
setLoading(isLoading) {
|
|
26
|
+
this._loading.set(isLoading);
|
|
27
|
+
}
|
|
28
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaSignalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
29
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaSignalService, providedIn: 'root' });
|
|
30
|
+
}
|
|
31
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaSignalService, decorators: [{
|
|
32
|
+
type: Injectable,
|
|
33
|
+
args: [{
|
|
34
|
+
providedIn: 'root'
|
|
35
|
+
}]
|
|
36
|
+
}] });
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* Public API Surface of ngx-recaptcha-v3/signals
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Generated bundle index. Do not edit.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export { RecaptchaSignalService };
|
|
47
|
+
//# sourceMappingURL=ngx-recaptcha-v3-signals.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-signals.mjs","sources":["../../../projects/ngx-recaptcha-v3/signals/src/recaptcha-signal.service.ts","../../../projects/ngx-recaptcha-v3/signals/src/public-api.ts","../../../projects/ngx-recaptcha-v3/signals/src/ngx-recaptcha-v3-signals.ts"],"sourcesContent":["import { Injectable, signal, computed } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaSignalService {\n private _token = signal<string | null>(null);\n private _loading = signal<boolean>(false);\n private _error = signal<string | null>(null);\n\n // Simplified Signals API (No redundant computed wraps)\n public readonly token = this._token.asReadonly();\n public readonly loading = this._loading.asReadonly();\n public readonly error = this._error.asReadonly();\n public readonly verified = computed(() => !!this._token());\n\n public setToken(token: string | null): void {\n this._token.set(token);\n this._error.set(null);\n }\n\n public setError(errorMsg: string | null): void {\n this._token.set(null);\n this._error.set(errorMsg);\n }\n\n public setLoading(isLoading: boolean): void {\n this._loading.set(isLoading);\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/signals\n */\n\nexport * from './recaptcha-signal.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAKa,sBAAsB,CAAA;IACzB,MAAM,GAAG,MAAM,CAAgB,IAAI;+EAAC;IACpC,QAAQ,GAAG,MAAM,CAAU,KAAK;iFAAC;IACjC,MAAM,GAAG,MAAM,CAAgB,IAAI;+EAAC;;AAG5B,IAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AAChC,IAAA,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE;AACpC,IAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;IAChC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;iFAAC;AAEnD,IAAA,QAAQ,CAAC,KAAoB,EAAA;AAClC,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;IACvB;AAEO,IAAA,QAAQ,CAAC,QAAuB,EAAA;AACrC,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC3B;AAEO,IAAA,UAAU,CAAC,SAAkB,EAAA;AAClC,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;IAC9B;uGAvBW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cAFrB,MAAM,EAAA,CAAA;;2FAEP,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAHlC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACJD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { of } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
class RecaptchaMockV3Service {
|
|
6
|
+
mockToken = 'mock-v3-recaptcha-token';
|
|
7
|
+
/**
|
|
8
|
+
* Configures the mock token to be returned upon execution.
|
|
9
|
+
*/
|
|
10
|
+
setMockToken(token) {
|
|
11
|
+
this.mockToken = token;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Mock execute returning a pre-configured token immediately.
|
|
15
|
+
*/
|
|
16
|
+
execute(action) {
|
|
17
|
+
return of(this.mockToken);
|
|
18
|
+
}
|
|
19
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockV3Service, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
20
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockV3Service, providedIn: 'root' });
|
|
21
|
+
}
|
|
22
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockV3Service, decorators: [{
|
|
23
|
+
type: Injectable,
|
|
24
|
+
args: [{
|
|
25
|
+
providedIn: 'root'
|
|
26
|
+
}]
|
|
27
|
+
}] });
|
|
28
|
+
|
|
29
|
+
class RecaptchaMockLoaderService {
|
|
30
|
+
/**
|
|
31
|
+
* Immediately resolves to true, bypassing network and DOM script injections.
|
|
32
|
+
*/
|
|
33
|
+
loadScript() {
|
|
34
|
+
return of(true);
|
|
35
|
+
}
|
|
36
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
37
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockLoaderService, providedIn: 'root' });
|
|
38
|
+
}
|
|
39
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaMockLoaderService, decorators: [{
|
|
40
|
+
type: Injectable,
|
|
41
|
+
args: [{
|
|
42
|
+
providedIn: 'root'
|
|
43
|
+
}]
|
|
44
|
+
}] });
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Public API Surface of ngx-recaptcha-v3/testing
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generated bundle index. Do not edit.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export { RecaptchaMockLoaderService, RecaptchaMockV3Service };
|
|
55
|
+
//# sourceMappingURL=ngx-recaptcha-v3-testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-testing.mjs","sources":["../../../projects/ngx-recaptcha-v3/testing/src/recaptcha-mock.service.ts","../../../projects/ngx-recaptcha-v3/testing/src/recaptcha-mock-loader.service.ts","../../../projects/ngx-recaptcha-v3/testing/src/public-api.ts","../../../projects/ngx-recaptcha-v3/testing/src/ngx-recaptcha-v3-testing.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { Observable, of } from 'rxjs';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaMockV3Service {\n private mockToken = 'mock-v3-recaptcha-token';\n\n /**\n * Configures the mock token to be returned upon execution.\n */\n public setMockToken(token: string): void {\n this.mockToken = token;\n }\n\n /**\n * Mock execute returning a pre-configured token immediately.\n */\n public execute(action: string): Observable<string> {\n return of(this.mockToken);\n }\n}\n","import { Injectable } from '@angular/core';\nimport { Observable, of } from 'rxjs';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaMockLoaderService {\n /**\n * Immediately resolves to true, bypassing network and DOM script injections.\n */\n public loadScript(): Observable<boolean> {\n return of(true);\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/testing\n */\n\nexport * from './recaptcha-mock.service';\nexport * from './recaptcha-mock-loader.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAMa,sBAAsB,CAAA;IACzB,SAAS,GAAG,yBAAyB;AAE7C;;AAEG;AACI,IAAA,YAAY,CAAC,KAAa,EAAA;AAC/B,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK;IACxB;AAEA;;AAEG;AACI,IAAA,OAAO,CAAC,MAAc,EAAA;AAC3B,QAAA,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;IAC3B;uGAfW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cAFrB,MAAM,EAAA,CAAA;;2FAEP,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAHlC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;MCCY,0BAA0B,CAAA;AACrC;;AAEG;IACI,UAAU,GAAA;AACf,QAAA,OAAO,EAAE,CAAC,IAAI,CAAC;IACjB;uGANW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,0BAA0B,cAFzB,MAAM,EAAA,CAAA;;2FAEP,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAHtC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACLD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, EventEmitter, inject, NgZone, ChangeDetectorRef, PLATFORM_ID, DestroyRef, effect, Output, ViewChild, Component, Injectable } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { RecaptchaLoaderService } from 'ngx-recaptcha-v3/core';
|
|
6
|
+
|
|
7
|
+
class RecaptchaV2Component {
|
|
8
|
+
wrapper;
|
|
9
|
+
container;
|
|
10
|
+
siteKey = input.required(/* @ts-ignore */
|
|
11
|
+
...(ngDevMode ? [{ debugName: "siteKey" }] : /* istanbul ignore next */ []));
|
|
12
|
+
theme = input('light', /* @ts-ignore */
|
|
13
|
+
...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
14
|
+
size = input('normal', /* @ts-ignore */
|
|
15
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
16
|
+
tabIndex = input(0, /* @ts-ignore */
|
|
17
|
+
...(ngDevMode ? [{ debugName: "tabIndex" }] : /* istanbul ignore next */ []));
|
|
18
|
+
resolved = new EventEmitter();
|
|
19
|
+
error = new EventEmitter();
|
|
20
|
+
expired = new EventEmitter();
|
|
21
|
+
loader = inject(RecaptchaLoaderService);
|
|
22
|
+
ngZone = inject(NgZone);
|
|
23
|
+
cdr = inject(ChangeDetectorRef);
|
|
24
|
+
platformId = inject(PLATFORM_ID);
|
|
25
|
+
destroyRef = inject(DestroyRef);
|
|
26
|
+
widgetId = null;
|
|
27
|
+
isBrowser = isPlatformBrowser(this.platformId);
|
|
28
|
+
scriptLoaded = false;
|
|
29
|
+
viewReady = false;
|
|
30
|
+
constructor() {
|
|
31
|
+
effect(() => {
|
|
32
|
+
// Read all signal inputs to register them as dependencies
|
|
33
|
+
const sk = this.siteKey();
|
|
34
|
+
const th = this.theme();
|
|
35
|
+
const sz = this.size();
|
|
36
|
+
const ti = this.tabIndex();
|
|
37
|
+
if (this.isBrowser && this.scriptLoaded && this.viewReady && this.wrapper?.nativeElement) {
|
|
38
|
+
this.reRenderWidget();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
ngOnInit() {
|
|
43
|
+
if (this.isBrowser) {
|
|
44
|
+
this.loader.loadScript()
|
|
45
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
46
|
+
.subscribe((loaded) => {
|
|
47
|
+
if (loaded) {
|
|
48
|
+
this.scriptLoaded = true;
|
|
49
|
+
if (this.viewReady && this.wrapper?.nativeElement) {
|
|
50
|
+
this.renderWidget();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
ngAfterViewInit() {
|
|
57
|
+
this.viewReady = true;
|
|
58
|
+
if (this.isBrowser && this.scriptLoaded && this.wrapper?.nativeElement) {
|
|
59
|
+
this.renderWidget();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
reRenderWidget() {
|
|
63
|
+
if (!this.wrapper?.nativeElement)
|
|
64
|
+
return;
|
|
65
|
+
this.cleanupWidget();
|
|
66
|
+
this.renderWidget();
|
|
67
|
+
}
|
|
68
|
+
cleanupWidget() {
|
|
69
|
+
if (this.widgetId !== null) {
|
|
70
|
+
const windowRef = window;
|
|
71
|
+
const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;
|
|
72
|
+
if (grecaptchaObj) {
|
|
73
|
+
try {
|
|
74
|
+
grecaptchaObj.reset(this.widgetId);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
// ignore errors on reset
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.widgetId = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
renderWidget() {
|
|
84
|
+
if (!this.isBrowser || !this.scriptLoaded || !this.wrapper?.nativeElement)
|
|
85
|
+
return;
|
|
86
|
+
// Replace the inner container with a brand new div
|
|
87
|
+
this.wrapper.nativeElement.innerHTML = '<div></div>';
|
|
88
|
+
const newContainer = this.wrapper.nativeElement.firstElementChild;
|
|
89
|
+
this.ngZone.runOutsideAngular(() => {
|
|
90
|
+
const windowRef = window;
|
|
91
|
+
const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;
|
|
92
|
+
if (!grecaptchaObj) {
|
|
93
|
+
console.warn('Google reCAPTCHA script is not loaded or missing.');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.widgetId = grecaptchaObj.render(newContainer, {
|
|
97
|
+
sitekey: this.siteKey(),
|
|
98
|
+
theme: this.theme(),
|
|
99
|
+
size: this.size(),
|
|
100
|
+
tabindex: this.tabIndex(),
|
|
101
|
+
callback: (token) => {
|
|
102
|
+
this.ngZone.run(() => {
|
|
103
|
+
this.resolved.emit(token);
|
|
104
|
+
this.cdr.markForCheck();
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
'expired-callback': () => {
|
|
108
|
+
this.ngZone.run(() => {
|
|
109
|
+
this.expired.emit();
|
|
110
|
+
this.cdr.markForCheck();
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
'error-callback': () => {
|
|
114
|
+
this.ngZone.run(() => {
|
|
115
|
+
this.error.emit();
|
|
116
|
+
this.cdr.markForCheck();
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Manually executes an invisible reCAPTCHA v2 widget.
|
|
124
|
+
*/
|
|
125
|
+
execute() {
|
|
126
|
+
if (!this.isBrowser || this.widgetId === null)
|
|
127
|
+
return;
|
|
128
|
+
const windowRef = window;
|
|
129
|
+
const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;
|
|
130
|
+
if (grecaptchaObj) {
|
|
131
|
+
this.ngZone.runOutsideAngular(() => {
|
|
132
|
+
grecaptchaObj.execute(this.widgetId);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Resets the reCAPTCHA widget instance state.
|
|
138
|
+
*/
|
|
139
|
+
reset() {
|
|
140
|
+
if (!this.isBrowser || this.widgetId === null)
|
|
141
|
+
return;
|
|
142
|
+
const windowRef = window;
|
|
143
|
+
const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;
|
|
144
|
+
if (grecaptchaObj) {
|
|
145
|
+
this.ngZone.runOutsideAngular(() => {
|
|
146
|
+
grecaptchaObj.reset(this.widgetId);
|
|
147
|
+
});
|
|
148
|
+
this.resolved.emit(null);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
152
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.0", type: RecaptchaV2Component, isStandalone: true, selector: "ngx-recaptcha-v3", inputs: { siteKey: { classPropertyName: "siteKey", publicName: "siteKey", isSignal: true, isRequired: true, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resolved: "resolved", error: "error", expired: "expired" }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `<div #wrapper><div #container></div></div>`, isInline: true, styles: [":host{display:inline-block;min-height:78px}\n"] });
|
|
153
|
+
}
|
|
154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV2Component, decorators: [{
|
|
155
|
+
type: Component,
|
|
156
|
+
args: [{ selector: 'ngx-recaptcha-v3', template: `<div #wrapper><div #container></div></div>`, standalone: true, styles: [":host{display:inline-block;min-height:78px}\n"] }]
|
|
157
|
+
}], ctorParameters: () => [], propDecorators: { wrapper: [{
|
|
158
|
+
type: ViewChild,
|
|
159
|
+
args: ['wrapper', { static: false }]
|
|
160
|
+
}], container: [{
|
|
161
|
+
type: ViewChild,
|
|
162
|
+
args: ['container', { static: false }]
|
|
163
|
+
}], siteKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "siteKey", required: true }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], resolved: [{
|
|
164
|
+
type: Output
|
|
165
|
+
}], error: [{
|
|
166
|
+
type: Output
|
|
167
|
+
}], expired: [{
|
|
168
|
+
type: Output
|
|
169
|
+
}] } });
|
|
170
|
+
|
|
171
|
+
class RecaptchaV2Service {
|
|
172
|
+
instances = new Map();
|
|
173
|
+
/**
|
|
174
|
+
* Registers a V2 widget instance under a specific key.
|
|
175
|
+
*/
|
|
176
|
+
register(key, component) {
|
|
177
|
+
this.instances.set(key, component);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Unregisters a V2 widget instance.
|
|
181
|
+
*/
|
|
182
|
+
unregister(key) {
|
|
183
|
+
this.instances.delete(key);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Executes a registered invisible V2 component by key.
|
|
187
|
+
*/
|
|
188
|
+
execute(key) {
|
|
189
|
+
const comp = this.instances.get(key);
|
|
190
|
+
if (comp) {
|
|
191
|
+
comp.execute();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Resets a registered V2 component by key.
|
|
196
|
+
*/
|
|
197
|
+
reset(key) {
|
|
198
|
+
const comp = this.instances.get(key);
|
|
199
|
+
if (comp) {
|
|
200
|
+
comp.reset();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV2Service, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
204
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV2Service, providedIn: 'root' });
|
|
205
|
+
}
|
|
206
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV2Service, decorators: [{
|
|
207
|
+
type: Injectable,
|
|
208
|
+
args: [{
|
|
209
|
+
providedIn: 'root'
|
|
210
|
+
}]
|
|
211
|
+
}] });
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* Public API Surface of ngx-recaptcha-v3/v2
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Generated bundle index. Do not edit.
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
export { RecaptchaV2Component, RecaptchaV2Service };
|
|
222
|
+
//# sourceMappingURL=ngx-recaptcha-v3-v2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-v2.mjs","sources":["../../../projects/ngx-recaptcha-v3/v2/src/recaptcha-v2.component.ts","../../../projects/ngx-recaptcha-v3/v2/src/recaptcha-v2.service.ts","../../../projects/ngx-recaptcha-v3/v2/src/public-api.ts","../../../projects/ngx-recaptcha-v3/v2/src/ngx-recaptcha-v3-v2.ts"],"sourcesContent":["import { \n Component, \n ElementRef, \n EventEmitter, \n Output, \n NgZone, \n ChangeDetectorRef, \n ViewChild,\n inject,\n DestroyRef,\n effect,\n input,\n OnInit,\n AfterViewInit,\n PLATFORM_ID\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { RecaptchaLoaderService } from 'ngx-recaptcha-v3/core';\n\n@Component({\n selector: 'ngx-recaptcha-v3',\n template: `<div #wrapper><div #container></div></div>`,\n styles: [`:host { display: inline-block; min-height: 78px; }`],\n standalone: true\n})\nexport class RecaptchaV2Component implements OnInit, AfterViewInit {\n @ViewChild('wrapper', { static: false }) wrapper?: ElementRef<HTMLDivElement>;\n @ViewChild('container', { static: false }) container?: ElementRef<HTMLDivElement>;\n\n siteKey = input.required<string>();\n theme = input<'light' | 'dark'>('light');\n size = input<'normal' | 'compact' | 'invisible'>('normal');\n tabIndex = input(0);\n\n @Output() resolved = new EventEmitter<string | null>();\n @Output() error = new EventEmitter<void>();\n @Output() expired = new EventEmitter<void>();\n\n private loader = inject(RecaptchaLoaderService);\n private ngZone = inject(NgZone);\n private cdr = inject(ChangeDetectorRef);\n private platformId = inject(PLATFORM_ID);\n private destroyRef = inject(DestroyRef);\n\n private widgetId: number | null = null;\n private isBrowser = isPlatformBrowser(this.platformId);\n private scriptLoaded = false;\n private viewReady = false;\n\n constructor() {\n effect(() => {\n // Read all signal inputs to register them as dependencies\n const sk = this.siteKey();\n const th = this.theme();\n const sz = this.size();\n const ti = this.tabIndex();\n\n if (this.isBrowser && this.scriptLoaded && this.viewReady && this.wrapper?.nativeElement) {\n this.reRenderWidget();\n }\n });\n }\n\n ngOnInit(): void {\n if (this.isBrowser) {\n this.loader.loadScript()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((loaded) => {\n if (loaded) {\n this.scriptLoaded = true;\n if (this.viewReady && this.wrapper?.nativeElement) {\n this.renderWidget();\n }\n }\n });\n }\n }\n\n ngAfterViewInit(): void {\n this.viewReady = true;\n if (this.isBrowser && this.scriptLoaded && this.wrapper?.nativeElement) {\n this.renderWidget();\n }\n }\n\n private reRenderWidget(): void {\n if (!this.wrapper?.nativeElement) return;\n this.cleanupWidget();\n this.renderWidget();\n }\n\n private cleanupWidget(): void {\n if (this.widgetId !== null) {\n const windowRef = window as any;\n const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;\n if (grecaptchaObj) {\n try {\n grecaptchaObj.reset(this.widgetId);\n } catch (e) {\n // ignore errors on reset\n }\n }\n this.widgetId = null;\n }\n }\n\n private renderWidget(): void {\n if (!this.isBrowser || !this.scriptLoaded || !this.wrapper?.nativeElement) return;\n\n // Replace the inner container with a brand new div\n this.wrapper.nativeElement.innerHTML = '<div></div>';\n const newContainer = this.wrapper.nativeElement.firstElementChild as HTMLDivElement;\n\n this.ngZone.runOutsideAngular(() => {\n const windowRef = window as any;\n const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;\n\n if (!grecaptchaObj) {\n console.warn('Google reCAPTCHA script is not loaded or missing.');\n return;\n }\n\n this.widgetId = grecaptchaObj.render(newContainer, {\n sitekey: this.siteKey(),\n theme: this.theme(),\n size: this.size(),\n tabindex: this.tabIndex(),\n callback: (token: string) => {\n this.ngZone.run(() => {\n this.resolved.emit(token);\n this.cdr.markForCheck();\n });\n },\n 'expired-callback': () => {\n this.ngZone.run(() => {\n this.expired.emit();\n this.cdr.markForCheck();\n });\n },\n 'error-callback': () => {\n this.ngZone.run(() => {\n this.error.emit();\n this.cdr.markForCheck();\n });\n }\n });\n });\n }\n\n /**\n * Manually executes an invisible reCAPTCHA v2 widget.\n */\n public execute(): void {\n if (!this.isBrowser || this.widgetId === null) return;\n\n const windowRef = window as any;\n const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;\n\n if (grecaptchaObj) {\n this.ngZone.runOutsideAngular(() => {\n grecaptchaObj.execute(this.widgetId);\n });\n }\n }\n\n /**\n * Resets the reCAPTCHA widget instance state.\n */\n public reset(): void {\n if (!this.isBrowser || this.widgetId === null) return;\n\n const windowRef = window as any;\n const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;\n\n if (grecaptchaObj) {\n this.ngZone.runOutsideAngular(() => {\n grecaptchaObj.reset(this.widgetId);\n });\n this.resolved.emit(null);\n }\n }\n}\n","import { Injectable } from '@angular/core';\nimport { RecaptchaV2Component } from './recaptcha-v2.component';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaV2Service {\n private instances = new Map<string, RecaptchaV2Component>();\n\n /**\n * Registers a V2 widget instance under a specific key.\n */\n public register(key: string, component: RecaptchaV2Component): void {\n this.instances.set(key, component);\n }\n\n /**\n * Unregisters a V2 widget instance.\n */\n public unregister(key: string): void {\n this.instances.delete(key);\n }\n\n /**\n * Executes a registered invisible V2 component by key.\n */\n public execute(key: string): void {\n const comp = this.instances.get(key);\n if (comp) {\n comp.execute();\n }\n }\n\n /**\n * Resets a registered V2 component by key.\n */\n public reset(key: string): void {\n const comp = this.instances.get(key);\n if (comp) {\n comp.reset();\n }\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/v2\n */\n\nexport * from './recaptcha-v2.component';\nexport * from './recaptcha-v2.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;MA0Ba,oBAAoB,CAAA;AACU,IAAA,OAAO;AACL,IAAA,SAAS;IAEpD,OAAO,GAAG,KAAK,CAAC,QAAQ;gFAAU;IAClC,KAAK,GAAG,KAAK,CAAmB,OAAO;8EAAC;IACxC,IAAI,GAAG,KAAK,CAAqC,QAAQ;6EAAC;IAC1D,QAAQ,GAAG,KAAK,CAAC,CAAC;iFAAC;AAET,IAAA,QAAQ,GAAG,IAAI,YAAY,EAAiB;AAC5C,IAAA,KAAK,GAAG,IAAI,YAAY,EAAQ;AAChC,IAAA,OAAO,GAAG,IAAI,YAAY,EAAQ;AAEpC,IAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACvC,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAC/B,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;AAChC,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAE/B,QAAQ,GAAkB,IAAI;AAC9B,IAAA,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;IAC9C,YAAY,GAAG,KAAK;IACpB,SAAS,GAAG,KAAK;AAEzB,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;;AAEV,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;AACzB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE;AACvB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;AACtB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE;AAE1B,YAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;gBACxF,IAAI,CAAC,cAAc,EAAE;YACvB;AACF,QAAA,CAAC,CAAC;IACJ;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE;AAClB,YAAA,IAAI,CAAC,MAAM,CAAC,UAAU;AACnB,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,iBAAA,SAAS,CAAC,CAAC,MAAM,KAAI;gBACpB,IAAI,MAAM,EAAE;AACV,oBAAA,IAAI,CAAC,YAAY,GAAG,IAAI;oBACxB,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;wBACjD,IAAI,CAAC,YAAY,EAAE;oBACrB;gBACF;AACF,YAAA,CAAC,CAAC;QACN;IACF;IAEA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;YACtE,IAAI,CAAC,YAAY,EAAE;QACrB;IACF;IAEQ,cAAc,GAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa;YAAE;QAClC,IAAI,CAAC,aAAa,EAAE;QACpB,IAAI,CAAC,YAAY,EAAE;IACrB;IAEQ,aAAa,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE;YAC1B,MAAM,SAAS,GAAG,MAAa;YAC/B,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,EAAE,UAAU,IAAI,SAAS,CAAC,UAAU;YAC9E,IAAI,aAAa,EAAE;AACjB,gBAAA,IAAI;AACF,oBAAA,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACpC;gBAAE,OAAO,CAAC,EAAE;;gBAEZ;YACF;AACA,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACtB;IACF;IAEQ,YAAY,GAAA;AAClB,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa;YAAE;;QAG3E,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,GAAG,aAAa;QACpD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,iBAAmC;AAEnF,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;YACjC,MAAM,SAAS,GAAG,MAAa;YAC/B,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,EAAE,UAAU,IAAI,SAAS,CAAC,UAAU;YAE9E,IAAI,CAAC,aAAa,EAAE;AAClB,gBAAA,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC;gBACjE;YACF;YAEA,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,YAAY,EAAE;AACjD,gBAAA,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;AACvB,gBAAA,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;AACnB,gBAAA,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;AACjB,gBAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;AACzB,gBAAA,QAAQ,EAAE,CAAC,KAAa,KAAI;AAC1B,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,wBAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;AACzB,wBAAA,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;AACzB,oBAAA,CAAC,CAAC;gBACJ,CAAC;gBACD,kBAAkB,EAAE,MAAK;AACvB,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,wBAAA,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;AACnB,wBAAA,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;AACzB,oBAAA,CAAC,CAAC;gBACJ,CAAC;gBACD,gBAAgB,EAAE,MAAK;AACrB,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,wBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;AACjB,wBAAA,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE;AACzB,oBAAA,CAAC,CAAC;gBACJ;AACD,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;AAEA;;AAEG;IACI,OAAO,GAAA;QACZ,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE;QAE/C,MAAM,SAAS,GAAG,MAAa;QAC/B,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,EAAE,UAAU,IAAI,SAAS,CAAC,UAAU;QAE9E,IAAI,aAAa,EAAE;AACjB,YAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,gBAAA,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;AAEG;IACI,KAAK,GAAA;QACV,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE;QAE/C,MAAM,SAAS,GAAG,MAAa;QAC/B,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,EAAE,UAAU,IAAI,SAAS,CAAC,UAAU;QAE9E,IAAI,aAAa,EAAE;AACjB,YAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACjC,gBAAA,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;AACpC,YAAA,CAAC,CAAC;AACF,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1B;IACF;uGA3JW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,oBAAoB,u0BAJrB,CAAA,0CAAA,CAA4C,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,+CAAA,CAAA,EAAA,CAAA;;2FAI3C,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBANhC,SAAS;+BACE,kBAAkB,EAAA,QAAA,EAClB,CAAA,0CAAA,CAA4C,EAAA,UAAA,EAE1C,IAAI,EAAA,MAAA,EAAA,CAAA,+CAAA,CAAA,EAAA;;sBAGf,SAAS;AAAC,gBAAA,IAAA,EAAA,CAAA,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;;sBACtC,SAAS;AAAC,gBAAA,IAAA,EAAA,CAAA,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;;sBAOxC;;sBACA;;sBACA;;;MC/BU,kBAAkB,CAAA;AACrB,IAAA,SAAS,GAAG,IAAI,GAAG,EAAgC;AAE3D;;AAEG;IACI,QAAQ,CAAC,GAAW,EAAE,SAA+B,EAAA;QAC1D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC;IACpC;AAEA;;AAEG;AACI,IAAA,UAAU,CAAC,GAAW,EAAA;AAC3B,QAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;IAC5B;AAEA;;AAEG;AACI,IAAA,OAAO,CAAC,GAAW,EAAA;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,OAAO,EAAE;QAChB;IACF;AAEA;;AAEG;AACI,IAAA,KAAK,CAAC,GAAW,EAAA;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,KAAK,EAAE;QACd;IACF;uGAnCW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,kBAAkB,cAFjB,MAAM,EAAA,CAAA;;2FAEP,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAH9B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACLD;;AAEG;;ACFH;;AAEG;;;;"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, NgZone, PLATFORM_ID, Injectable } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { Observable, firstValueFrom } from 'rxjs';
|
|
5
|
+
import { switchMap } from 'rxjs/operators';
|
|
6
|
+
import { RecaptchaLoaderService, RECAPTCHA_CONFIG } from 'ngx-recaptcha-v3/core';
|
|
7
|
+
|
|
8
|
+
class RecaptchaV3Service {
|
|
9
|
+
loader = inject(RecaptchaLoaderService);
|
|
10
|
+
ngZone = inject(NgZone);
|
|
11
|
+
platformId = inject(PLATFORM_ID);
|
|
12
|
+
config = inject(RECAPTCHA_CONFIG, { optional: true });
|
|
13
|
+
isBrowser = isPlatformBrowser(this.platformId);
|
|
14
|
+
/**
|
|
15
|
+
* Executes a specific action on the V3 siteKey and yields the resolution token as an Observable.
|
|
16
|
+
*/
|
|
17
|
+
execute(action) {
|
|
18
|
+
if (!this.isBrowser) {
|
|
19
|
+
return new Observable((subscriber) => {
|
|
20
|
+
subscriber.next('');
|
|
21
|
+
subscriber.complete();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const siteKey = this.config?.v3SiteKey;
|
|
25
|
+
if (!siteKey) {
|
|
26
|
+
return new Observable((subscriber) => {
|
|
27
|
+
subscriber.error(new Error('reCAPTCHA v3 siteKey is not provided in RECAPTCHA_CONFIG.'));
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return this.loader.loadScript().pipe(switchMap(() => {
|
|
31
|
+
return new Observable((subscriber) => {
|
|
32
|
+
this.ngZone.runOutsideAngular(() => {
|
|
33
|
+
const windowRef = window;
|
|
34
|
+
const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;
|
|
35
|
+
if (!grecaptchaObj) {
|
|
36
|
+
this.ngZone.run(() => {
|
|
37
|
+
subscriber.error(new Error('Google reCAPTCHA script is not loaded or missing.'));
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
grecaptchaObj.ready(() => {
|
|
42
|
+
grecaptchaObj.execute(siteKey, { action })
|
|
43
|
+
.then((token) => {
|
|
44
|
+
this.ngZone.run(() => {
|
|
45
|
+
if (!token) {
|
|
46
|
+
subscriber.error(new Error('Google reCAPTCHA returned null/undefined token.'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
subscriber.next(token);
|
|
50
|
+
subscriber.complete();
|
|
51
|
+
});
|
|
52
|
+
})
|
|
53
|
+
.catch((err) => {
|
|
54
|
+
this.ngZone.run(() => {
|
|
55
|
+
subscriber.error(err);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Executes a specific action on the V3 siteKey and yields the resolution token as a Promise.
|
|
65
|
+
* Ideal for modern async/await execution pipelines.
|
|
66
|
+
*/
|
|
67
|
+
executeAsync(action) {
|
|
68
|
+
return firstValueFrom(this.execute(action));
|
|
69
|
+
}
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV3Service, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
71
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV3Service, providedIn: 'root' });
|
|
72
|
+
}
|
|
73
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RecaptchaV3Service, decorators: [{
|
|
74
|
+
type: Injectable,
|
|
75
|
+
args: [{
|
|
76
|
+
providedIn: 'root'
|
|
77
|
+
}]
|
|
78
|
+
}] });
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Public API Surface of ngx-recaptcha-v3/v3
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generated bundle index. Do not edit.
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
export { RecaptchaV3Service };
|
|
89
|
+
//# sourceMappingURL=ngx-recaptcha-v3-v3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3-v3.mjs","sources":["../../../projects/ngx-recaptcha-v3/v3/src/recaptcha-v3.service.ts","../../../projects/ngx-recaptcha-v3/v3/src/public-api.ts","../../../projects/ngx-recaptcha-v3/v3/src/ngx-recaptcha-v3-v3.ts"],"sourcesContent":["import { Injectable, NgZone, Inject, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { Observable, firstValueFrom } from 'rxjs';\nimport { switchMap } from 'rxjs/operators';\nimport { RecaptchaLoaderService, RECAPTCHA_CONFIG, RecaptchaConfig } from 'ngx-recaptcha-v3/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class RecaptchaV3Service {\n private loader = inject(RecaptchaLoaderService);\n private ngZone = inject(NgZone);\n private platformId = inject(PLATFORM_ID);\n private config = inject(RECAPTCHA_CONFIG, { optional: true });\n\n private isBrowser = isPlatformBrowser(this.platformId);\n\n /**\n * Executes a specific action on the V3 siteKey and yields the resolution token as an Observable.\n */\n public execute(action: string): Observable<string> {\n if (!this.isBrowser) {\n return new Observable<string>((subscriber) => {\n subscriber.next('');\n subscriber.complete();\n });\n }\n\n const siteKey = this.config?.v3SiteKey;\n if (!siteKey) {\n return new Observable<string>((subscriber) => {\n subscriber.error(new Error('reCAPTCHA v3 siteKey is not provided in RECAPTCHA_CONFIG.'));\n });\n }\n\n return this.loader.loadScript().pipe(\n switchMap(() => {\n return new Observable<string>((subscriber) => {\n this.ngZone.runOutsideAngular(() => {\n const windowRef = window as any;\n const grecaptchaObj = windowRef.grecaptcha?.enterprise || windowRef.grecaptcha;\n\n if (!grecaptchaObj) {\n this.ngZone.run(() => {\n subscriber.error(new Error('Google reCAPTCHA script is not loaded or missing.'));\n });\n return;\n }\n\n grecaptchaObj.ready(() => {\n grecaptchaObj.execute(siteKey, { action })\n .then((token: string | null | undefined) => {\n this.ngZone.run(() => {\n if (!token) {\n subscriber.error(new Error('Google reCAPTCHA returned null/undefined token.'));\n return;\n }\n subscriber.next(token);\n subscriber.complete();\n });\n })\n .catch((err: any) => {\n this.ngZone.run(() => {\n subscriber.error(err);\n });\n });\n });\n });\n });\n })\n );\n }\n\n /**\n * Executes a specific action on the V3 siteKey and yields the resolution token as a Promise.\n * Ideal for modern async/await execution pipelines.\n */\n public executeAsync(action: string): Promise<string> {\n return firstValueFrom(this.execute(action));\n }\n}\n","/*\n * Public API Surface of ngx-recaptcha-v3/v3\n */\n\nexport * from './recaptcha-v3.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-recaptcha-v3.mjs","sources":["../../../projects/ngx-recaptcha-v3/src/public-api.ts","../../../projects/ngx-recaptcha-v3/src/ngx-recaptcha-v3.ts"],"sourcesContent":["/*\n * Public API Surface of ngx-recaptcha-v3\n */\n\nexport const NGX_RECAPTCHA_VERSION = '1.0.0';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;AAEG;AAEI,MAAM,qBAAqB,GAAG;;ACJrC;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-recaptcha-v3",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A modern, standalone Google reCAPTCHA library for Angular supporting v2, v3, enterprise, reactive forms, and signals. Fully compatible with Angular versions 12–22",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,10 +35,6 @@
|
|
|
35
35
|
},
|
|
36
36
|
"author": "",
|
|
37
37
|
"license": "MIT",
|
|
38
|
-
"files": [
|
|
39
|
-
"README.md",
|
|
40
|
-
"CHANGELOG.md"
|
|
41
|
-
],
|
|
42
38
|
"module": "fesm2022/ngx-recaptcha-v3.mjs",
|
|
43
39
|
"typings": "types/ngx-recaptcha-v3.d.ts",
|
|
44
40
|
"exports": {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken } from '@angular/core';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
interface RecaptchaConfig {
|
|
6
|
+
v2SiteKey?: string;
|
|
7
|
+
v3SiteKey?: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
useEnterprise?: boolean;
|
|
10
|
+
recaptchaDomain?: 'google.com' | 'recaptcha.net';
|
|
11
|
+
}
|
|
12
|
+
declare const RECAPTCHA_CONFIG: InjectionToken<RecaptchaConfig>;
|
|
13
|
+
|
|
14
|
+
declare class RecaptchaLoaderService {
|
|
15
|
+
private config;
|
|
16
|
+
private platformId;
|
|
17
|
+
private scriptLoaded$;
|
|
18
|
+
private isBrowser;
|
|
19
|
+
/**
|
|
20
|
+
* Loads the reCAPTCHA script.
|
|
21
|
+
* Returns an Observable emitting true when loaded, or false if not in browser.
|
|
22
|
+
*/
|
|
23
|
+
loadScript(): Observable<boolean>;
|
|
24
|
+
private injectScript;
|
|
25
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecaptchaLoaderService, never>;
|
|
26
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RecaptchaLoaderService>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { RECAPTCHA_CONFIG, RecaptchaLoaderService };
|
|
30
|
+
export type { RecaptchaConfig };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class EnterpriseRecaptchaService {
|
|
5
|
+
private v3Service;
|
|
6
|
+
private platformId;
|
|
7
|
+
private config;
|
|
8
|
+
private isBrowser;
|
|
9
|
+
/**
|
|
10
|
+
* Executes score-based action verification using Google reCAPTCHA Enterprise.
|
|
11
|
+
*/
|
|
12
|
+
executeAction(action: string): Observable<string>;
|
|
13
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EnterpriseRecaptchaService, never>;
|
|
14
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<EnterpriseRecaptchaService>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { EnterpriseRecaptchaService };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ControlValueAccessor } from '@angular/forms';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class RecaptchaValueAccessorDirective implements ControlValueAccessor {
|
|
5
|
+
private host;
|
|
6
|
+
private destroyRef;
|
|
7
|
+
private onChange;
|
|
8
|
+
private onTouched;
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Writes value from the form model.
|
|
12
|
+
* If value is empty, resets the recaptcha widget.
|
|
13
|
+
*/
|
|
14
|
+
writeValue(value: string | null): void;
|
|
15
|
+
/**
|
|
16
|
+
* Registers a callback function to be triggered when the value changes.
|
|
17
|
+
*/
|
|
18
|
+
registerOnChange(fn: (value: string | null) => void): void;
|
|
19
|
+
/**
|
|
20
|
+
* Registers a callback function to be triggered when the control is touched.
|
|
21
|
+
*/
|
|
22
|
+
registerOnTouched(fn: () => void): void;
|
|
23
|
+
/**
|
|
24
|
+
* Sets disabled state. reCAPTCHA does not have a native disabled state,
|
|
25
|
+
* but we can hook this if required.
|
|
26
|
+
*/
|
|
27
|
+
setDisabledState?(isDisabled: boolean): void;
|
|
28
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecaptchaValueAccessorDirective, never>;
|
|
29
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<RecaptchaValueAccessorDirective, "ngx-recaptcha-v3[formControlName],ngx-recaptcha-v3[formControl],ngx-recaptcha-v3[ngModel]", never, {}, {}, never, never, true, never>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { RecaptchaValueAccessorDirective };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
|
|
3
|
+
declare class RecaptchaSignalService {
|
|
4
|
+
private _token;
|
|
5
|
+
private _loading;
|
|
6
|
+
private _error;
|
|
7
|
+
readonly token: _angular_core.Signal<string | null>;
|
|
8
|
+
readonly loading: _angular_core.Signal<boolean>;
|
|
9
|
+
readonly error: _angular_core.Signal<string | null>;
|
|
10
|
+
readonly verified: _angular_core.Signal<boolean>;
|
|
11
|
+
setToken(token: string | null): void;
|
|
12
|
+
setError(errorMsg: string | null): void;
|
|
13
|
+
setLoading(isLoading: boolean): void;
|
|
14
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RecaptchaSignalService, never>;
|
|
15
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RecaptchaSignalService>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { RecaptchaSignalService };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class RecaptchaMockV3Service {
|
|
5
|
+
private mockToken;
|
|
6
|
+
/**
|
|
7
|
+
* Configures the mock token to be returned upon execution.
|
|
8
|
+
*/
|
|
9
|
+
setMockToken(token: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Mock execute returning a pre-configured token immediately.
|
|
12
|
+
*/
|
|
13
|
+
execute(action: string): Observable<string>;
|
|
14
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecaptchaMockV3Service, never>;
|
|
15
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RecaptchaMockV3Service>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare class RecaptchaMockLoaderService {
|
|
19
|
+
/**
|
|
20
|
+
* Immediately resolves to true, bypassing network and DOM script injections.
|
|
21
|
+
*/
|
|
22
|
+
loadScript(): Observable<boolean>;
|
|
23
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecaptchaMockLoaderService, never>;
|
|
24
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RecaptchaMockLoaderService>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { RecaptchaMockLoaderService, RecaptchaMockV3Service };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { OnInit, AfterViewInit, ElementRef, EventEmitter } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class RecaptchaV2Component implements OnInit, AfterViewInit {
|
|
5
|
+
wrapper?: ElementRef<HTMLDivElement>;
|
|
6
|
+
container?: ElementRef<HTMLDivElement>;
|
|
7
|
+
siteKey: _angular_core.InputSignal<string>;
|
|
8
|
+
theme: _angular_core.InputSignal<"light" | "dark">;
|
|
9
|
+
size: _angular_core.InputSignal<"normal" | "compact" | "invisible">;
|
|
10
|
+
tabIndex: _angular_core.InputSignal<number>;
|
|
11
|
+
resolved: EventEmitter<string | null>;
|
|
12
|
+
error: EventEmitter<void>;
|
|
13
|
+
expired: EventEmitter<void>;
|
|
14
|
+
private loader;
|
|
15
|
+
private ngZone;
|
|
16
|
+
private cdr;
|
|
17
|
+
private platformId;
|
|
18
|
+
private destroyRef;
|
|
19
|
+
private widgetId;
|
|
20
|
+
private isBrowser;
|
|
21
|
+
private scriptLoaded;
|
|
22
|
+
private viewReady;
|
|
23
|
+
constructor();
|
|
24
|
+
ngOnInit(): void;
|
|
25
|
+
ngAfterViewInit(): void;
|
|
26
|
+
private reRenderWidget;
|
|
27
|
+
private cleanupWidget;
|
|
28
|
+
private renderWidget;
|
|
29
|
+
/**
|
|
30
|
+
* Manually executes an invisible reCAPTCHA v2 widget.
|
|
31
|
+
*/
|
|
32
|
+
execute(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Resets the reCAPTCHA widget instance state.
|
|
35
|
+
*/
|
|
36
|
+
reset(): void;
|
|
37
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RecaptchaV2Component, never>;
|
|
38
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<RecaptchaV2Component, "ngx-recaptcha-v3", never, { "siteKey": { "alias": "siteKey"; "required": true; "isSignal": true; }; "theme": { "alias": "theme"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; }, { "resolved": "resolved"; "error": "error"; "expired": "expired"; }, never, never, true, never>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare class RecaptchaV2Service {
|
|
42
|
+
private instances;
|
|
43
|
+
/**
|
|
44
|
+
* Registers a V2 widget instance under a specific key.
|
|
45
|
+
*/
|
|
46
|
+
register(key: string, component: RecaptchaV2Component): void;
|
|
47
|
+
/**
|
|
48
|
+
* Unregisters a V2 widget instance.
|
|
49
|
+
*/
|
|
50
|
+
unregister(key: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Executes a registered invisible V2 component by key.
|
|
53
|
+
*/
|
|
54
|
+
execute(key: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Resets a registered V2 component by key.
|
|
57
|
+
*/
|
|
58
|
+
reset(key: string): void;
|
|
59
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RecaptchaV2Service, never>;
|
|
60
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RecaptchaV2Service>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { RecaptchaV2Component, RecaptchaV2Service };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class RecaptchaV3Service {
|
|
5
|
+
private loader;
|
|
6
|
+
private ngZone;
|
|
7
|
+
private platformId;
|
|
8
|
+
private config;
|
|
9
|
+
private isBrowser;
|
|
10
|
+
/**
|
|
11
|
+
* Executes a specific action on the V3 siteKey and yields the resolution token as an Observable.
|
|
12
|
+
*/
|
|
13
|
+
execute(action: string): Observable<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Executes a specific action on the V3 siteKey and yields the resolution token as a Promise.
|
|
16
|
+
* Ideal for modern async/await execution pipelines.
|
|
17
|
+
*/
|
|
18
|
+
executeAsync(action: string): Promise<string>;
|
|
19
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RecaptchaV3Service, never>;
|
|
20
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<RecaptchaV3Service>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { RecaptchaV3Service };
|