@internetarchive/recaptcha-manager 0.1.2-alpha.1 → 1.0.0

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.
Files changed (51) hide show
  1. package/.editorconfig +29 -29
  2. package/.github/workflows/ci.yml +27 -26
  3. package/.github/workflows/gh-pages-main.yml +39 -0
  4. package/.github/workflows/pr-preview.yml +63 -0
  5. package/.husky/pre-commit +1 -4
  6. package/.prettierignore +1 -0
  7. package/LICENSE +661 -661
  8. package/README.md +63 -85
  9. package/coverage/.gitignore +3 -0
  10. package/coverage/.placeholder +0 -0
  11. package/demo/app-root.ts +93 -93
  12. package/demo/index.html +21 -21
  13. package/dist/demo/app-root.d.ts +14 -14
  14. package/dist/demo/app-root.js +85 -85
  15. package/dist/demo/app-root.js.map +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +2 -2
  18. package/dist/index.js.map +1 -1
  19. package/dist/src/recaptcha-manager.d.ts +34 -35
  20. package/dist/src/recaptcha-manager.js +54 -52
  21. package/dist/src/recaptcha-manager.js.map +1 -1
  22. package/dist/src/recaptcha-widget.d.ts +38 -39
  23. package/dist/src/recaptcha-widget.js +95 -95
  24. package/dist/src/recaptcha-widget.js.map +1 -1
  25. package/dist/test/mock-grecaptcha.d.ts +23 -24
  26. package/dist/test/mock-grecaptcha.js +59 -61
  27. package/dist/test/mock-grecaptcha.js.map +1 -1
  28. package/dist/test/mock-lazy-loader.d.ts +15 -15
  29. package/dist/test/mock-lazy-loader.js +17 -16
  30. package/dist/test/mock-lazy-loader.js.map +1 -1
  31. package/dist/test/recaptcha-manager.test.d.ts +1 -1
  32. package/dist/test/recaptcha-manager.test.js +137 -137
  33. package/dist/test/recaptcha-manager.test.js.map +1 -1
  34. package/dist/vite.config.d.ts +2 -0
  35. package/dist/vite.config.js +25 -0
  36. package/dist/vite.config.js.map +1 -0
  37. package/eslint.config.mjs +53 -0
  38. package/index.ts +10 -10
  39. package/package.json +76 -98
  40. package/renovate.json +6 -0
  41. package/src/recaptcha-manager.ts +89 -87
  42. package/src/recaptcha-widget.ts +148 -148
  43. package/ssl/server.crt +22 -0
  44. package/ssl/server.key +28 -0
  45. package/test/mock-grecaptcha.ts +85 -87
  46. package/test/mock-lazy-loader.ts +39 -38
  47. package/test/recaptcha-manager.test.ts +151 -151
  48. package/tsconfig.json +31 -20
  49. package/vite.config.ts +25 -0
  50. package/web-dev-server.config.mjs +32 -28
  51. package/web-test-runner.config.mjs +41 -41
