ng-recaptcha.mjs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. import * as i0 from '@angular/core';
  2. import { InjectionToken, PLATFORM_ID, Injectable, Inject, Optional, EventEmitter, Component, Input, HostBinding, Output, NgModule, forwardRef, Directive, HostListener } from '@angular/core';
  3. import { isPlatformBrowser } from '@angular/common';
  4. import { of, BehaviorSubject, Subject } from 'rxjs';
  5. import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
  6. const RECAPTCHA_LANGUAGE = new InjectionToken("recaptcha-language");
  7. const RECAPTCHA_BASE_URL = new InjectionToken("recaptcha-base-url");
  8. const RECAPTCHA_NONCE = new InjectionToken("recaptcha-nonce-tag");
  9. const RECAPTCHA_SETTINGS = new InjectionToken("recaptcha-settings");
  10. const RECAPTCHA_V3_SITE_KEY = new InjectionToken("recaptcha-v3-site-key");
  11. function loadScript(renderMode, onLoaded, urlParams, url, nonce) {
  12. window.ng2recaptchaloaded = () => {
  13. onLoaded(grecaptcha);
  14. };
  15. const script = document.createElement("script");
  16. script.innerHTML = "";
  17. const baseUrl = url || "https://www.google.com/recaptcha/api.js";
  18. script.src = `${baseUrl}?render=${renderMode}&onload=ng2recaptchaloaded${urlParams}`;
  19. if (nonce) {
  20. script.nonce = nonce;
  21. }
  22. script.async = true;
  23. script.defer = true;
  24. document.head.appendChild(script);
  25. }
  26. const loader = { loadScript };
  27. class RecaptchaLoaderService {
  28. /**
  29. * @internal
  30. * @nocollapse
  31. */
  32. static { this.ready = null; }
  33. constructor(
  34. // eslint-disable-next-line @typescript-eslint/ban-types
  35. platformId, language, baseUrl, nonce, v3SiteKey) {
  36. this.platformId = platformId;
  37. this.language = language;
  38. this.baseUrl = baseUrl;
  39. this.nonce = nonce;
  40. this.v3SiteKey = v3SiteKey;
  41. this.init();
  42. this.ready = isPlatformBrowser(this.platformId) ? RecaptchaLoaderService.ready.asObservable() : of();
  43. }
  44. /** @internal */
  45. init() {
  46. if (RecaptchaLoaderService.ready) {
  47. return;
  48. }
  49. if (isPlatformBrowser(this.platformId)) {
  50. const subject = new BehaviorSubject(null);
  51. RecaptchaLoaderService.ready = subject;
  52. const langParam = this.language ? "&hl=" + this.language : "";
  53. const renderMode = this.v3SiteKey || "explicit";
  54. loader.loadScript(renderMode, (grecaptcha) => subject.next(grecaptcha), langParam, this.baseUrl, this.nonce);
  55. }
  56. }
  57. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService, deps: [{ token: PLATFORM_ID }, { token: RECAPTCHA_LANGUAGE, optional: true }, { token: RECAPTCHA_BASE_URL, optional: true }, { token: RECAPTCHA_NONCE, optional: true }, { token: RECAPTCHA_V3_SITE_KEY, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
  58. static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService }); }
  59. }
  60. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService, decorators: [{
  61. type: Injectable
  62. }], ctorParameters: function () { return [{ type: Object, decorators: [{
  63. type: Inject,
  64. args: [PLATFORM_ID]
  65. }] }, { type: undefined, decorators: [{
  66. type: Optional
  67. }, {
  68. type: Inject,
  69. args: [RECAPTCHA_LANGUAGE]
  70. }] }, { type: undefined, decorators: [{
  71. type: Optional
  72. }, {
  73. type: Inject,
  74. args: [RECAPTCHA_BASE_URL]
  75. }] }, { type: undefined, decorators: [{
  76. type: Optional
  77. }, {
  78. type: Inject,
  79. args: [RECAPTCHA_NONCE]
  80. }] }, { type: undefined, decorators: [{
  81. type: Optional
  82. }, {
  83. type: Inject,
  84. args: [RECAPTCHA_V3_SITE_KEY]
  85. }] }]; } });
  86. let nextId = 0;
  87. class RecaptchaComponent {
  88. constructor(elementRef, loader, zone, settings) {
  89. this.elementRef = elementRef;
  90. this.loader = loader;
  91. this.zone = zone;
  92. this.id = `ngrecaptcha-${nextId++}`;
  93. this.errorMode = "default";
  94. this.resolved = new EventEmitter();
  95. /**
  96. * @deprecated `(error) output will be removed in the next major version. Use (errored) instead
  97. */
  98. // eslint-disable-next-line @angular-eslint/no-output-native
  99. this.error = new EventEmitter();
  100. this.errored = new EventEmitter();
  101. if (settings) {
  102. this.siteKey = settings.siteKey;
  103. this.theme = settings.theme;
  104. this.type = settings.type;
  105. this.size = settings.size;
  106. this.badge = settings.badge;
  107. }
  108. }
  109. ngAfterViewInit() {
  110. this.subscription = this.loader.ready.subscribe((grecaptcha) => {
  111. if (grecaptcha != null && grecaptcha.render instanceof Function) {
  112. this.grecaptcha = grecaptcha;
  113. this.renderRecaptcha();
  114. }
  115. });
  116. }
  117. ngOnDestroy() {
  118. // reset the captcha to ensure it does not leave anything behind
  119. // after the component is no longer needed
  120. this.grecaptchaReset();
  121. if (this.subscription) {
  122. this.subscription.unsubscribe();
  123. }
  124. }
  125. /**
  126. * Executes the invisible recaptcha.
  127. * Does nothing if component's size is not set to "invisible".
  128. */
  129. execute() {
  130. if (this.size !== "invisible") {
  131. return;
  132. }
  133. if (this.widget != null) {
  134. void this.grecaptcha.execute(this.widget);
  135. }
  136. else {
  137. // delay execution of recaptcha until it actually renders
  138. this.executeRequested = true;
  139. }
  140. }
  141. reset() {
  142. if (this.widget != null) {
  143. if (this.grecaptcha.getResponse(this.widget)) {
  144. // Only emit an event in case if something would actually change.
  145. // That way we do not trigger "touching" of the control if someone does a "reset"
  146. // on a non-resolved captcha.
  147. this.resolved.emit(null);
  148. }
  149. this.grecaptchaReset();
  150. }
  151. }
  152. /**
  153. * ⚠️ Warning! Use this property at your own risk!
  154. *
  155. * While this member is `public`, it is not a part of the component's public API.
  156. * The semantic versioning guarantees _will not be honored_! Thus, you might find that this property behavior changes in incompatible ways in minor or even patch releases.
  157. * You are **strongly advised** against using this property.
  158. * Instead, use more idiomatic ways to get reCAPTCHA value, such as `resolved` EventEmitter, or form-bound methods (ngModel, formControl, and the likes).å
  159. */
  160. get __unsafe_widgetValue() {
  161. return this.widget != null ? this.grecaptcha.getResponse(this.widget) : null;
  162. }
  163. /** @internal */
  164. expired() {
  165. this.resolved.emit(null);
  166. }
  167. /** @internal */
  168. onError(args) {
  169. this.error.emit(args);
  170. this.errored.emit(args);
  171. }
  172. /** @internal */
  173. captchaResponseCallback(response) {
  174. this.resolved.emit(response);
  175. }
  176. /** @internal */
  177. grecaptchaReset() {
  178. if (this.widget != null) {
  179. this.zone.runOutsideAngular(() => this.grecaptcha.reset(this.widget));
  180. }
  181. }
  182. /** @internal */
  183. renderRecaptcha() {
  184. // This `any` can be removed after @types/grecaptcha get updated
  185. const renderOptions = {
  186. badge: this.badge,
  187. callback: (response) => {
  188. this.zone.run(() => this.captchaResponseCallback(response));
  189. },
  190. "expired-callback": () => {
  191. this.zone.run(() => this.expired());
  192. },
  193. sitekey: this.siteKey,
  194. size: this.size,
  195. tabindex: this.tabIndex,
  196. theme: this.theme,
  197. type: this.type,
  198. };
  199. if (this.errorMode === "handled") {
  200. renderOptions["error-callback"] = (...args) => {
  201. this.zone.run(() => this.onError(args));
  202. };
  203. }
  204. this.widget = this.grecaptcha.render(this.elementRef.nativeElement, renderOptions);
  205. if (this.executeRequested === true) {
  206. this.executeRequested = false;
  207. this.execute();
  208. }
  209. }
  210. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaComponent, deps: [{ token: i0.ElementRef }, { token: RecaptchaLoaderService }, { token: i0.NgZone }, { token: RECAPTCHA_SETTINGS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
  211. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.1", type: RecaptchaComponent, selector: "re-captcha", inputs: { id: "id", siteKey: "siteKey", theme: "theme", type: "type", size: "size", tabIndex: "tabIndex", badge: "badge", errorMode: "errorMode" }, outputs: { resolved: "resolved", error: "error", errored: "errored" }, host: { properties: { "attr.id": "this.id" } }, exportAs: ["reCaptcha"], ngImport: i0, template: ``, isInline: true }); }
  212. }
  213. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaComponent, decorators: [{
  214. type: Component,
  215. args: [{
  216. exportAs: "reCaptcha",
  217. selector: "re-captcha",
  218. template: ``,
  219. }]
  220. }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: RecaptchaLoaderService }, { type: i0.NgZone }, { type: undefined, decorators: [{
  221. type: Optional
  222. }, {
  223. type: Inject,
  224. args: [RECAPTCHA_SETTINGS]
  225. }] }]; }, propDecorators: { id: [{
  226. type: Input
  227. }, {
  228. type: HostBinding,
  229. args: ["attr.id"]
  230. }], siteKey: [{
  231. type: Input
  232. }], theme: [{
  233. type: Input
  234. }], type: [{
  235. type: Input
  236. }], size: [{
  237. type: Input
  238. }], tabIndex: [{
  239. type: Input
  240. }], badge: [{
  241. type: Input
  242. }], errorMode: [{
  243. type: Input
  244. }], resolved: [{
  245. type: Output
  246. }], error: [{
  247. type: Output
  248. }], errored: [{
  249. type: Output
  250. }] } });
  251. class RecaptchaCommonModule {
  252. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  253. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, declarations: [RecaptchaComponent], exports: [RecaptchaComponent] }); }
  254. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule }); }
  255. }
  256. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, decorators: [{
  257. type: NgModule,
  258. args: [{
  259. declarations: [RecaptchaComponent],
  260. exports: [RecaptchaComponent],
  261. }]
  262. }] });
  263. class RecaptchaModule {
  264. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  265. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, imports: [RecaptchaCommonModule], exports: [RecaptchaComponent] }); }
  266. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, providers: [RecaptchaLoaderService], imports: [RecaptchaCommonModule] }); }
  267. }
  268. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, decorators: [{
  269. type: NgModule,
  270. args: [{
  271. exports: [RecaptchaComponent],
  272. imports: [RecaptchaCommonModule],
  273. providers: [RecaptchaLoaderService],
  274. }]
  275. }] });
  276. /**
  277. * The main service for working with reCAPTCHA v3 APIs.
  278. *
  279. * Use the `execute` method for executing a single action, and
  280. * `onExecute` observable for listening to all actions at once.
  281. */
  282. class ReCaptchaV3Service {
  283. constructor(zone, siteKey,
  284. // eslint-disable-next-line @typescript-eslint/ban-types
  285. platformId, baseUrl, nonce, language) {
  286. /** @internal */
  287. this.onLoadComplete = (grecaptcha) => {
  288. this.grecaptcha = grecaptcha;
  289. if (this.actionBacklog && this.actionBacklog.length > 0) {
  290. this.actionBacklog.forEach(([action, subject]) => this.executeActionWithSubject(action, subject));
  291. this.actionBacklog = undefined;
  292. }
  293. };
  294. this.zone = zone;
  295. this.isBrowser = isPlatformBrowser(platformId);
  296. this.siteKey = siteKey;
  297. this.nonce = nonce;
  298. this.language = language;
  299. this.baseUrl = baseUrl;
  300. this.init();
  301. }
  302. get onExecute() {
  303. if (!this.onExecuteSubject) {
  304. this.onExecuteSubject = new Subject();
  305. this.onExecuteObservable = this.onExecuteSubject.asObservable();
  306. }
  307. return this.onExecuteObservable;
  308. }
  309. get onExecuteError() {
  310. if (!this.onExecuteErrorSubject) {
  311. this.onExecuteErrorSubject = new Subject();
  312. this.onExecuteErrorObservable = this.onExecuteErrorSubject.asObservable();
  313. }
  314. return this.onExecuteErrorObservable;
  315. }
  316. /**
  317. * Executes the provided `action` with reCAPTCHA v3 API.
  318. * Use the emitted token value for verification purposes on the backend.
  319. *
  320. * For more information about reCAPTCHA v3 actions and tokens refer to the official documentation at
  321. * https://developers.google.com/recaptcha/docs/v3.
  322. *
  323. * @param {string} action the action to execute
  324. * @returns {Observable<string>} an `Observable` that will emit the reCAPTCHA v3 string `token` value whenever ready.
  325. * The returned `Observable` completes immediately after emitting a value.
  326. */
  327. execute(action) {
  328. const subject = new Subject();
  329. if (this.isBrowser) {
  330. if (!this.grecaptcha) {
  331. if (!this.actionBacklog) {
  332. this.actionBacklog = [];
  333. }
  334. this.actionBacklog.push([action, subject]);
  335. }
  336. else {
  337. this.executeActionWithSubject(action, subject);
  338. }
  339. }
  340. return subject.asObservable();
  341. }
  342. /** @internal */
  343. executeActionWithSubject(action, subject) {
  344. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  345. const onError = (error) => {
  346. this.zone.run(() => {
  347. subject.error(error);
  348. if (this.onExecuteErrorSubject) {
  349. // We don't know any better at this point, unfortunately, so have to resort to `any`
  350. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  351. this.onExecuteErrorSubject.next({ action, error });
  352. }
  353. });
  354. };
  355. this.zone.runOutsideAngular(() => {
  356. try {
  357. this.grecaptcha.execute(this.siteKey, { action }).then((token) => {
  358. this.zone.run(() => {
  359. subject.next(token);
  360. subject.complete();
  361. if (this.onExecuteSubject) {
  362. this.onExecuteSubject.next({ action, token });
  363. }
  364. });
  365. }, onError);
  366. }
  367. catch (e) {
  368. onError(e);
  369. }
  370. });
  371. }
  372. /** @internal */
  373. init() {
  374. if (this.isBrowser) {
  375. if ("grecaptcha" in window) {
  376. this.grecaptcha = grecaptcha;
  377. }
  378. else {
  379. const langParam = this.language ? "&hl=" + this.language : "";
  380. loader.loadScript(this.siteKey, this.onLoadComplete, langParam, this.baseUrl, this.nonce);
  381. }
  382. }
  383. }
  384. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service, deps: [{ token: i0.NgZone }, { token: RECAPTCHA_V3_SITE_KEY }, { token: PLATFORM_ID }, { token: RECAPTCHA_BASE_URL, optional: true }, { token: RECAPTCHA_NONCE, optional: true }, { token: RECAPTCHA_LANGUAGE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
  385. static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service }); }
  386. }
  387. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service, decorators: [{
  388. type: Injectable
  389. }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: undefined, decorators: [{
  390. type: Inject,
  391. args: [RECAPTCHA_V3_SITE_KEY]
  392. }] }, { type: Object, decorators: [{
  393. type: Inject,
  394. args: [PLATFORM_ID]
  395. }] }, { type: undefined, decorators: [{
  396. type: Optional
  397. }, {
  398. type: Inject,
  399. args: [RECAPTCHA_BASE_URL]
  400. }] }, { type: undefined, decorators: [{
  401. type: Optional
  402. }, {
  403. type: Inject,
  404. args: [RECAPTCHA_NONCE]
  405. }] }, { type: undefined, decorators: [{
  406. type: Optional
  407. }, {
  408. type: Inject,
  409. args: [RECAPTCHA_LANGUAGE]
  410. }] }]; } });
  411. class RecaptchaV3Module {
  412. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  413. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module }); }
  414. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, providers: [ReCaptchaV3Service] }); }
  415. }
  416. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, decorators: [{
  417. type: NgModule,
  418. args: [{
  419. providers: [ReCaptchaV3Service],
  420. }]
  421. }] });
  422. class RecaptchaValueAccessorDirective {
  423. constructor(host) {
  424. this.host = host;
  425. this.requiresControllerReset = false;
  426. }
  427. writeValue(value) {
  428. if (!value) {
  429. this.host.reset();
  430. }
  431. else {
  432. // In this case, it is most likely that a form controller has requested to write a specific value into the component.
  433. // This isn't really a supported case - reCAPTCHA values are single-use, and, in a sense, readonly.
  434. // What this means is that the form controller has recaptcha control state of X, while reCAPTCHA itself can't "restore"
  435. // to that state. In order to make form controller aware of this discrepancy, and to fix the said misalignment,
  436. // we'll be telling the controller to "reset" the value back to null.
  437. if (this.host.__unsafe_widgetValue !== value && Boolean(this.host.__unsafe_widgetValue) === false) {
  438. this.requiresControllerReset = true;
  439. }
  440. }
  441. }
  442. registerOnChange(fn) {
  443. this.onChange = fn;
  444. if (this.requiresControllerReset) {
  445. this.requiresControllerReset = false;
  446. this.onChange(null);
  447. }
  448. }
  449. registerOnTouched(fn) {
  450. this.onTouched = fn;
  451. }
  452. onResolve($event) {
  453. if (this.onChange) {
  454. this.onChange($event);
  455. }
  456. if (this.onTouched) {
  457. this.onTouched();
  458. }
  459. }
  460. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaValueAccessorDirective, deps: [{ token: RecaptchaComponent }], target: i0.ɵɵFactoryTarget.Directive }); }
  461. static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.1", type: RecaptchaValueAccessorDirective, selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]", host: { listeners: { "resolved": "onResolve($event)" } }, providers: [
  462. {
  463. multi: true,
  464. provide: NG_VALUE_ACCESSOR,
  465. useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
  466. },
  467. ], ngImport: i0 }); }
  468. }
  469. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaValueAccessorDirective, decorators: [{
  470. type: Directive,
  471. args: [{
  472. providers: [
  473. {
  474. multi: true,
  475. provide: NG_VALUE_ACCESSOR,
  476. useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
  477. },
  478. ],
  479. selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]",
  480. }]
  481. }], ctorParameters: function () { return [{ type: RecaptchaComponent }]; }, propDecorators: { onResolve: [{
  482. type: HostListener,
  483. args: ["resolved", ["$event"]]
  484. }] } });
  485. class RecaptchaFormsModule {
  486. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
  487. static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, declarations: [RecaptchaValueAccessorDirective], imports: [FormsModule, RecaptchaCommonModule], exports: [RecaptchaValueAccessorDirective] }); }
  488. static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, imports: [FormsModule, RecaptchaCommonModule] }); }
  489. }
  490. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, decorators: [{
  491. type: NgModule,
  492. args: [{
  493. declarations: [RecaptchaValueAccessorDirective],
  494. exports: [RecaptchaValueAccessorDirective],
  495. imports: [FormsModule, RecaptchaCommonModule],
  496. }]
  497. }] });
  498. /**
  499. * Generated bundle index. Do not edit.
  500. */
  501. export { RECAPTCHA_BASE_URL, RECAPTCHA_LANGUAGE, RECAPTCHA_NONCE, RECAPTCHA_SETTINGS, RECAPTCHA_V3_SITE_KEY, ReCaptchaV3Service, RecaptchaComponent, RecaptchaFormsModule, RecaptchaLoaderService, RecaptchaModule, RecaptchaV3Module, RecaptchaValueAccessorDirective };
  502. //# sourceMappingURL=ng-recaptcha.mjs.map