@prosopo/procaptcha-frictionless 2.13.23 → 2.15.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 +4 -4
- package/CHANGELOG.md +89 -0
- package/dist/ProcaptchaFrictionless.d.ts.map +1 -1
- package/dist/ProcaptchaFrictionless.js +50 -6
- package/dist/ProcaptchaFrictionless.js.map +1 -1
- package/dist/cjs/ProcaptchaFrictionless.cjs +49 -5
- 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 +77 -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.15.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.
|
|
37
|
-
"@prosopo/procaptcha-pow": "2.
|
|
38
|
-
"@prosopo/procaptcha-puzzle": "2.
|
|
39
|
-
"@prosopo/procaptcha-react": "2.
|
|
40
|
-
"@prosopo/types": "5.
|
|
41
|
-
"@prosopo/widget-skeleton": "2.8.
|
|
33
|
+
"@prosopo/api": "4.1.6",
|
|
34
|
+
"@prosopo/common": "3.1.54",
|
|
35
|
+
"@prosopo/locale": "3.4.1",
|
|
36
|
+
"@prosopo/procaptcha-common": "2.13.0",
|
|
37
|
+
"@prosopo/procaptcha-pow": "2.12.0",
|
|
38
|
+
"@prosopo/procaptcha-puzzle": "2.12.0",
|
|
39
|
+
"@prosopo/procaptcha-react": "2.10.0",
|
|
40
|
+
"@prosopo/types": "5.7.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.14",
|
|
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
|
|
|
@@ -269,6 +287,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
269
287
|
autoStart={resumedAutoStart}
|
|
270
288
|
startCoords={startCoords}
|
|
271
289
|
onSessionInvalidated={onSessionInvalidated}
|
|
290
|
+
container={container}
|
|
272
291
|
onReload={onReload}
|
|
273
292
|
/>,
|
|
274
293
|
);
|
|
@@ -284,6 +303,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
284
303
|
autoStart={resumedAutoStart}
|
|
285
304
|
startCoords={startCoords}
|
|
286
305
|
onSessionInvalidated={onSessionInvalidated}
|
|
306
|
+
container={container}
|
|
287
307
|
/>,
|
|
288
308
|
);
|
|
289
309
|
} else {
|
|
@@ -299,6 +319,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
299
319
|
autoStart={resumedAutoStart}
|
|
300
320
|
startCoords={startCoords}
|
|
301
321
|
onSessionInvalidated={onSessionInvalidated}
|
|
322
|
+
container={container}
|
|
302
323
|
/>,
|
|
303
324
|
);
|
|
304
325
|
}
|
|
@@ -374,6 +395,59 @@ export const ProcaptchaFrictionless = ({
|
|
|
374
395
|
});
|
|
375
396
|
};
|
|
376
397
|
|
|
398
|
+
const startManually = async (
|
|
399
|
+
autoStart: boolean,
|
|
400
|
+
coords?: RetryCoords,
|
|
401
|
+
): Promise<void> => {
|
|
402
|
+
if (manualStartedRef.current) return;
|
|
403
|
+
manualStartedRef.current = true;
|
|
404
|
+
pendingRetryCoordsRef.current = coords ?? null;
|
|
405
|
+
nextMountAutoStartRef.current = autoStart;
|
|
406
|
+
setComponentToRender(
|
|
407
|
+
renderPlaceholder(
|
|
408
|
+
config.theme,
|
|
409
|
+
config.mode,
|
|
410
|
+
stateRef.current.errorMessage,
|
|
411
|
+
i18n.isInitialized,
|
|
412
|
+
i18n.t,
|
|
413
|
+
true,
|
|
414
|
+
),
|
|
415
|
+
);
|
|
416
|
+
await start();
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
manualCheckboxHandlerRef.current = async (event: CheckboxEvent) => {
|
|
420
|
+
let x = 0;
|
|
421
|
+
let y = 0;
|
|
422
|
+
const nativeEvent = event.nativeEvent;
|
|
423
|
+
if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
|
|
424
|
+
x = nativeEvent.clientX;
|
|
425
|
+
y = nativeEvent.clientY;
|
|
426
|
+
}
|
|
427
|
+
await startManually(true, normaliseRetryCoords(x, y) ?? undefined);
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: intentional — `startManually` captures the mount-time `start()`, as the auto-mode effect below does.
|
|
431
|
+
useEffect(() => {
|
|
432
|
+
if (!manualStart) return;
|
|
433
|
+
const onStartEvent = (event: Event) => {
|
|
434
|
+
const detail = (event as CustomEvent<ProcaptchaStartEventDetail>).detail;
|
|
435
|
+
if (detail?.element && container && !detail.element.contains(container)) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
void startManually(false);
|
|
439
|
+
};
|
|
440
|
+
const onExecuteEvent = () => {
|
|
441
|
+
void startManually(true);
|
|
442
|
+
};
|
|
443
|
+
document.addEventListener(PROCAPTCHA_START_EVENT, onStartEvent);
|
|
444
|
+
document.addEventListener(PROCAPTCHA_EXECUTE_EVENT, onExecuteEvent);
|
|
445
|
+
return () => {
|
|
446
|
+
document.removeEventListener(PROCAPTCHA_START_EVENT, onStartEvent);
|
|
447
|
+
document.removeEventListener(PROCAPTCHA_EXECUTE_EVENT, onExecuteEvent);
|
|
448
|
+
};
|
|
449
|
+
}, [manualStart, container]);
|
|
450
|
+
|
|
377
451
|
// Track which config identity has already been started for. Host
|
|
378
452
|
// pages often recreate the `callbacks` object (and sometimes the whole
|
|
379
453
|
// `config`) on every render, which — before this guard — re-fired
|
|
@@ -399,6 +473,7 @@ export const ProcaptchaFrictionless = ({
|
|
|
399
473
|
}`;
|
|
400
474
|
if (startedForKeyRef.current === key) return;
|
|
401
475
|
startedForKeyRef.current = key;
|
|
476
|
+
if (manualStart) return;
|
|
402
477
|
void start();
|
|
403
478
|
}, [config.account?.address, config.language, config.mode]);
|
|
404
479
|
|