@prosopo/procaptcha-frictionless 2.13.22 → 2.14.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.
- package/.turbo/turbo-build$colon$cjs.log +3 -3
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +74 -0
- package/dist/ProcaptchaFrictionless.d.ts.map +1 -1
- package/dist/ProcaptchaFrictionless.js +45 -4
- package/dist/ProcaptchaFrictionless.js.map +1 -1
- package/dist/cjs/ProcaptchaFrictionless.cjs +44 -3
- package/dist/tests/manualStart.test.d.ts +5 -0
- package/dist/tests/manualStart.test.d.ts.map +1 -0
- package/dist/tests/manualStart.test.js +254 -0
- package/dist/tests/manualStart.test.js.map +1 -0
- package/package.json +13 -13
- package/src/ProcaptchaFrictionless.tsx +74 -2
- package/src/tests/manualStart.test.tsx +388 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { CaptchaType, ModeEnum, PROCAPTCHA_START_EVENT, StartModeEnum, } from "@prosopo/types";
|
|
2
|
+
import { act, createElement } from "react";
|
|
3
|
+
import { createRoot } from "react-dom/client";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
6
|
+
const mocks = vi.hoisted(() => ({
|
|
7
|
+
mounts: [],
|
|
8
|
+
}));
|
|
9
|
+
const stub = (widget) => (props) => {
|
|
10
|
+
mocks.mounts.push({ widget, props });
|
|
11
|
+
return createElement("div", { "data-widget": widget });
|
|
12
|
+
};
|
|
13
|
+
vi.mock("@prosopo/procaptcha-pow", () => ({ ProcaptchaPow: stub("pow") }));
|
|
14
|
+
vi.mock("@prosopo/procaptcha-react", () => ({ Procaptcha: stub("image") }));
|
|
15
|
+
vi.mock("@prosopo/procaptcha-puzzle", () => ({
|
|
16
|
+
ProcaptchaPuzzle: stub("puzzle"),
|
|
17
|
+
}));
|
|
18
|
+
vi.mock("@prosopo/procaptcha-common", async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal();
|
|
20
|
+
return { ...actual, isSecureBrowserContext: () => true };
|
|
21
|
+
});
|
|
22
|
+
const { ProcaptchaFrictionless } = await import("../ProcaptchaFrictionless.js");
|
|
23
|
+
const SITE_KEY = "5siteKey";
|
|
24
|
+
const SESSION_ID = "provider-session";
|
|
25
|
+
const config = (overrides = {}) => ({
|
|
26
|
+
account: { address: SITE_KEY },
|
|
27
|
+
userAccountAddress: "",
|
|
28
|
+
web2: true,
|
|
29
|
+
mode: ModeEnum.visible,
|
|
30
|
+
startMode: StartModeEnum.manual,
|
|
31
|
+
...overrides,
|
|
32
|
+
});
|
|
33
|
+
const i18nStub = {
|
|
34
|
+
isInitialized: true,
|
|
35
|
+
language: "en",
|
|
36
|
+
t: (key) => key,
|
|
37
|
+
changeLanguage: vi.fn(),
|
|
38
|
+
};
|
|
39
|
+
const detectionResult = () => ({
|
|
40
|
+
status: "ok",
|
|
41
|
+
captchaType: CaptchaType.image,
|
|
42
|
+
sessionId: SESSION_ID,
|
|
43
|
+
provider: { provider: { url: "https://provider.test" } },
|
|
44
|
+
userAccount: { account: { address: "5FakeUserAccountAddress" } },
|
|
45
|
+
});
|
|
46
|
+
const detectBotResolving = () => vi.fn().mockResolvedValue(detectionResult());
|
|
47
|
+
let host;
|
|
48
|
+
let root;
|
|
49
|
+
const mountWrapper = async (options = {}) => {
|
|
50
|
+
const detectBot = options.detectBot ?? detectBotResolving();
|
|
51
|
+
await act(async () => {
|
|
52
|
+
root.render(createElement(ProcaptchaFrictionless, {
|
|
53
|
+
config: options.config ?? config(),
|
|
54
|
+
callbacks: {},
|
|
55
|
+
restart: vi.fn(),
|
|
56
|
+
i18n: i18nStub,
|
|
57
|
+
detectBot,
|
|
58
|
+
container: options.container,
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
return detectBot;
|
|
62
|
+
};
|
|
63
|
+
const checkbox = () => {
|
|
64
|
+
const element = host.querySelector('[data-cy="captcha-checkbox"]');
|
|
65
|
+
if (!element)
|
|
66
|
+
throw new Error("expected the checkbox to be on the page");
|
|
67
|
+
return element;
|
|
68
|
+
};
|
|
69
|
+
const spinner = () => host.querySelector('[aria-label="Loading spinner"]');
|
|
70
|
+
const lastMountOf = (widget) => {
|
|
71
|
+
const mount = mocks.mounts.filter((m) => m.widget === widget).at(-1);
|
|
72
|
+
if (!mount)
|
|
73
|
+
throw new Error(`expected the ${widget} widget to have mounted`);
|
|
74
|
+
return mount;
|
|
75
|
+
};
|
|
76
|
+
const setTrusted = (event, trusted) => {
|
|
77
|
+
for (const symbol of Object.getOwnPropertySymbols(event)) {
|
|
78
|
+
const impl = Reflect.get(event, symbol);
|
|
79
|
+
if (impl && typeof impl === "object" && "isTrusted" in impl) {
|
|
80
|
+
Object.defineProperty(impl, "isTrusted", {
|
|
81
|
+
configurable: true,
|
|
82
|
+
get: () => trusted,
|
|
83
|
+
set: () => undefined,
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw new Error("could not reach the jsdom event implementation");
|
|
89
|
+
};
|
|
90
|
+
const click = async (element, options = {}) => {
|
|
91
|
+
const event = new MouseEvent("click", {
|
|
92
|
+
bubbles: true,
|
|
93
|
+
cancelable: true,
|
|
94
|
+
clientX: options.clientX ?? 0,
|
|
95
|
+
clientY: options.clientY ?? 0,
|
|
96
|
+
});
|
|
97
|
+
setTrusted(event, options.trusted ?? true);
|
|
98
|
+
await act(async () => {
|
|
99
|
+
element.dispatchEvent(event);
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const dispatchStart = async (detail) => {
|
|
103
|
+
await act(async () => {
|
|
104
|
+
document.dispatchEvent(new CustomEvent(PROCAPTCHA_START_EVENT, {
|
|
105
|
+
detail,
|
|
106
|
+
bubbles: true,
|
|
107
|
+
}));
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
const dispatchExecute = async () => {
|
|
111
|
+
await act(async () => {
|
|
112
|
+
document.dispatchEvent(new CustomEvent("procaptcha:execute"));
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
beforeEach(() => {
|
|
116
|
+
mocks.mounts.length = 0;
|
|
117
|
+
host = document.createElement("div");
|
|
118
|
+
document.body.appendChild(host);
|
|
119
|
+
act(() => {
|
|
120
|
+
root = createRoot(host);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
afterEach(() => {
|
|
124
|
+
act(() => {
|
|
125
|
+
root.unmount();
|
|
126
|
+
});
|
|
127
|
+
host.remove();
|
|
128
|
+
vi.clearAllMocks();
|
|
129
|
+
});
|
|
130
|
+
describe("manual start mode", () => {
|
|
131
|
+
it("mounts a live checkbox without running detection", async () => {
|
|
132
|
+
const detectBot = await mountWrapper();
|
|
133
|
+
expect(detectBot).not.toHaveBeenCalled();
|
|
134
|
+
expect(mocks.mounts).toHaveLength(0);
|
|
135
|
+
expect(checkbox().disabled).toBe(false);
|
|
136
|
+
expect(spinner()).toBeNull();
|
|
137
|
+
});
|
|
138
|
+
it("still runs detection on mount in auto mode", async () => {
|
|
139
|
+
const detectBot = await mountWrapper({
|
|
140
|
+
config: config({ startMode: StartModeEnum.auto }),
|
|
141
|
+
});
|
|
142
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
143
|
+
expect(lastMountOf("image").props.autoStart).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
it("defaults to auto when no start mode is given", async () => {
|
|
146
|
+
const detectBot = await mountWrapper({
|
|
147
|
+
config: config({ startMode: undefined }),
|
|
148
|
+
});
|
|
149
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
150
|
+
});
|
|
151
|
+
describe("started by the site", () => {
|
|
152
|
+
it("runs detection on procaptcha:start and leaves the widget waiting for a click", async () => {
|
|
153
|
+
const detectBot = await mountWrapper();
|
|
154
|
+
await dispatchStart();
|
|
155
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
156
|
+
const mount = lastMountOf("image").props;
|
|
157
|
+
expect(mount.autoStart).toBe(false);
|
|
158
|
+
expect(mount.startCoords).toBeUndefined();
|
|
159
|
+
expect(mount.frictionlessState?.sessionId).toBe(SESSION_ID);
|
|
160
|
+
});
|
|
161
|
+
it("honours an event addressed to its own element", async () => {
|
|
162
|
+
const widgetElement = document.createElement("div");
|
|
163
|
+
const container = document.createElement("div");
|
|
164
|
+
widgetElement.appendChild(container);
|
|
165
|
+
const detectBot = await mountWrapper({ container });
|
|
166
|
+
await dispatchStart({ element: widgetElement });
|
|
167
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
168
|
+
});
|
|
169
|
+
it("ignores an event addressed to another widget's element", async () => {
|
|
170
|
+
const container = document.createElement("div");
|
|
171
|
+
document.createElement("div").appendChild(container);
|
|
172
|
+
const detectBot = await mountWrapper({ container });
|
|
173
|
+
await dispatchStart({ element: document.createElement("div") });
|
|
174
|
+
expect(detectBot).not.toHaveBeenCalled();
|
|
175
|
+
expect(checkbox().disabled).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
it("receives every event when mounted without a container", async () => {
|
|
178
|
+
const detectBot = await mountWrapper();
|
|
179
|
+
await dispatchStart({ element: document.createElement("div") });
|
|
180
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
181
|
+
});
|
|
182
|
+
it("opens the challenge straight away on procaptcha:execute", async () => {
|
|
183
|
+
const detectBot = await mountWrapper({
|
|
184
|
+
config: config({ mode: ModeEnum.invisible }),
|
|
185
|
+
});
|
|
186
|
+
await dispatchExecute();
|
|
187
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
188
|
+
expect(lastMountOf("image").props.autoStart).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
it("ignores the events once started", async () => {
|
|
191
|
+
const detectBot = await mountWrapper();
|
|
192
|
+
await dispatchStart();
|
|
193
|
+
await dispatchStart();
|
|
194
|
+
await dispatchExecute();
|
|
195
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
196
|
+
expect(mocks.mounts).toHaveLength(1);
|
|
197
|
+
});
|
|
198
|
+
it("does not react to the events in auto mode", async () => {
|
|
199
|
+
const detectBot = await mountWrapper({
|
|
200
|
+
config: config({ startMode: StartModeEnum.auto }),
|
|
201
|
+
});
|
|
202
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
203
|
+
await dispatchStart();
|
|
204
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe("started by the user", () => {
|
|
208
|
+
it("runs detection on a checkbox click and opens the challenge where the user clicked", async () => {
|
|
209
|
+
const detectBot = await mountWrapper();
|
|
210
|
+
await click(checkbox(), { clientX: 11, clientY: 22 });
|
|
211
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
212
|
+
const mount = lastMountOf("image").props;
|
|
213
|
+
expect(mount.autoStart).toBe(true);
|
|
214
|
+
expect(mount.startCoords).toEqual({ x: 11, y: 22 });
|
|
215
|
+
});
|
|
216
|
+
it("opens the challenge after a keyboard activation with no position", async () => {
|
|
217
|
+
const detectBot = await mountWrapper();
|
|
218
|
+
await click(checkbox());
|
|
219
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
220
|
+
const mount = lastMountOf("image").props;
|
|
221
|
+
expect(mount.autoStart).toBe(true);
|
|
222
|
+
expect(mount.startCoords).toBeUndefined();
|
|
223
|
+
});
|
|
224
|
+
it("shows the spinner while the deferred flow runs", async () => {
|
|
225
|
+
let finish;
|
|
226
|
+
const detectBot = vi.fn().mockImplementation(() => new Promise((resolve) => {
|
|
227
|
+
finish = resolve;
|
|
228
|
+
}));
|
|
229
|
+
await mountWrapper({ detectBot });
|
|
230
|
+
await click(checkbox(), { clientX: 1, clientY: 1 });
|
|
231
|
+
expect(spinner()).not.toBeNull();
|
|
232
|
+
expect(mocks.mounts).toHaveLength(0);
|
|
233
|
+
await act(async () => {
|
|
234
|
+
finish?.(detectionResult());
|
|
235
|
+
});
|
|
236
|
+
expect(spinner()).toBeNull();
|
|
237
|
+
expect(lastMountOf("image").props.autoStart).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
it("ignores a synthetic click", async () => {
|
|
240
|
+
const detectBot = await mountWrapper();
|
|
241
|
+
await click(checkbox(), { trusted: false, clientX: 1, clientY: 1 });
|
|
242
|
+
expect(detectBot).not.toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
it("starts once even if the site also asks", async () => {
|
|
245
|
+
const detectBot = await mountWrapper();
|
|
246
|
+
await click(checkbox(), { clientX: 3, clientY: 4 });
|
|
247
|
+
await dispatchStart();
|
|
248
|
+
expect(detectBot).toHaveBeenCalledTimes(1);
|
|
249
|
+
expect(mocks.mounts).toHaveLength(1);
|
|
250
|
+
expect(lastMountOf("image").props.startCoords).toEqual({ x: 3, y: 4 });
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
//# sourceMappingURL=manualStart.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manualStart.test.js","sourceRoot":"","sources":["../../src/tests/manualStart.test.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/procaptcha-frictionless",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,22 +30,22 @@
|
|
|
30
30
|
},
|
|
31
31
|
"browserslist": ["> 0.5%, last 2 versions, not dead"],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@prosopo/api": "4.1.
|
|
34
|
-
"@prosopo/common": "3.1.
|
|
35
|
-
"@prosopo/locale": "3.4.
|
|
36
|
-
"@prosopo/procaptcha-common": "2.12.
|
|
37
|
-
"@prosopo/procaptcha-pow": "2.11.
|
|
38
|
-
"@prosopo/procaptcha-puzzle": "2.11.
|
|
39
|
-
"@prosopo/procaptcha-react": "2.9.
|
|
40
|
-
"@prosopo/types": "5.
|
|
41
|
-
"@prosopo/widget-skeleton": "2.8.
|
|
33
|
+
"@prosopo/api": "4.1.5",
|
|
34
|
+
"@prosopo/common": "3.1.53",
|
|
35
|
+
"@prosopo/locale": "3.4.1",
|
|
36
|
+
"@prosopo/procaptcha-common": "2.12.6",
|
|
37
|
+
"@prosopo/procaptcha-pow": "2.11.6",
|
|
38
|
+
"@prosopo/procaptcha-puzzle": "2.11.6",
|
|
39
|
+
"@prosopo/procaptcha-react": "2.9.122",
|
|
40
|
+
"@prosopo/types": "5.6.0",
|
|
41
|
+
"@prosopo/widget-skeleton": "2.8.7",
|
|
42
42
|
"dotenv": "16.4.5",
|
|
43
43
|
"react": "19.2.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@prosopo/config": "3.3.
|
|
46
|
+
"@prosopo/config": "3.3.13",
|
|
47
47
|
"@types/node": "22.10.2",
|
|
48
|
-
"@vitest/coverage-v8": "4.1.
|
|
48
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
49
49
|
"concurrently": "9.0.1",
|
|
50
50
|
"del-cli": "6.0.0",
|
|
51
51
|
"npm-run-all": "4.1.5",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"tsx": "4.20.3",
|
|
55
55
|
"typescript": "5.6.2",
|
|
56
56
|
"vite": "8.1.5",
|
|
57
|
-
"vitest": "4.1.
|
|
57
|
+
"vitest": "4.1.11"
|
|
58
58
|
},
|
|
59
59
|
"repository": {
|
|
60
60
|
"type": "git",
|
|
@@ -24,10 +24,14 @@ import {
|
|
|
24
24
|
CaptchaType,
|
|
25
25
|
type FrictionlessState,
|
|
26
26
|
type ModeType,
|
|
27
|
+
PROCAPTCHA_START_EVENT,
|
|
27
28
|
ProcaptchaConfigSchema,
|
|
28
29
|
type ProcaptchaFrictionlessProps,
|
|
30
|
+
type ProcaptchaStartEventDetail,
|
|
31
|
+
StartModeEnum,
|
|
29
32
|
} from "@prosopo/types";
|
|
30
33
|
import { darkTheme, lightTheme } from "@prosopo/widget-skeleton";
|
|
34
|
+
import type { KeyboardEvent, MouseEvent, TouchEvent } from "react";
|
|
31
35
|
import { useEffect, useRef, useState } from "react";
|
|
32
36
|
import customDetectBot from "./customDetectBot.js";
|
|
33
37
|
import { evaluateFrictionlessResult } from "./frictionlessResultGuard.js";
|
|
@@ -46,6 +50,12 @@ const ProcaptchaPuzzleLoader = async () =>
|
|
|
46
50
|
const ProcaptchaPowLoader = async () =>
|
|
47
51
|
(await import("@prosopo/procaptcha-pow")).ProcaptchaPow;
|
|
48
52
|
|
|
53
|
+
const PROCAPTCHA_EXECUTE_EVENT = "procaptcha:execute";
|
|
54
|
+
|
|
55
|
+
type CheckboxEvent = MouseEvent | TouchEvent | KeyboardEvent;
|
|
56
|
+
|
|
57
|
+
const noopCheckboxHandler = async (_event: CheckboxEvent): Promise<void> => {};
|
|
58
|
+
|
|
49
59
|
const renderPlaceholder = (
|
|
50
60
|
theme: string | undefined,
|
|
51
61
|
mode: ModeType,
|
|
@@ -53,6 +63,7 @@ const renderPlaceholder = (
|
|
|
53
63
|
isTranslationLoaded: boolean,
|
|
54
64
|
translationFn: (key: string) => string,
|
|
55
65
|
loading: boolean,
|
|
66
|
+
onChange: (event: CheckboxEvent) => Promise<void> = noopCheckboxHandler,
|
|
56
67
|
) => {
|
|
57
68
|
const checkboxTheme = "light" === theme ? lightTheme : darkTheme;
|
|
58
69
|
|
|
@@ -63,7 +74,7 @@ const renderPlaceholder = (
|
|
|
63
74
|
return (
|
|
64
75
|
<Checkbox
|
|
65
76
|
theme={checkboxTheme}
|
|
66
|
-
onChange={
|
|
77
|
+
onChange={onChange}
|
|
67
78
|
checked={false}
|
|
68
79
|
labelText={isTranslationLoaded ? translationFn("WIDGET.I_AM_HUMAN") : ""}
|
|
69
80
|
error={errorMessage}
|
|
@@ -116,6 +127,10 @@ export const ProcaptchaFrictionless = ({
|
|
|
116
127
|
// because `providerRetry` re-invokes `start` with no arguments, which would
|
|
117
128
|
// otherwise drop the flag on the first provider retry.
|
|
118
129
|
const nextMountAutoStartRef = useRef(false);
|
|
130
|
+
const manualStart = config.startMode === StartModeEnum.manual;
|
|
131
|
+
const manualStartedRef = useRef(false);
|
|
132
|
+
// The placeholder is built before `start()` exists in this scope.
|
|
133
|
+
const manualCheckboxHandlerRef = useRef(noopCheckboxHandler);
|
|
119
134
|
|
|
120
135
|
useEffect(() => {
|
|
121
136
|
if (!config.language) return;
|
|
@@ -139,7 +154,10 @@ export const ProcaptchaFrictionless = ({
|
|
|
139
154
|
stateRef.current.errorMessage,
|
|
140
155
|
i18n.isInitialized,
|
|
141
156
|
i18n.t,
|
|
142
|
-
|
|
157
|
+
!manualStart,
|
|
158
|
+
manualStart
|
|
159
|
+
? (event: CheckboxEvent) => manualCheckboxHandlerRef.current(event)
|
|
160
|
+
: undefined,
|
|
143
161
|
),
|
|
144
162
|
);
|
|
145
163
|
|
|
@@ -374,6 +392,59 @@ export const ProcaptchaFrictionless = ({
|
|
|
374
392
|
});
|
|
375
393
|
};
|
|
376
394
|
|
|
395
|
+
const startManually = async (
|
|
396
|
+
autoStart: boolean,
|
|
397
|
+
coords?: RetryCoords,
|
|
398
|
+
): Promise<void> => {
|
|
399
|
+
if (manualStartedRef.current) return;
|
|
400
|
+
manualStartedRef.current = true;
|
|
401
|
+
pendingRetryCoordsRef.current = coords ?? null;
|
|
402
|
+
nextMountAutoStartRef.current = autoStart;
|
|
403
|
+
setComponentToRender(
|
|
404
|
+
renderPlaceholder(
|
|
405
|
+
config.theme,
|
|
406
|
+
config.mode,
|
|
407
|
+
stateRef.current.errorMessage,
|
|
408
|
+
i18n.isInitialized,
|
|
409
|
+
i18n.t,
|
|
410
|
+
true,
|
|
411
|
+
),
|
|
412
|
+
);
|
|
413
|
+
await start();
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
manualCheckboxHandlerRef.current = async (event: CheckboxEvent) => {
|
|
417
|
+
let x = 0;
|
|
418
|
+
let y = 0;
|
|
419
|
+
const nativeEvent = event.nativeEvent;
|
|
420
|
+
if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
|
|
421
|
+
x = nativeEvent.clientX;
|
|
422
|
+
y = nativeEvent.clientY;
|
|
423
|
+
}
|
|
424
|
+
await startManually(true, normaliseRetryCoords(x, y) ?? undefined);
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: intentional — `startManually` captures the mount-time `start()`, as the auto-mode effect below does.
|
|
428
|
+
useEffect(() => {
|
|
429
|
+
if (!manualStart) return;
|
|
430
|
+
const onStartEvent = (event: Event) => {
|
|
431
|
+
const detail = (event as CustomEvent<ProcaptchaStartEventDetail>).detail;
|
|
432
|
+
if (detail?.element && container && !detail.element.contains(container)) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
void startManually(false);
|
|
436
|
+
};
|
|
437
|
+
const onExecuteEvent = () => {
|
|
438
|
+
void startManually(true);
|
|
439
|
+
};
|
|
440
|
+
document.addEventListener(PROCAPTCHA_START_EVENT, onStartEvent);
|
|
441
|
+
document.addEventListener(PROCAPTCHA_EXECUTE_EVENT, onExecuteEvent);
|
|
442
|
+
return () => {
|
|
443
|
+
document.removeEventListener(PROCAPTCHA_START_EVENT, onStartEvent);
|
|
444
|
+
document.removeEventListener(PROCAPTCHA_EXECUTE_EVENT, onExecuteEvent);
|
|
445
|
+
};
|
|
446
|
+
}, [manualStart, container]);
|
|
447
|
+
|
|
377
448
|
// Track which config identity has already been started for. Host
|
|
378
449
|
// pages often recreate the `callbacks` object (and sometimes the whole
|
|
379
450
|
// `config`) on every render, which — before this guard — re-fired
|
|
@@ -399,6 +470,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
399
470
|
}`;
|
|
400
471
|
if (startedForKeyRef.current === key) return;
|
|
401
472
|
startedForKeyRef.current = key;
|
|
473
|
+
if (manualStart) return;
|
|
402
474
|
void start();
|
|
403
475
|
}, [config.account?.address, config.language, config.mode]);
|
|
404
476
|
|