@@ -1,148 +1,148 @@
1
- /**
2
- * This encompasses a widget for a given site key.
3
- */
4
- export interface RecaptchaWidgetInterface {
5
- /** execute the recaptcha request and returns a token */
6
- execute(): Promise<string>;
7
- }
8
-
9
- /**
10
- * The combines parameters from the Recaptcha config and adds the zIndex, which
11
- * allows us to control the z-index of the recaptcha widget.
12
- */
13
- export type RecaptchaWidgetConfig = Pick<
14
- ReCaptchaV2.Parameters,
15
- 'tabindex' | 'theme' | 'type' | 'size' | 'badge'
16
- > & {
17
- zIndex?: number;
18
- };
19
-
20
- /**
21
- * This encompasses a widget for a given site key.
22
- */
23
- export class RecaptchaWidget implements RecaptchaWidgetInterface {
24
- private executionSuccessBlock?: (token: string) => void;
25
-
26
- private executionExpiredBlock?: () => void;
27
-
28
- private executionErrorBlock?: () => void;
29
-
30
- private grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
31
-
32
- private siteKey: string;
33
-
34
- private widgetId: number | null = null;
35
-
36
- private isExecuting = false;
37
-
38
- constructor(
39
- config: {
40
- siteKey: string;
41
- grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
42
- },
43
- widgetConfig?: RecaptchaWidgetConfig
44
- ) {
45
- this.siteKey = config.siteKey;
46
- this.grecaptchaLibrary = config.grecaptchaLibrary;
47
-
48
- const container = this.createContainer();
49
- this.setup(container, widgetConfig);
50
- }
51
-
52
- /** @inheritdoc */
53
- async execute(): Promise<string> {
54
- const { widgetId } = this;
55
-
56
- if (widgetId === null) {
57
- throw new Error('Recaptcha is not setup');
58
- }
59
-
60
- if (this.isExecuting) {
61
- // there is no way to know when users have dismissed a previous recaptcha
62
- // so if we're still in the middle of execution when we call execute again,
63
- // just reset it and execute it again
64
- this.finishExecution();
65
- }
66
-
67
- this.isExecuting = true;
68
-
69
- return new Promise((resolve, reject) => {
70
- this.executionSuccessBlock = (token: string): void => {
71
- this.finishExecution();
72
- resolve(token);
73
- };
74
-
75
- this.executionExpiredBlock = (): void => {
76
- this.finishExecution();
77
- reject(new Error('expired'));
78
- };
79
-
80
- this.executionErrorBlock = (): void => {
81
- this.finishExecution();
82
- reject(new Error('error'));
83
- };
84
-
85
- this.grecaptchaLibrary.execute(widgetId);
86
- });
87
- }
88
-
89
- private finishExecution() {
90
- this.isExecuting = false;
91
- const { widgetId } = this;
92
- if (widgetId === null) return;
93
- this.grecaptchaLibrary.reset(widgetId);
94
- }
95
-
96
- private setup(
97
- container: HTMLElement,
98
- widgetConfig?: ReCaptchaV2.Parameters
99
- ): void {
100
- this.widgetId = this.grecaptchaLibrary.render(container, {
101
- callback: this.responseHandler.bind(this),
102
- 'expired-callback': this.expiredHandler.bind(this),
103
- 'error-callback': this.errorHandler.bind(this),
104
- sitekey: this.siteKey,
105
- tabindex: widgetConfig?.tabindex,
106
- theme: widgetConfig?.theme,
107
- type: widgetConfig?.type,
108
- size: widgetConfig?.size ?? 'invisible',
109
- badge: widgetConfig?.badge,
110
- });
111
- }
112
-
113
- private createContainer(zIndex?: number): HTMLElement {
114
- const elementId = `recaptchaManager-${this.siteKey}`;
115
- let element: HTMLElement | null = document.getElementById(elementId);
116
- if (!element) {
117
- element = document.createElement('div');
118
- element.id = elementId;
119
- element.style.position = 'fixed';
120
- element.style.top = '50%';
121
- element.style.left = '50%';
122
- element.style.zIndex = zIndex ? `${zIndex}` : '10';
123
- document.body.appendChild(element);
124
- }
125
- return element;
126
- }
127
-
128
- private responseHandler(response: any): void {
129
- if (this.executionSuccessBlock) {
130
- this.executionSuccessBlock(response);
131
- this.executionSuccessBlock = undefined;
132
- }
133
- }
134
-
135
- private expiredHandler(): void {
136
- if (this.executionExpiredBlock) {
137
- this.executionExpiredBlock();
138
- this.executionExpiredBlock = undefined;
139
- }
140
- }
141
-
142
- private errorHandler(): void {
143
- if (this.executionErrorBlock) {
144
- this.executionErrorBlock();
145
- this.executionErrorBlock = undefined;
146
- }
147
- }
148
- }
1
+ /**
2
+ * This encompasses a widget for a given site key.
3
+ */
4
+ export interface RecaptchaWidgetInterface {
5
+ /** execute the recaptcha request and returns a token */
6
+ execute(): Promise<string>;
7
+ }
8
+
9
+ /**
10
+ * The combines parameters from the Recaptcha config and adds the zIndex, which
11
+ * allows us to control the z-index of the recaptcha widget.
12
+ */
13
+ export type RecaptchaWidgetConfig = Pick<
14
+ ReCaptchaV2.Parameters,
15
+ 'tabindex' | 'theme' | 'type' | 'size' | 'badge'
16
+ > & {
17
+ zIndex?: number;
18
+ };
19
+
20
+ /**
21
+ * This encompasses a widget for a given site key.
22
+ */
23
+ export class RecaptchaWidget implements RecaptchaWidgetInterface {
24
+ private executionSuccessBlock?: (token: string) => void;
25
+
26
+ private executionExpiredBlock?: () => void;
27
+
28
+ private executionErrorBlock?: () => void;
29
+
30
+ private grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
31
+
32
+ private siteKey: string;
33
+
34
+ private widgetId: number | null = null;
35
+
36
+ private isExecuting = false;
37
+
38
+ constructor(
39
+ config: {
40
+ siteKey: string;
41
+ grecaptchaLibrary: ReCaptchaV2.ReCaptcha;
42
+ },
43
+ widgetConfig?: RecaptchaWidgetConfig,
44
+ ) {
45
+ this.siteKey = config.siteKey;
46
+ this.grecaptchaLibrary = config.grecaptchaLibrary;
47
+
48
+ const container = this.createContainer();
49
+ this.setup(container, widgetConfig);
50
+ }
51
+
52
+ /** @inheritdoc */
53
+ async execute(): Promise<string> {
54
+ const { widgetId } = this;
55
+
56
+ if (widgetId === null) {
57
+ throw new Error('Recaptcha is not setup');
58
+ }
59
+
60
+ if (this.isExecuting) {
61
+ // there is no way to know when users have dismissed a previous recaptcha
62
+ // so if we're still in the middle of execution when we call execute again,
63
+ // just reset it and execute it again
64
+ this.finishExecution();
65
+ }
66
+
67
+ this.isExecuting = true;
68
+
69
+ return new Promise((resolve, reject) => {
70
+ this.executionSuccessBlock = (token: string): void => {
71
+ this.finishExecution();
72
+ resolve(token);
73
+ };
74
+
75
+ this.executionExpiredBlock = (): void => {
76
+ this.finishExecution();
77
+ reject(new Error('expired'));
78
+ };
79
+
80
+ this.executionErrorBlock = (): void => {
81
+ this.finishExecution();
82
+ reject(new Error('error'));
83
+ };
84
+
85
+ this.grecaptchaLibrary.execute(widgetId);
86
+ });
87
+ }
88
+
89
+ private finishExecution() {
90
+ this.isExecuting = false;
91
+ const { widgetId } = this;
92
+ if (widgetId === null) return;
93
+ this.grecaptchaLibrary.reset(widgetId);
94
+ }
95
+
96
+ private setup(
97
+ container: HTMLElement,
98
+ widgetConfig?: ReCaptchaV2.Parameters,
99
+ ): void {
100
+ this.widgetId = this.grecaptchaLibrary.render(container, {
101
+ callback: this.responseHandler.bind(this),
102
+ 'expired-callback': this.expiredHandler.bind(this),
103
+ 'error-callback': this.errorHandler.bind(this),
104
+ sitekey: this.siteKey,
105
+ tabindex: widgetConfig?.tabindex,
106
+ theme: widgetConfig?.theme,
107
+ type: widgetConfig?.type,
108
+ size: widgetConfig?.size ?? 'invisible',
109
+ badge: widgetConfig?.badge,
110
+ });
111
+ }
112
+
113
+ private createContainer(zIndex?: number): HTMLElement {
114
+ const elementId = `recaptchaManager-${this.siteKey}`;
115
+ let element: HTMLElement | null = document.getElementById(elementId);
116
+ if (!element) {
117
+ element = document.createElement('div');
118
+ element.id = elementId;
119
+ element.style.position = 'fixed';
120
+ element.style.top = '50%';
121
+ element.style.left = '50%';
122
+ element.style.zIndex = zIndex ? `${zIndex}` : '10';
123
+ document.body.appendChild(element);
124
+ }
125
+ return element;
126
+ }
127
+
128
+ private responseHandler(response: string): void {
129
+ if (this.executionSuccessBlock) {
130
+ this.executionSuccessBlock(response);
131
+ this.executionSuccessBlock = undefined;
132
+ }
133
+ }
134
+
135
+ private expiredHandler(): void {
136
+ if (this.executionExpiredBlock) {
137
+ this.executionExpiredBlock();
138
+ this.executionExpiredBlock = undefined;
139
+ }
140
+ }
141
+
142
+ private errorHandler(): void {
143
+ if (this.executionErrorBlock) {
144
+ this.executionErrorBlock();
145
+ this.executionErrorBlock = undefined;
146
+ }
147
+ }
148
+ }
package/ssl/server.crt ADDED
@@ -0,0 +1,22 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDszCCApugAwIBAgIUYr5csS2ntaMTww0b5QoFI0xlOpUwDQYJKoZIhvcNAQEL
3
+ BQAwaTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJh
4
+ bmNpc2NvMRkwFwYDVQQKDBBJbnRlcm5ldCBBcmNoaXZlMRowGAYDVQQDDBFsb2Nh
5
+ bC5hcmNoaXZlLm9yZzAeFw0yNTAzMDcxOTM1MzRaFw0yNTA0MDYxOTM1MzRaMGkx
6
+ CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNj
7
+ bzEZMBcGA1UECgwQSW50ZXJuZXQgQXJjaGl2ZTEaMBgGA1UEAwwRbG9jYWwuYXJj
8
+ aGl2ZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZqbS9hNS3
9
+ 8AtcA7Uszq7EA7RavuHc8AcpbURa6Y7NORs0SmfDD0oLptQ7DX5pSuHyOeDHzQ3U
10
+ XRCUDAhAD1XlaYQ6PPdiJPRAe4ACELzgDzepxVz3pdKPcfXd5/mHV3ghUZya2XW5
11
+ DSF1CRYUX2j10a+JORJIG4bhvTg4HxTJZZDuaNfBMC6ZSn7d9YLQoAf1MLLJm43Y
12
+ cj1WlOnyG4DHxNEqEk260BlbBywJH+SJA6GA0GR2bnzYZaDnZ0wqea0Zamx8ijpd
13
+ JxBUxYOqLfzs2KREVkkGOmsFEu82W6G3D4bKsY1UNaWXb/jcl3UkXIJJij6CdbbM
14
+ QkUJc8dow3sVAgMBAAGjUzBRMB0GA1UdDgQWBBSla0L0Yhpx9/DEV4uJ6OoHH92Q
15
+ bTAfBgNVHSMEGDAWgBSla0L0Yhpx9/DEV4uJ6OoHH92QbTAPBgNVHRMBAf8EBTAD
16
+ AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBEzt9sgWtwjLI7AVrejDSE6F/01ng4bTni
17
+ 0PJXa7IpwjhAApVWcjxDKp8SkDUAcZNULqBGvpPicqjnKf+wxk3xTMc7pvLqzOor
18
+ pm+plDUBfCEbrv1ouLDMgOtxQxbwbBUPySsLoNmDUGAGnL2zENX7qidOOmmSQEN4
19
+ jZuPtiEkgTqmtkfHaRX/7jhmGVfxMxj0Krlar1/cSbvwaVs4kRSjiL9/avT+AX59
20
+ 0QoNYTLGcBP0RKia8NF2A3cgUivIMFZQDvdsiAvqY+DbC7Mnyv4Sj/ZHHwVa9+8k
21
+ iRU56DrOt7sgaa/oQfzWnvRtL0F5eXC3veqM4qZrXs9hHeGlgPFo
22
+ -----END CERTIFICATE-----
package/ssl/server.key ADDED
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDZqbS9hNS38Atc
3
+ A7Uszq7EA7RavuHc8AcpbURa6Y7NORs0SmfDD0oLptQ7DX5pSuHyOeDHzQ3UXRCU
4
+ DAhAD1XlaYQ6PPdiJPRAe4ACELzgDzepxVz3pdKPcfXd5/mHV3ghUZya2XW5DSF1
5
+ CRYUX2j10a+JORJIG4bhvTg4HxTJZZDuaNfBMC6ZSn7d9YLQoAf1MLLJm43Ycj1W
6
+ lOnyG4DHxNEqEk260BlbBywJH+SJA6GA0GR2bnzYZaDnZ0wqea0Zamx8ijpdJxBU
7
+ xYOqLfzs2KREVkkGOmsFEu82W6G3D4bKsY1UNaWXb/jcl3UkXIJJij6CdbbMQkUJ
8
+ c8dow3sVAgMBAAECggEANgLpITAhcuVDhFk9L3m4H1bF/dCpDmCXfl2pXR/guicm
9
+ C4M9HUeheaOzvVWbXThiOe/HyfylpmFTmFEmCPNlPrDAyYzQXE/MNmYO/TQ3Eihk
10
+ iSG68I764XKHbsG+Byoa2rW8NSaqEjniZ/7Rtkt4qasXMmdxlGgUP9bq6O45g8HV
11
+ kHxneFlA2KbrvmWnBi7NTea9+tp61NWiq5n97UgHacQR6KkYIpbxd7uNSnCSdmXt
12
+ pcwzO4ZPabJ2/DKRjePhU5OggPh+9AhJ3jsBo99GwYPgSZDh8E3vh2OWOtLBMUH3
13
+ rmAYwlRT2aZ5hy5yi+4QD98WoUQtsr+9n757F8V6MQKBgQDzZycdgaKwWd5d34NN
14
+ 0TkFtPQPwxxJTCCs3I3q02uWcS3svQzBK0cWb4nISO04TnJ3MnXo83dgGhCMF+uZ
15
+ FCXxAA53z8F92iZo+ELlXFDFwNeNYih/afDA42tWZ6TlVsDnZ4zQgRjHS7jEF/JV
16
+ 0ZgwGpw5725JQt64dic8wTOcDQKBgQDk7YYACQcWTnmjDhZQ3PZSX4fcTtzPZKZj
17
+ fa1GrXEaUH1hSyc9VmY6qJpUmXexpvtr194nXE+O5wbThOHcBjVlo2Qv+vswmUX3
18
+ WEcVzTVN4/fODCLCqFcMNIr+BzwZfwpT+p0u8g9FxDy1gGmvkxwIu8DCpnUT12Xj
19
+ hm2wO+UxKQKBgFxCSDBF9+2SUtgQJYv0dwGzwiLLWMhro6MCAoT02D3w7nBihBgg
20
+ GFTnuDkDc285ROfrZ4gB6MizeHwxgOrIGU2NMO62/+d9LbvyBiE76Z3bZ5i+kQ0i
21
+ kc/7I69fn8ASLxJHTLenh0XbbNBfJ0riJCZvn7HSEGKShysyFdNQhAhtAoGAFYVi
22
+ 0IQIv4cXFkYPwQBUw7+pVQOw7GpI3heFf5x0goXIk6nuAW0q5R7Oi192CiRphGTh
23
+ xI+ABy4ezSmz1exbfreShpQwowv1sOACpsEI3s6skBlB90y+Ci6yVlk1xCvWO7jW
24
+ qAAngWaGUoXE6bWJsCR+ZY4ieYAJWw9bJnMrA6kCgYAzV4Xeoh5ofENZM21wKW3W
25
+ iCzRibPObv6Vb/j9A9yT57yzI3BdfvsX5zmuSvOJm1DimgGY9nCJUzUEYG0a1Dhh
26
+ /rqObPoVIFGesmvwflVYFktmVHk7ycEDVreSTz23cvmraPz1fnpdKeuEs4sRQJV7
27
+ iJhLoxX5SJlJc0RXMhgHGQ==
28
+ -----END PRIVATE KEY-----
@@ -1,87 +1,85 @@
1
- /* eslint-disable camelcase */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
- /* eslint-disable @typescript-eslint/no-unused-vars */
4
-
5
- export type MockGrecaptchaMode = 'success' | 'expired' | 'error';
6
-
7
- export class MockGrecaptcha implements ReCaptchaV2.ReCaptcha {
8
- response = 'foo';
9
-
10
- renderCalled = false;
11
-
12
- executeCalled = false;
13
-
14
- resetCallCount = 0;
15
-
16
- getResponseCalled = false;
17
-
18
- mode: MockGrecaptchaMode;
19
-
20
- addDelay: boolean;
21
-
22
- callback?: (response: string) => void;
23
-
24
- 'expired-callback'?: () => void;
25
-
26
- 'error-callback'?: () => void;
27
-
28
- render(
29
- container: string | HTMLElement,
30
- parameters?: ReCaptchaV2.Parameters | undefined,
31
- inherit?: boolean | undefined
32
- ): number {
33
- this.callback = parameters?.callback?.bind(this);
34
- this['error-callback'] = parameters?.['error-callback']?.bind(this);
35
- this['expired-callback'] = parameters?.['expired-callback']?.bind(this);
36
- this.renderCalled = true;
37
- return 1;
38
- }
39
-
40
- reset(opt_widget_id?: number | undefined): void {
41
- this.resetCallCount += 1;
42
- }
43
-
44
- getResponse(opt_widget_id?: number | undefined): string {
45
- this.getResponseCalled = true;
46
- return 'foo';
47
- }
48
-
49
- execute(opt_widget_id?: number): void {
50
- this.executeCalled = true;
51
-
52
- if (this.addDelay) {
53
- setTimeout(this.callCallback.bind(this), 100);
54
- } else {
55
- this.callCallback();
56
- }
57
- }
58
-
59
- ready(callback: () => void): void {}
60
-
61
- private callCallback(): void {
62
- switch (this.mode) {
63
- case 'success':
64
- if (this.callback) {
65
- this.callback('foo');
66
- }
67
- break;
68
- case 'error':
69
- if (this['error-callback']) {
70
- this['error-callback']();
71
- }
72
- break;
73
- case 'expired':
74
- if (this['expired-callback']) {
75
- this['expired-callback']();
76
- }
77
- break;
78
- default:
79
- break;
80
- }
81
- }
82
-
83
- constructor(options: { mode: MockGrecaptchaMode; addDelay?: boolean }) {
84
- this.mode = options.mode;
85
- this.addDelay = options.addDelay ?? false;
86
- }
87
- }
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+
3
+ export type MockGrecaptchaMode = 'success' | 'expired' | 'error';
4
+
5
+ export class MockGrecaptcha implements ReCaptchaV2.ReCaptcha {
6
+ response = 'foo';
7
+
8
+ renderCalled = false;
9
+
10
+ executeCalled = false;
11
+
12
+ resetCallCount = 0;
13
+
14
+ getResponseCalled = false;
15
+
16
+ mode: MockGrecaptchaMode;
17
+
18
+ addDelay: boolean;
19
+
20
+ callback?: (response: string) => void;
21
+
22
+ 'expired-callback'?: () => void;
23
+
24
+ 'error-callback'?: () => void;
25
+
26
+ render(
27
+ container: string | HTMLElement,
28
+ parameters?: ReCaptchaV2.Parameters | undefined,
29
+ inherit?: boolean | undefined,
30
+ ): number {
31
+ this.callback = parameters?.callback?.bind(this);
32
+ this['error-callback'] = parameters?.['error-callback']?.bind(this);
33
+ this['expired-callback'] = parameters?.['expired-callback']?.bind(this);
34
+ this.renderCalled = true;
35
+ return 1;
36
+ }
37
+
38
+ reset(opt_widget_id?: number | undefined): void {
39
+ this.resetCallCount += 1;
40
+ }
41
+
42
+ getResponse(opt_widget_id?: number | undefined): string {
43
+ this.getResponseCalled = true;
44
+ return 'foo';
45
+ }
46
+
47
+ execute(opt_widget_id?: number): void {
48
+ this.executeCalled = true;
49
+
50
+ if (this.addDelay) {
51
+ setTimeout(this.callCallback.bind(this), 100);
52
+ } else {
53
+ this.callCallback();
54
+ }
55
+ }
56
+
57
+ ready(callback: () => void): void {}
58
+
59
+ private callCallback(): void {
60
+ switch (this.mode) {
61
+ case 'success':
62
+ if (this.callback) {
63
+ this.callback('foo');
64
+ }
65
+ break;
66
+ case 'error':
67
+ if (this['error-callback']) {
68
+ this['error-callback']();
69
+ }
70
+ break;
71
+ case 'expired':
72
+ if (this['expired-callback']) {
73
+ this['expired-callback']();
74
+ }
75
+ break;
76
+ default:
77
+ break;
78
+ }
79
+ }
80
+
81
+ constructor(options: { mode: MockGrecaptchaMode; addDelay?: boolean }) {
82
+ this.mode = options.mode;
83
+ this.addDelay = options.addDelay ?? false;
84
+ }
85
+ }
@@ -1,38 +1,39 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import {
3
- BundleType,
4
- LazyLoaderServiceEvents,
5
- LazyLoaderServiceInterface,
6
- } from '@internetarchive/lazy-loader-service';
7
- import { Unsubscribe } from 'nanoevents';
8
- import { MockGrecaptcha } from './mock-grecaptcha';
9
-
10
- export class MockLazyLoaderService implements LazyLoaderServiceInterface {
11
- loadScriptSrc?: string;
12
-
13
- on<E extends keyof LazyLoaderServiceEvents>(
14
- event: E,
15
- callback: LazyLoaderServiceEvents[E]
16
- ): Unsubscribe {
17
- throw new Error('Method not implemented.');
18
- }
19
-
20
- async loadBundle(bundle: {
21
- module?: string;
22
- nomodule?: string;
23
- }): Promise<void> {
24
- console.debug('loadBundle', bundle);
25
- }
26
-
27
- async loadScript(options: {
28
- src: string;
29
- bundleType?: BundleType;
30
- attributes?: Record<string, string>;
31
- }): Promise<void> {
32
- this.loadScriptSrc = options.src;
33
- window.grecaptcha = new MockGrecaptcha({
34
- mode: 'success',
35
- });
36
- (window as any).grecaptchaLoadedCallback();
37
- }
38
- }
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {
3
+ BundleType,
4
+ LazyLoaderServiceEvents,
5
+ LazyLoaderServiceInterface,
6
+ } from '@internetarchive/lazy-loader-service';
7
+ import { Unsubscribe } from 'nanoevents';
8
+ import { MockGrecaptcha } from './mock-grecaptcha';
9
+
10
+ export class MockLazyLoaderService implements LazyLoaderServiceInterface {
11
+ loadScriptSrc?: string;
12
+
13
+ on<E extends keyof LazyLoaderServiceEvents>(
14
+ event: E,
15
+ callback: LazyLoaderServiceEvents[E],
16
+ ): Unsubscribe {
17
+ throw new Error('Method not implemented.');
18
+ }
19
+
20
+ async loadBundle(bundle: {
21
+ module?: string;
22
+ nomodule?: string;
23
+ }): Promise<void> {
24
+ console.debug('loadBundle', bundle);
25
+ }
26
+
27
+ async loadScript(options: {
28
+ src: string;
29
+ bundleType?: BundleType;
30
+ attributes?: Record<string, string>;
31
+ }): Promise<void> {
32
+ this.loadScriptSrc = options.src;
33
+ window.grecaptcha = new MockGrecaptcha({
34
+ mode: 'success',
35
+ });
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ (window as any).grecaptchaLoadedCallback();
38
+ }
39
+ }