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

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 (50) hide show
  1. package/.editorconfig +29 -29
  2. package/.github/workflows/ci.yml +26 -26
  3. package/.husky/pre-commit +4 -4
  4. package/LICENSE +661 -661
  5. package/README.md +85 -85
  6. package/demo/app-root.ts +93 -93
  7. package/demo/index.html +21 -21
  8. package/dist/demo/app-root.d.ts +14 -14
  9. package/dist/demo/app-root.js +85 -85
  10. package/dist/demo/app-root.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +2 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/src/recaptcha-manager.d.ts +35 -35
  15. package/dist/src/recaptcha-manager.js +52 -52
  16. package/dist/src/recaptcha-manager.js.map +1 -1
  17. package/dist/src/recaptcha-widget.d.ts +39 -39
  18. package/dist/src/recaptcha-widget.js +95 -95
  19. package/dist/src/recaptcha-widget.js.map +1 -1
  20. package/dist/test/mock-grecaptcha.d.ts +24 -24
  21. package/dist/test/mock-grecaptcha.js +61 -61
  22. package/dist/test/mock-grecaptcha.js.map +1 -1
  23. package/dist/test/mock-lazy-loader.d.ts +15 -15
  24. package/dist/test/mock-lazy-loader.js +16 -16
  25. package/dist/test/mock-lazy-loader.js.map +1 -1
  26. package/dist/test/recaptcha-manager.test.d.ts +1 -1
  27. package/dist/test/recaptcha-manager.test.js +137 -137
  28. package/dist/test/recaptcha-manager.test.js.map +1 -1
  29. package/index.ts +10 -10
  30. package/package.json +98 -97
  31. package/src/recaptcha-manager.ts +87 -87
  32. package/src/recaptcha-widget.ts +148 -148
  33. package/test/mock-grecaptcha.ts +87 -87
  34. package/test/mock-lazy-loader.ts +38 -38
  35. package/test/recaptcha-manager.test.ts +151 -151
  36. package/tsconfig.json +20 -20
  37. package/web-dev-server.config.mjs +28 -28
  38. package/web-test-runner.config.mjs +41 -41
  39. package/dist/src/recaptcha-manager copy.d.ts +0 -82
  40. package/dist/src/recaptcha-manager copy.js +0 -140
  41. package/dist/src/recaptcha-manager copy.js.map +0 -1
  42. package/dist/src/recaptcha-manager-bak.d.ts +0 -82
  43. package/dist/src/recaptcha-manager-bak.js +0 -140
  44. package/dist/src/recaptcha-manager-bak.js.map +0 -1
  45. package/dist/src/recaptcha.d.ts +0 -28
  46. package/dist/src/recaptcha.js +0 -87
  47. package/dist/src/recaptcha.js.map +0 -1
  48. package/dist/test/your-webcomponent.test.d.ts +0 -0
  49. package/dist/test/your-webcomponent.test.js +0 -4
  50. package/dist/test/your-webcomponent.test.js.map +0 -1
@@ -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: 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,87 +1,87 @@
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 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,38 +1,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
- (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
+ (window as any).grecaptchaLoadedCallback();
37
+ }
38
+ }