captchakraken 2.8.0 → 3.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.
- package/AGENTS.md +112 -0
- package/NOTICE +36 -0
- package/dist/cli-invocation.d.ts +9 -40
- package/dist/cli-invocation.js +16 -49
- package/dist/errors.d.ts +7 -27
- package/dist/errors.js +6 -25
- package/dist/humanize.d.ts +56 -240
- package/dist/humanize.js +159 -415
- package/dist/index.d.ts +5 -129
- package/dist/index.js +4 -98
- package/dist/kinds.d.ts +135 -0
- package/dist/kinds.js +70 -0
- package/dist/limits.d.ts +0 -48
- package/dist/limits.js +2 -48
- package/dist/model-name.d.ts +4 -19
- package/dist/model-name.js +32 -40
- package/dist/playwright-types.d.ts +25 -95
- package/dist/playwright-types.js +0 -23
- package/dist/puppeteer-adapter.d.ts +4 -43
- package/dist/puppeteer-adapter.js +22 -58
- package/dist/python-command.d.ts +0 -41
- package/dist/python-command.js +0 -37
- package/dist/selectors.d.ts +54 -0
- package/dist/selectors.js +117 -0
- package/dist/slide-geometry.d.ts +2 -29
- package/dist/slide-geometry.js +18 -44
- package/dist/solver.d.ts +112 -539
- package/dist/solver.js +1088 -2950
- package/dist/timing.d.ts +7 -40
- package/dist/timing.js +4 -36
- package/dist/token-usage.d.ts +1 -7
- package/dist/token-usage.js +10 -95
- package/dist/types.d.ts +77 -483
- package/dist/watcher.d.ts +5 -78
- package/dist/watcher.js +0 -56
- package/package.json +12 -4
- package/python/AGENTS.md +122 -0
- package/python/NOTICE +36 -0
- package/python/README.md +1 -2
- package/python/examples/README.md +10 -0
- package/python/examples/_harness.py +4 -73
- package/python/examples/demoHcaptcha.py +0 -13
- package/python/examples/demoRecaptcha.py +0 -10
- package/python/examples/watch_playwright.py +1 -26
- package/python/examples/with_local_gguf.py +28 -0
- package/python/examples/with_playwright.py +0 -19
- package/python/pyproject.toml +68 -19
- package/python/src/captchakraken/__init__.py +37 -45
- package/python/src/captchakraken/action_types.py +14 -36
- package/python/src/captchakraken/cli.py +262 -879
- package/python/src/captchakraken/config.py +60 -146
- package/python/src/captchakraken/errors.py +17 -95
- package/python/src/captchakraken/humanize.py +174 -597
- package/python/src/captchakraken/image_processor.py +16 -235
- package/python/src/captchakraken/keyframes.py +69 -434
- package/python/src/captchakraken/kinds.py +152 -0
- package/python/src/captchakraken/models.json +79 -21
- package/python/src/captchakraken/overlay.py +65 -498
- package/python/src/captchakraken/page_solver.py +1123 -2564
- package/python/src/captchakraken/planner.py +70 -428
- package/python/src/captchakraken/prompts.py +45 -261
- package/python/src/captchakraken/selectors.py +184 -0
- package/python/src/captchakraken/server_manager.py +7 -58
- package/python/src/captchakraken/solver.py +128 -522
- package/python/src/captchakraken/timing.py +20 -74
- package/python/src/captchakraken/tool_calls/board_painted.py +47 -0
- package/python/src/captchakraken/tool_calls/find_checkbox.py +20 -30
- package/python/src/captchakraken/tool_calls/find_grid.py +186 -1339
- package/python/src/captchakraken/tool_calls/track_piece.py +81 -57
- package/python/src/captchakraken/updater.py +7 -76
- package/python/src/captchakraken/watcher.py +12 -101
- package/scripts/copy-python.mjs +10 -10
- package/scripts/setup-python.js +1 -21
- package/dist/trajectory.d.ts +0 -58
- package/dist/trajectory.js +0 -266
- package/python/src/captchakraken/tool_calls/move_indicator.py +0 -431
- package/python/src/captchakraken/trajectory.py +0 -284
package/dist/humanize.d.ts
CHANGED
|
@@ -1,92 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* How the driver
|
|
2
|
+
* How the driver moves: one pluggable object per input device. Mirrors python/humanize.py.
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
* CaptchaKrakenFinetune pins that the mode names and the pause vocabulary have
|
|
7
|
-
* not drifted.
|
|
4
|
+
* The pointer position lives here, not in the solver, because a touch mode that dispatches no
|
|
5
|
+
* motion between taps still has to say where the next gesture starts.
|
|
8
6
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - a caller driving a MOBILE page has no cursor. Dispatching mousemove at a
|
|
15
|
-
* touch-only widget is not weak humanisation, it is the wrong event type:
|
|
16
|
-
* the page's touch handlers never fire, and a vendor that scores pointer
|
|
17
|
-
* telemetry sees a desktop mouse on a phone.
|
|
18
|
-
* - a caller who has their OWN humanisation (a hardware pointer, a proxied
|
|
19
|
-
* device farm, a model of their own users) was composing two of them. That
|
|
20
|
-
* is not hypothetical — camoufox's `humanize` juggler re-humanises every
|
|
21
|
-
* `mouse.move()` it is handed, and running both measured 82.1s against
|
|
22
|
-
* 13.4s on one geetest_v4_slide solve, because each of the 60 trajectory
|
|
23
|
-
* points became its own humanised sub-trajectory.
|
|
24
|
-
* - a caller on their own infrastructure, against their own fixtures, is
|
|
25
|
-
* paying for texture nobody is measuring.
|
|
26
|
-
*
|
|
27
|
-
* So the vocabulary of gestures is an INTERFACE and the humanisation is an
|
|
28
|
-
* implementation of it. The solver says "tap here", "drag this there", "type
|
|
29
|
-
* that"; a `Humanizer` decides what events that is and how long it takes.
|
|
30
|
-
*
|
|
31
|
-
* Four modes, selected by `CaptchaKrakenConfig.humanization`:
|
|
32
|
-
*
|
|
33
|
-
* 'mouse' MouseHumanizer — the default, and byte-for-byte what the
|
|
34
|
-
* driver did before this module existed.
|
|
35
|
-
* 'mobile' MobileHumanizer — touch events, finger kinematics. Dispatches
|
|
36
|
-
* through a `TouchBackend`, so it drives either
|
|
37
|
-
* a Chromium-family page (CDP) or an
|
|
38
|
-
* Appium/WebdriverIO driver on a real device.
|
|
39
|
-
* 'none' NullHumanizer — the shortest legal path to the same DOM
|
|
40
|
-
* effect.
|
|
41
|
-
* custom anything satisfying `Humanizer`, passed as
|
|
42
|
-
* `CaptchaKrakenConfig.humanizer`.
|
|
43
|
-
*
|
|
44
|
-
* THE POINTER POSITION LIVES HERE, not in the solver. A humanizer that
|
|
45
|
-
* dispatches no motion at all (mobile, between taps) still has to answer "where
|
|
46
|
-
* is the pointer", because that is what the next gesture starts from and what
|
|
47
|
-
* `SolveResult.finalMousePosition` reports.
|
|
7
|
+
* Pluggable because camoufox's juggler re-humanises every mouse.move() it is handed, and running
|
|
8
|
+
* both measured 82s against 13s on one GeeTest slider; and a touch widget needs touch events, not
|
|
9
|
+
* mousemove. See TRIBAL_KNOWLEDGE.md. The 2026-09 cut removed our drag-overshoot redraw and swipe
|
|
10
|
+
* wobble in favour of Cursory's raw recordings; the one-pixel tap wobble stayed because a
|
|
11
|
+
* motionless tap is a synthetic one.
|
|
48
12
|
*/
|
|
49
13
|
import type { Page, PlaywrightElementHandle } from './playwright-types.js';
|
|
14
|
+
import { HumanizationMode, PauseKind } from './kinds.js';
|
|
15
|
+
export type { HumanizationMode, PauseKind } from './kinds.js';
|
|
50
16
|
export type Point = [number, number];
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* A vocabulary rather than a number at each call site, because the whole point
|
|
55
|
-
* of the mode switch is that these differ per device — a finger dwells on a tap
|
|
56
|
-
* about four times as long as a mouse button is held, and neither number means
|
|
57
|
-
* anything to the caller who turned humanisation off. Each mode supplies its own
|
|
58
|
-
* table below; an unknown name yields no wait rather than throwing, so adding a
|
|
59
|
-
* pause site cannot break a custom humanizer written against an older release.
|
|
60
|
-
*
|
|
61
|
-
* tap inside a click/tap, between press and release
|
|
62
|
-
* between between two taps of one batch (grid tiles)
|
|
63
|
-
* grab after pressing, before a drag starts moving
|
|
64
|
-
* drop after a drag arrives, before releasing
|
|
65
|
-
* probe between the slider's measurement nudges
|
|
66
|
-
* settle before releasing a slider — the release IS the submit, and some
|
|
67
|
-
* vendors sample the final milliseconds of the gesture
|
|
68
|
-
* key between two typed characters
|
|
69
|
-
*/
|
|
70
|
-
export type PauseKind = 'tap' | 'between' | 'grab' | 'drop' | 'probe' | 'settle' | 'key';
|
|
17
|
+
/** A recorded human movement morphed onto the endpoints; timings are cumulative ms. */
|
|
18
|
+
export declare function trajectory(start: Point, end: Point, frequency: number): [Point[], number[]];
|
|
19
|
+
/** Every inter-gesture wait the driver takes, named, so each device supplies its own table. */
|
|
71
20
|
export declare const PAUSE_KINDS: readonly PauseKind[];
|
|
72
|
-
/**
|
|
73
|
-
* The gesture vocabulary the solver drives. Implement this to supply your own
|
|
74
|
-
* humanisation; only `move`, `press`, `release`, `typeText` and `pause` are
|
|
75
|
-
* required, and `BaseHumanizer` composes `click`/`drag` from them.
|
|
76
|
-
*/
|
|
77
21
|
export interface Humanizer {
|
|
78
|
-
/** Mode name, for logs. */
|
|
79
22
|
readonly name: string;
|
|
80
|
-
/**
|
|
81
|
-
* Whether this device has a cursor that can rest somewhere without touching.
|
|
82
|
-
* False switches off every hover-for-realism behaviour — the reCAPTCHA tile
|
|
83
|
-
* hover and the idle drift during inference — because on a touchscreen those
|
|
84
|
-
* are not weak mimicry, they are impossible.
|
|
85
|
-
*/
|
|
23
|
+
/** False on a device with no resting cursor; switches off every hover-for-realism behaviour. */
|
|
86
24
|
readonly hovers: boolean;
|
|
87
|
-
/** Where the pointer is now. */
|
|
88
25
|
at: Point;
|
|
89
|
-
/** Called once at the top of each `solve()`. Drop per-page caches. */
|
|
90
26
|
reset(page: Page): Promise<void>;
|
|
91
27
|
move(page: Page, to: Point): Promise<void>;
|
|
92
28
|
press(page: Page): Promise<void>;
|
|
@@ -96,7 +32,7 @@ export interface Humanizer {
|
|
|
96
32
|
typeText(page: Page, field: PlaywrightElementHandle, text: string): Promise<boolean>;
|
|
97
33
|
pause(kind: PauseKind): Promise<void>;
|
|
98
34
|
}
|
|
99
|
-
type PauseTable = Record<
|
|
35
|
+
type PauseTable = Partial<Record<PauseKind, [number, number]>>;
|
|
100
36
|
export declare abstract class BaseHumanizer implements Humanizer {
|
|
101
37
|
abstract readonly name: string;
|
|
102
38
|
abstract readonly hovers: boolean;
|
|
@@ -108,190 +44,99 @@ export declare abstract class BaseHumanizer implements Humanizer {
|
|
|
108
44
|
abstract press(page: Page): Promise<void>;
|
|
109
45
|
abstract release(page: Page): Promise<void>;
|
|
110
46
|
abstract typeText(page: Page, field: PlaywrightElementHandle, text: string): Promise<boolean>;
|
|
47
|
+
/** An unknown kind waits nothing, so adding a pause site cannot break a custom humanizer written against an older release. */
|
|
111
48
|
protected pauseMs(kind: PauseKind): number;
|
|
112
49
|
pause(kind: PauseKind): Promise<void>;
|
|
113
50
|
click(page: Page, to: Point): Promise<void>;
|
|
114
51
|
drag(page: Page, src: Point, dst: Point): Promise<void>;
|
|
115
52
|
}
|
|
116
|
-
/**
|
|
117
|
-
* A hand on a mouse. Bezier arcs, Fitts's-law durations, overshoot.
|
|
118
|
-
*
|
|
119
|
-
* Everything in here was `solver.performSmoothMove` / `tracePath` before this
|
|
120
|
-
* module existed, and is unchanged: the constants were measured and a refactor
|
|
121
|
-
* is not the place to revisit them.
|
|
122
|
-
*/
|
|
123
53
|
export declare class MouseHumanizer extends BaseHumanizer {
|
|
124
|
-
readonly name
|
|
54
|
+
readonly name: HumanizationMode;
|
|
125
55
|
readonly hovers = true;
|
|
126
|
-
/** Inclusive ranges, in ms. See PauseKind. */
|
|
127
56
|
protected readonly pauses: PauseTable;
|
|
128
57
|
private frequency;
|
|
58
|
+
private viewportCache;
|
|
129
59
|
constructor(start?: Point, frequency?: number);
|
|
60
|
+
reset(_page: Page): Promise<void>;
|
|
61
|
+
/** The window to keep the cursor inside; null under camoufox, which reports no viewport and whose window we ask instead. */
|
|
62
|
+
private viewport;
|
|
130
63
|
move(page: Page, to: Point): Promise<void>;
|
|
131
64
|
press(page: Page): Promise<void>;
|
|
132
65
|
release(page: Page): Promise<void>;
|
|
66
|
+
/** Per character with a humanised pause, not type(text, {delay}): a constant inter-key delay is itself a signal these vendors score. */
|
|
133
67
|
typeText(page: Page, _field: PlaywrightElementHandle, text: string): Promise<boolean>;
|
|
134
|
-
private trace;
|
|
135
68
|
}
|
|
136
|
-
/** `[x, y, dtMs]
|
|
69
|
+
/** `[x, y, dtMs]`: dt is the wait before that sample. */
|
|
137
70
|
export type TouchSample = [number, number, number];
|
|
138
|
-
/**
|
|
139
|
-
* Where touch events actually go.
|
|
140
|
-
*
|
|
141
|
-
* Three methods rather than one per sample, because the two backends want
|
|
142
|
-
* opposite things: CDP dispatches one event per call and we pace it locally,
|
|
143
|
-
* while a W3C/Appium driver takes a whole timed action chain in one round trip
|
|
144
|
-
* and paces it on the device. Handing `move` the entire leg lets each do what it
|
|
145
|
-
* is good at — and on a real device, pacing over the wire is not pacing at all.
|
|
146
|
-
*/
|
|
71
|
+
/** Where touch events go. `move` takes a whole leg so a device driver can pace it itself. */
|
|
147
72
|
export interface TouchBackend {
|
|
148
73
|
readonly name: string;
|
|
149
74
|
down(x: number, y: number): Promise<void>;
|
|
150
75
|
move(path: TouchSample[]): Promise<void>;
|
|
151
76
|
up(x: number, y: number): Promise<void>;
|
|
152
77
|
}
|
|
153
|
-
/**
|
|
154
|
-
* `Input.dispatchTouchEvent` over a CDP session on a Playwright page.
|
|
155
|
-
*
|
|
156
|
-
* Chromium-family only, and that is checked at construction rather than
|
|
157
|
-
* discovered per gesture: WebKit and Firefox (camoufox included) expose no touch
|
|
158
|
-
* dispatch through Playwright at all, so the alternatives there are to fail
|
|
159
|
-
* loudly or to quietly emit MOUSE events at a touch-only widget. The second is
|
|
160
|
-
* worse than not running — the page's touch handlers never fire, the solve fails
|
|
161
|
-
* for a reason nothing reports, and the report reads as a model that cannot
|
|
162
|
-
* solve mobile puzzles.
|
|
163
|
-
*
|
|
164
|
-
* The context must also have been created with `hasTouch: true`, or the page
|
|
165
|
-
* advertises no touch support to feature detection and a mobile widget renders
|
|
166
|
-
* its desktop branch.
|
|
167
|
-
*/
|
|
78
|
+
/** `Input.dispatchTouchEvent` over CDP; Chromium-family pages launched with `hasTouch: true`. */
|
|
168
79
|
export declare class CdpTouchBackend implements TouchBackend {
|
|
169
|
-
readonly name = "cdp";
|
|
170
80
|
private session;
|
|
81
|
+
readonly name = "cdp";
|
|
171
82
|
private constructor();
|
|
83
|
+
/**
|
|
84
|
+
* Checked at construction, not per gesture. WebKit and Firefox expose no touch dispatch, and emitting
|
|
85
|
+
* mouse events instead is worse than not running: the page's touch handlers never fire and the report
|
|
86
|
+
* reads as a model that cannot solve mobile puzzles.
|
|
87
|
+
*/
|
|
172
88
|
static open(page: Page): Promise<CdpTouchBackend>;
|
|
173
89
|
private send;
|
|
174
90
|
down(x: number, y: number): Promise<void>;
|
|
175
91
|
move(path: TouchSample[]): Promise<void>;
|
|
176
92
|
up(_x: number, _y: number): Promise<void>;
|
|
177
93
|
}
|
|
178
|
-
/** CSS-pixel
|
|
94
|
+
/** CSS-pixel to device-pixel transform for a real handset. */
|
|
179
95
|
export interface TouchTransform {
|
|
180
96
|
scale?: number;
|
|
181
97
|
origin?: Point;
|
|
182
98
|
}
|
|
183
99
|
/**
|
|
184
|
-
* W3C pointer actions
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* kinematics are reproduced BY THE DEVICE rather than by a JS loop round-tripping
|
|
188
|
-
* over the wire — over which a 90Hz path is not 90Hz at all.
|
|
189
|
-
*
|
|
190
|
-
* Press and release are separate `performActions()` calls on purpose. W3C input
|
|
191
|
-
* state is per SESSION, so a pointer put down in one chain stays down across
|
|
192
|
-
* later chains until it is lifted; that is what lets the puzzle-slider driver
|
|
193
|
-
* press, screenshot, steer, screenshot and only then release. (It is also why
|
|
194
|
-
* the spec has a "release actions" endpoint at all.)
|
|
195
|
-
*
|
|
196
|
-
* COORDINATES. Everything upstream of here is CSS pixels in the page's viewport,
|
|
197
|
-
* because that is what `boundingBox()` returns. A real device wants screen
|
|
198
|
-
* pixels, and the two differ by the device pixel ratio and by whatever chrome
|
|
199
|
-
* sits above the webview. Neither is guessable from here, so both are options:
|
|
200
|
-
*
|
|
201
|
-
* new AppiumTouchBackend(driver, { scale: 3, origin: [0, 132] })
|
|
202
|
-
*
|
|
203
|
-
* `scale` is usually `window.devicePixelRatio`; `origin` is the top-left of the
|
|
204
|
-
* webview in screen coordinates. Defaults are the identity transform, which is
|
|
205
|
-
* correct for browser mobile emulation and for any caller who has already mapped
|
|
206
|
-
* the coordinates themselves.
|
|
100
|
+
* W3C touch pointer actions for Appium and WebdriverIO, paced by the device from one chain per leg.
|
|
101
|
+
* Raw protocol payloads so this imports no client. Press and release are separate performs because W3C
|
|
102
|
+
* input state is per session: that is what lets the slider driver press, screenshot, steer, then release.
|
|
207
103
|
*/
|
|
208
104
|
export declare class AppiumTouchBackend implements TouchBackend {
|
|
209
|
-
readonly name = "appium";
|
|
210
105
|
private driver;
|
|
106
|
+
private page?;
|
|
107
|
+
readonly name = "appium";
|
|
211
108
|
private scale;
|
|
212
109
|
private origin;
|
|
213
|
-
/**
|
|
214
|
-
* UNSET is not the same fact as an explicit 1. The first is a caller who has
|
|
215
|
-
* not thought about the transform; the second is one who has, and says the
|
|
216
|
-
* coordinates are already mapped. Only the first is checked.
|
|
217
|
-
*/
|
|
218
110
|
private scaleGiven;
|
|
219
|
-
private page;
|
|
220
111
|
private checked;
|
|
221
|
-
constructor(driver: any, transform?: TouchTransform, page?: Page);
|
|
112
|
+
constructor(driver: any, transform?: TouchTransform, page?: Page | undefined);
|
|
222
113
|
/**
|
|
223
|
-
* Refuse an unset scale on a
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
* valid W3C, the device performs it, and the finger lands somewhere else. The
|
|
227
|
-
* solve then fails looking exactly like a model that cannot read the puzzle.
|
|
228
|
-
*
|
|
229
|
-
* Read once, not per gesture — it is a round trip into the page and a solve
|
|
230
|
-
* makes hundreds of these. An unreadable ratio is absent evidence, not
|
|
231
|
-
* evidence of a mismatch, so it falls through to the identity. `origin`
|
|
232
|
-
* cannot be measured from here at all, so it is named in the refusal rather
|
|
233
|
-
* than guessed at.
|
|
114
|
+
* Refuse an unset scale on a device whose pixel ratio is not 1: the finger would land elsewhere. An
|
|
115
|
+
* explicit scale of 1 is the caller's word and is not re-checked; the ratio is read once, since a solve
|
|
116
|
+
* makes hundreds of these, and an unreadable ratio is taken as 1.
|
|
234
117
|
*/
|
|
235
118
|
private checkScale;
|
|
236
119
|
private map;
|
|
237
|
-
/**
|
|
238
|
-
* One W3C action chain on a single touch pointer.
|
|
239
|
-
*
|
|
240
|
-
* Sent as the raw protocol payload rather than through a client's action
|
|
241
|
-
* builder, so this imports nothing and works against any client that speaks
|
|
242
|
-
* WebDriver — WebdriverIO (`performActions`), selenium-webdriver, or a thin
|
|
243
|
-
* HTTP wrapper of someone's own.
|
|
244
|
-
*/
|
|
245
120
|
private perform;
|
|
246
121
|
down(x: number, y: number): Promise<void>;
|
|
122
|
+
/** The per-sample gap becomes the move's `duration`, so the device interpolates the leg itself. */
|
|
247
123
|
move(path: TouchSample[]): Promise<void>;
|
|
248
124
|
up(_x: number, _y: number): Promise<void>;
|
|
249
125
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Playwright's `page.touchscreen.tap()` — taps only, no travel.
|
|
252
|
-
*
|
|
253
|
-
* The fallback for a browser with touch support but no CDP (WebKit). A tap still
|
|
254
|
-
* lands correctly; a DRAG cannot be expressed at all, so it throws rather than
|
|
255
|
-
* approximating one with a mouse, for the reason in `CdpTouchBackend`.
|
|
256
|
-
*/
|
|
126
|
+
/** Playwright's tap-only touchscreen, for browsers with touch but no CDP. A drag cannot be expressed. */
|
|
257
127
|
export declare class TouchscreenTouchBackend implements TouchBackend {
|
|
258
|
-
readonly name = "touchscreen";
|
|
259
128
|
private page;
|
|
129
|
+
readonly name = "touchscreen";
|
|
260
130
|
private pending;
|
|
261
|
-
constructor(page:
|
|
131
|
+
constructor(page: any);
|
|
262
132
|
down(x: number, y: number): Promise<void>;
|
|
263
133
|
move(_path: TouchSample[]): Promise<void>;
|
|
264
134
|
up(x: number, y: number): Promise<void>;
|
|
265
135
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Pick a backend. An explicit `driver` always wins.
|
|
268
|
-
*
|
|
269
|
-
* `driver` is what a caller passes when the thing under automation is not the
|
|
270
|
-
* thing being touched — an Appium session driving a real handset while the page
|
|
271
|
-
* object is a webview bridge over it.
|
|
272
|
-
*/
|
|
273
136
|
export declare function touchBackendFor(page: Page, driver?: any, transform?: TouchTransform): Promise<TouchBackend>;
|
|
274
|
-
/**
|
|
275
|
-
* A finger on glass.
|
|
276
|
-
*
|
|
277
|
-
* What differs from `MouseHumanizer`, and none of it is cosmetic:
|
|
278
|
-
*
|
|
279
|
-
* - **A move that is not touching dispatches nothing.** There is no hover on a
|
|
280
|
-
* touchscreen. The position is still RECORDED, because the next gesture
|
|
281
|
-
* starts from it, but no event is emitted — emitting one would be the
|
|
282
|
-
* desktop tell this mode exists to remove.
|
|
283
|
-
* - **Taps carry a contact wobble.** A finger held on glass for 90ms does not
|
|
284
|
-
* report one unchanging coordinate; the centroid of the contact patch rolls
|
|
285
|
-
* a pixel or two under pressure. A tap with zero movement between touchstart
|
|
286
|
-
* and touchend is a synthetic tap.
|
|
287
|
-
* - **Touch kinematics**, via `generate_swipe` — see its docstring for why that
|
|
288
|
-
* is a different model rather than the mouse one retuned.
|
|
289
|
-
* - **Longer, more variable pauses.** Every measured touch interaction is
|
|
290
|
-
* slower than its mouse equivalent, and a phone's are more variable because
|
|
291
|
-
* the hand holding the device is also moving.
|
|
292
|
-
*/
|
|
137
|
+
/** A finger on glass: no hover, touch events only, slower and more variable pauses. */
|
|
293
138
|
export declare class MobileHumanizer extends BaseHumanizer {
|
|
294
|
-
readonly name
|
|
139
|
+
readonly name: HumanizationMode;
|
|
295
140
|
readonly hovers = false;
|
|
296
141
|
protected readonly pauses: PauseTable;
|
|
297
142
|
private backend;
|
|
@@ -305,37 +150,23 @@ export declare class MobileHumanizer extends BaseHumanizer {
|
|
|
305
150
|
transform?: TouchTransform;
|
|
306
151
|
frequency?: number;
|
|
307
152
|
});
|
|
153
|
+
/** A solve that ended mid-gesture leaves a pointer down in the session's input state; lift it before the next one. */
|
|
308
154
|
reset(page: Page): Promise<void>;
|
|
309
155
|
private touch;
|
|
310
156
|
move(page: Page, to: Point): Promise<void>;
|
|
311
157
|
press(page: Page): Promise<void>;
|
|
312
158
|
release(page: Page): Promise<void>;
|
|
313
|
-
/**
|
|
159
|
+
/** A tap whose contact patch wobbles a pixel while held; a motionless tap is a synthetic one. */
|
|
314
160
|
click(page: Page, to: Point): Promise<void>;
|
|
315
|
-
/**
|
|
316
|
-
* Into the field, at soft-keyboard pace.
|
|
317
|
-
*
|
|
318
|
-
* The mouse path clears with Control+A. There is no Control on a phone
|
|
319
|
-
* keyboard, so the box is cleared through the element instead — which also
|
|
320
|
-
* works on an Appium element, where `page.keyboard` does not exist.
|
|
321
|
-
*/
|
|
161
|
+
/** Clears through the element: there is no Control key on a phone and no `page.keyboard` on Appium. */
|
|
322
162
|
typeText(page: Page, field: PlaywrightElementHandle, text: string): Promise<boolean>;
|
|
323
163
|
}
|
|
324
164
|
/**
|
|
325
|
-
* No humanisation:
|
|
326
|
-
*
|
|
327
|
-
* One mousemove per gesture instead of sixty, no dwell, no jitter, and text goes
|
|
328
|
-
* in with a single `fill()`. Roughly an order of magnitude faster on a slider
|
|
329
|
-
* puzzle, and it will be detected by anything that scores pointer telemetry —
|
|
330
|
-
* which is the whole trade, stated plainly. For fixtures, for self-hosted
|
|
331
|
-
* targets, and for callers whose stack humanises somewhere else.
|
|
332
|
-
*
|
|
333
|
-
* Still moves the mouse and still presses and releases: the events are what make
|
|
334
|
-
* the widget respond at all, and a click dispatched with no preceding move fails
|
|
335
|
-
* on the vendors that require a hover state first.
|
|
165
|
+
* No humanisation: one move per gesture and a single fill. Fast, and detectable. It still moves before
|
|
166
|
+
* it presses, because a click with no preceding move fails on the vendors that require a hover state first.
|
|
336
167
|
*/
|
|
337
168
|
export declare class NullHumanizer extends BaseHumanizer {
|
|
338
|
-
readonly name
|
|
169
|
+
readonly name: HumanizationMode;
|
|
339
170
|
readonly hovers = false;
|
|
340
171
|
protected readonly pauses: PauseTable;
|
|
341
172
|
move(page: Page, to: Point): Promise<void>;
|
|
@@ -343,9 +174,7 @@ export declare class NullHumanizer extends BaseHumanizer {
|
|
|
343
174
|
release(page: Page): Promise<void>;
|
|
344
175
|
typeText(page: Page, field: PlaywrightElementHandle, text: string): Promise<boolean>;
|
|
345
176
|
}
|
|
346
|
-
export type HumanizationMode = 'mouse' | 'mobile' | 'none';
|
|
347
177
|
export declare const MODES: readonly HumanizationMode[];
|
|
348
|
-
/** The subset of `CaptchaKrakenConfig` this module reads. */
|
|
349
178
|
export interface HumanizerOptions {
|
|
350
179
|
humanization?: HumanizationMode;
|
|
351
180
|
humanizer?: Humanizer;
|
|
@@ -357,21 +186,8 @@ export interface HumanizerOptions {
|
|
|
357
186
|
};
|
|
358
187
|
}
|
|
359
188
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* 1. `config.humanizer` — a caller who handed us an OBJECT has already
|
|
365
|
-
* decided; there is nothing left to select.
|
|
366
|
-
* 2. `config.humanization` — an explicit mode set in code.
|
|
367
|
-
* 3. `CAPTCHA_HUMANIZATION` — for a caller who cannot edit the code.
|
|
368
|
-
* 4. 'mouse'.
|
|
369
|
-
*
|
|
370
|
-
* Note that the env var loses to code, which is the opposite of this package's
|
|
371
|
-
* model-identity settings. Deliberate: which mode is right is a property of the
|
|
372
|
-
* PAGE the caller is driving, and an env var flipping a desktop solve to touch
|
|
373
|
-
* dispatch would break every one of them silently. Pinning a model is a
|
|
374
|
-
* deployment decision; picking an input device is not.
|
|
189
|
+
* `config.humanizer`, else `config.humanization`, else CAPTCHA_HUMANIZATION, else mouse. The env var loses
|
|
190
|
+
* to code, the opposite of the model settings, on purpose: an env var flipping a desktop solve to touch
|
|
191
|
+
* dispatch would break every one of them silently.
|
|
375
192
|
*/
|
|
376
193
|
export declare function resolveHumanizer(config?: HumanizerOptions): Humanizer;
|
|
377
|
-
export {};
|