mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
refactor(js): extract HumanActionOptions type, fix frame check/uncheck error handling, align SOCKS5 log level
- Extract HumanActionOptions type alias to replace ~40 inline copies - Frame check/uncheck: let isChecked errors propagate instead of silently clicking non-checkbox elements - SOCKS5 credential log: console.debug → console.info (parity with Python logger.info) - Add contributors to README
This commit is contained in:
@@ -1192,5 +1192,7 @@ Issues and PRs welcome. If something isn't working, [open an issue](https://gith
|
|||||||
- [@evelaa123](https://github.com/evelaa123) — humanize behavior, persistent contexts, Windows fix
|
- [@evelaa123](https://github.com/evelaa123) — humanize behavior, persistent contexts, Windows fix
|
||||||
- [@yahooguntu](https://github.com/yahooguntu) — persistent contexts
|
- [@yahooguntu](https://github.com/yahooguntu) — persistent contexts
|
||||||
- [@kitiho](https://github.com/kitiho) — null viewport fix
|
- [@kitiho](https://github.com/kitiho) — null viewport fix
|
||||||
- [@eofreternal](https://github.com/eofreternal) — humanConfig type fix
|
- [@eofreternal](https://github.com/eofreternal) — humanConfig type fix, humanized method option types
|
||||||
|
- [@manaskarra](https://github.com/manaskarra) — iframe scope fix for humanized frame actions
|
||||||
|
- [@Youhai020616](https://github.com/Youhai020616) — SOCKS5 credential encoding logging
|
||||||
- [@AlexTech314](https://github.com/AlexTech314) — AWS Lambda integration
|
- [@AlexTech314](https://github.com/AlexTech314) — AWS Lambda integration
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Browser, Page, Frame, CDPSession, ElementHandle, BrowserContext } from 'puppeteer-core';
|
import type { Browser, Page, Frame, CDPSession, ElementHandle, BrowserContext } from 'puppeteer-core';
|
||||||
import type { HumanConfig } from '../human/config.js';
|
import type { HumanConfig, HumanActionOptions } from '../human/config.js';
|
||||||
import { resolveConfig, mergeConfig, rand, randRange, sleep } from '../human/config.js';
|
import { resolveConfig, mergeConfig, rand, randRange, sleep } from '../human/config.js';
|
||||||
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from '../human/mouse.js';
|
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from '../human/mouse.js';
|
||||||
import { humanType } from './keyboard.js';
|
import { humanType } from './keyboard.js';
|
||||||
@@ -331,14 +331,12 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ==== click (with clickCount support for dblclick) ====
|
// ==== click (with clickCount support for dblclick) ====
|
||||||
const humanClickFn = async (selector: string, options?: Partial<HumanConfig> & ({
|
const humanClickFn = async (selector: string, options?: HumanActionOptions & {
|
||||||
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
||||||
clickCount?: number;
|
clickCount?: number;
|
||||||
count?: number;
|
count?: number;
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
}) => {
|
||||||
timeout?: number;
|
|
||||||
})) => {
|
|
||||||
await ensureCursorInit();
|
await ensureCursorInit();
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
@@ -366,7 +364,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ==== hover ====
|
// ==== hover ====
|
||||||
const humanHoverFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanHoverFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await ensureCursorInit();
|
await ensureCursorInit();
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
@@ -382,11 +380,9 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ==== type ====
|
// ==== type ====
|
||||||
const humanTypeFn = async (selector: string, text: string, options?: Partial<HumanConfig> & ({
|
const humanTypeFn = async (selector: string, text: string, options?: HumanActionOptions & {
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
}) => {
|
||||||
timeout?: number;
|
|
||||||
})) => {
|
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await sleep(randRange(callCfg.field_switch_delay));
|
await sleep(randRange(callCfg.field_switch_delay));
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
@@ -410,7 +406,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ==== tap ====
|
// ==== tap ====
|
||||||
const humanTapFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanTapFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -671,13 +667,12 @@ function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.click() ---
|
// --- el.click() ---
|
||||||
(el as any).click = async (options?: Partial<HumanConfig> & ({
|
(el as any).click = async (options?: HumanActionOptions & {
|
||||||
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
||||||
clickCount?: number;
|
clickCount?: number;
|
||||||
count?: number;
|
count?: number;
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
}) => {
|
||||||
})) => {
|
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElClick(options);
|
if (!info) return origElClick(options);
|
||||||
@@ -701,7 +696,7 @@ function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.type() ---
|
// --- el.type() ---
|
||||||
(el as any).type = async (text: string, options?: Partial<HumanConfig> & ({ delay?: number; human_config?: Partial<HumanConfig> })) => {
|
(el as any).type = async (text: string, options?: HumanActionOptions & { delay?: number }) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElType(text, options);
|
if (!info) return origElType(text, options);
|
||||||
@@ -718,7 +713,7 @@ function patchSingleElementHandle(
|
|||||||
// page.click(). Only patched when the underlying ElementHandle exposes
|
// page.click(). Only patched when the underlying ElementHandle exposes
|
||||||
// ``scrollIntoView`` (Puppeteer v22+).
|
// ``scrollIntoView`` (Puppeteer v22+).
|
||||||
if (origElScrollIntoView) {
|
if (origElScrollIntoView) {
|
||||||
(el as any).scrollIntoView = async (options?: Partial<HumanConfig> & { human_config?: Partial<HumanConfig> }) => {
|
(el as any).scrollIntoView = async (options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await (page as any)._ensureCursorInit();
|
await (page as any)._ensureCursorInit();
|
||||||
try {
|
try {
|
||||||
@@ -870,26 +865,22 @@ function patchSingleFrame(
|
|||||||
|
|
||||||
const origFrameSelect = frame.select.bind(frame);
|
const origFrameSelect = frame.select.bind(frame);
|
||||||
|
|
||||||
(frame as any).click = async (selector: string, options?: Partial<HumanConfig> & ({
|
(frame as any).click = async (selector: string, options?: HumanActionOptions & {
|
||||||
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
button?: 'left' | 'right' | 'middle' | 'back' | 'forward';
|
||||||
clickCount?: number;
|
clickCount?: number;
|
||||||
count?: number;
|
count?: number;
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
}) => {
|
||||||
timeout?: number;
|
|
||||||
})) => {
|
|
||||||
await (page as any).click(selector, options);
|
await (page as any).click(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).hover = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).hover = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await (page as any).hover(selector, options);
|
await (page as any).hover(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).type = async (selector: string, text: string, options?: Partial<HumanConfig> & ({
|
(frame as any).type = async (selector: string, text: string, options?: HumanActionOptions & {
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
}) => {
|
||||||
timeout?: number;
|
|
||||||
})) => {
|
|
||||||
await (page as any).type(selector, text, options);
|
await (page as any).type(selector, text, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -903,7 +894,7 @@ function patchSingleFrame(
|
|||||||
await (page as any).focus(selector);
|
await (page as any).focus(selector);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).tap = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).tap = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await (page as any).click(selector, options);
|
await (page as any).click(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ export interface HumanConfig {
|
|||||||
|
|
||||||
export type HumanPreset = 'default' | 'careful';
|
export type HumanPreset = 'default' | 'careful';
|
||||||
|
|
||||||
|
export type HumanActionOptions = Partial<HumanConfig> & {
|
||||||
|
timeout?: number;
|
||||||
|
human_config?: Partial<HumanConfig>;
|
||||||
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Default preset
|
// Default preset
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Page, Frame, ElementHandle, CDPSession } from 'playwright-core';
|
import type { Page, Frame, ElementHandle, CDPSession } from 'playwright-core';
|
||||||
import type { HumanConfig } from './config.js';
|
import type { HumanConfig, HumanActionOptions } from './config.js';
|
||||||
import { rand, randRange, sleep, mergeConfig } from './config.js';
|
import { rand, randRange, sleep, mergeConfig } from './config.js';
|
||||||
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from './mouse.js';
|
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from './mouse.js';
|
||||||
import { humanType } from './keyboard.js';
|
import { humanType } from './keyboard.js';
|
||||||
@@ -179,18 +179,16 @@ export function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.click() ---
|
// --- el.click() ---
|
||||||
(el as any).click = async (options?: Partial<HumanConfig> & ({
|
(el as any).click = async (options?: HumanActionOptions & {
|
||||||
button?: 'left' | 'right' | 'middle';
|
button?: 'left' | 'right' | 'middle';
|
||||||
clickCount?: number;
|
clickCount?: number;
|
||||||
delay?: number;
|
delay?: number;
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
human_config?: Partial<HumanConfig>;
|
|
||||||
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
||||||
noWaitAfter?: boolean;
|
noWaitAfter?: boolean;
|
||||||
position?: { x: number; y: number };
|
position?: { x: number; y: number };
|
||||||
timeout?: number;
|
|
||||||
trial?: boolean;
|
trial?: boolean;
|
||||||
})) => {
|
}) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElClick(options);
|
if (!info) return origElClick(options);
|
||||||
@@ -198,17 +196,15 @@ export function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.dblclick() ---
|
// --- el.dblclick() ---
|
||||||
(el as any).dblclick = async (options?: Partial<HumanConfig> & ({
|
(el as any).dblclick = async (options?: HumanActionOptions & {
|
||||||
button?: 'left' | 'right' | 'middle';
|
button?: 'left' | 'right' | 'middle';
|
||||||
delay?: number;
|
delay?: number;
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
human_config?: Partial<HumanConfig>;
|
|
||||||
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
||||||
noWaitAfter?: boolean;
|
noWaitAfter?: boolean;
|
||||||
position?: { x: number; y: number };
|
position?: { x: number; y: number };
|
||||||
timeout?: number;
|
|
||||||
trial?: boolean;
|
trial?: boolean;
|
||||||
})) => {
|
}) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElDblclick(options);
|
if (!info) return origElDblclick(options);
|
||||||
@@ -218,14 +214,12 @@ export function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.hover() ---
|
// --- el.hover() ---
|
||||||
(el as any).hover = async (options?: Partial<HumanConfig> & ({
|
(el as any).hover = async (options?: HumanActionOptions & {
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
human_config?: Partial<HumanConfig>;
|
|
||||||
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
modifiers?: Array<'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift'>;
|
||||||
position?: { x: number; y: number };
|
position?: { x: number; y: number };
|
||||||
timeout?: number;
|
|
||||||
trial?: boolean;
|
trial?: boolean;
|
||||||
})) => {
|
}) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElHover(options);
|
if (!info) return origElHover(options);
|
||||||
@@ -233,12 +227,10 @@ export function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.type() ---
|
// --- el.type() ---
|
||||||
(el as any).type = async (text: string, options?: Partial<HumanConfig> & ({
|
(el as any).type = async (text: string, options?: HumanActionOptions & {
|
||||||
delay?: number;
|
delay?: number;
|
||||||
human_config?: Partial<HumanConfig>;
|
|
||||||
noWaitAfter?: boolean;
|
noWaitAfter?: boolean;
|
||||||
timeout?: number;
|
}) => {
|
||||||
})) => {
|
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElType(text, options);
|
if (!info) return origElType(text, options);
|
||||||
@@ -250,12 +242,10 @@ export function patchSingleElementHandle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- el.fill() ---
|
// --- el.fill() ---
|
||||||
(el as any).fill = async (value: string, options?: Partial<HumanConfig> & ({
|
(el as any).fill = async (value: string, options?: HumanActionOptions & {
|
||||||
force?: boolean;
|
force?: boolean;
|
||||||
human_config?: Partial<HumanConfig>;
|
|
||||||
noWaitAfter?: boolean;
|
noWaitAfter?: boolean;
|
||||||
timeout?: number;
|
}) => {
|
||||||
})) => {
|
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const info = await moveToElement(callCfg);
|
const info = await moveToElement(callCfg);
|
||||||
if (!info) return origElFill(value, options);
|
if (!info) return origElFill(value, options);
|
||||||
@@ -374,7 +364,7 @@ export function patchSingleElementHandle(
|
|||||||
// wheel sequence used by page.click() etc. Falls back to the native
|
// wheel sequence used by page.click() etc. Falls back to the native
|
||||||
// method if the element is detached or scrolling fails.
|
// method if the element is detached or scrolling fails.
|
||||||
if (origElScrollIntoViewIfNeeded) {
|
if (origElScrollIntoViewIfNeeded) {
|
||||||
(el as any).scrollIntoViewIfNeeded = async (options?: Partial<HumanConfig> & ({ human_config?: Partial<HumanConfig>; timeout?: number })) => {
|
(el as any).scrollIntoViewIfNeeded = async (options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
const ensureCursorInit = (page as any)._ensureCursorInit;
|
const ensureCursorInit = (page as any)._ensureCursorInit;
|
||||||
if (ensureCursorInit) await ensureCursorInit();
|
if (ensureCursorInit) await ensureCursorInit();
|
||||||
|
|||||||
+32
-28
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Browser, BrowserContext, Page, Frame, CDPSession } from 'playwright-core';
|
import type { Browser, BrowserContext, Page, Frame, CDPSession } from 'playwright-core';
|
||||||
import { HumanConfig, resolveConfig, mergeConfig, rand, randRange, sleep } from './config.js';
|
import { HumanConfig, HumanActionOptions, resolveConfig, mergeConfig, rand, randRange, sleep } from './config.js';
|
||||||
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from './mouse.js';
|
import { RawMouse, RawKeyboard, humanMove, humanClick, clickTarget, humanIdle } from './mouse.js';
|
||||||
import { humanType } from './keyboard.js';
|
import { humanType } from './keyboard.js';
|
||||||
import { scrollToElement, humanScrollIntoView } from './scroll.js';
|
import { scrollToElement, humanScrollIntoView } from './scroll.js';
|
||||||
@@ -307,7 +307,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- click ---
|
// --- click ---
|
||||||
const humanClickFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanClickFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await ensureCursorInit();
|
await ensureCursorInit();
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
@@ -325,7 +325,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- dblclick ---
|
// --- dblclick ---
|
||||||
const humanDblclickFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanDblclickFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await ensureCursorInit();
|
await ensureCursorInit();
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
@@ -346,7 +346,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- hover ---
|
// --- hover ---
|
||||||
const humanHoverFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanHoverFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await ensureCursorInit();
|
await ensureCursorInit();
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
@@ -362,7 +362,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- type ---
|
// --- type ---
|
||||||
const humanTypeFn = async (selector: string, text: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanTypeFn = async (selector: string, text: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await sleep(randRange(callCfg.field_switch_delay));
|
await sleep(randRange(callCfg.field_switch_delay));
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
@@ -372,7 +372,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- fill (clears existing content first) ---
|
// --- fill (clears existing content first) ---
|
||||||
const humanFillFn = async (selector: string, value: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanFillFn = async (selector: string, value: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await sleep(randRange(callCfg.field_switch_delay));
|
await sleep(randRange(callCfg.field_switch_delay));
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
@@ -386,7 +386,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- clear ---
|
// --- clear ---
|
||||||
const humanClearFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanClearFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
if (!await isSelectorFocused(stealth, page, selector)) {
|
if (!await isSelectorFocused(stealth, page, selector)) {
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
}
|
}
|
||||||
@@ -397,7 +397,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- check ---
|
// --- check ---
|
||||||
const humanCheckFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanCheckFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
||||||
@@ -409,7 +409,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- uncheck ---
|
// --- uncheck ---
|
||||||
const humanUncheckFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanUncheckFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
||||||
@@ -421,14 +421,14 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- selectOption ---
|
// --- selectOption ---
|
||||||
const humanSelectOptionFn = async (selector: string, values: any, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanSelectOptionFn = async (selector: string, values: any, options?: HumanActionOptions) => {
|
||||||
await humanHoverFn(selector, options);
|
await humanHoverFn(selector, options);
|
||||||
await sleep(rand(100, 300));
|
await sleep(rand(100, 300));
|
||||||
return originals.selectOption(selector, values, options);
|
return originals.selectOption(selector, values, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- press (checks focus first — avoids redundant mouse moves) ---
|
// --- press (checks focus first — avoids redundant mouse moves) ---
|
||||||
const humanPressFn = async (selector: string, key: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanPressFn = async (selector: string, key: string, options?: HumanActionOptions) => {
|
||||||
if (!await isSelectorFocused(stealth, page, selector)) {
|
if (!await isSelectorFocused(stealth, page, selector)) {
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
}
|
}
|
||||||
@@ -437,7 +437,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- pressSequentially ---
|
// --- pressSequentially ---
|
||||||
const humanPressSequentiallyFn = async (selector: string, text: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanPressSequentiallyFn = async (selector: string, text: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (!await isSelectorFocused(stealth, page, selector)) {
|
if (!await isSelectorFocused(stealth, page, selector)) {
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
@@ -448,7 +448,7 @@ function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- tap ---
|
// --- tap ---
|
||||||
const humanTapFn = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const humanTapFn = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await humanClickFn(selector, options);
|
await humanClickFn(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -593,7 +593,7 @@ function patchSingleFrame(
|
|||||||
const origFrameTap = (frame as any).tap?.bind(frame);
|
const origFrameTap = (frame as any).tap?.bind(frame);
|
||||||
const origFrameDragAndDrop = frame.dragAndDrop.bind(frame);
|
const origFrameDragAndDrop = frame.dragAndDrop.bind(frame);
|
||||||
|
|
||||||
const moveToFrameSelector = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> }), inputBias = false) => {
|
const moveToFrameSelector = async (selector: string, options?: HumanActionOptions, inputBias = false) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (callCfg.idle_between_actions) {
|
if (callCfg.idle_between_actions) {
|
||||||
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
||||||
@@ -614,7 +614,7 @@ function patchSingleFrame(
|
|||||||
return { callCfg, isInput };
|
return { callCfg, isInput };
|
||||||
};
|
};
|
||||||
|
|
||||||
const frameClick = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const frameClick = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const moved = await moveToFrameSelector(selector, options);
|
const moved = await moveToFrameSelector(selector, options);
|
||||||
if (!moved) return origFrameClick(selector, options);
|
if (!moved) return origFrameClick(selector, options);
|
||||||
await humanClick(raw, moved.isInput, moved.callCfg);
|
await humanClick(raw, moved.isInput, moved.callCfg);
|
||||||
@@ -622,14 +622,14 @@ function patchSingleFrame(
|
|||||||
|
|
||||||
const getFrameCdp = async () => stealth.getCdpSession().catch(() => null);
|
const getFrameCdp = async () => stealth.getCdpSession().catch(() => null);
|
||||||
|
|
||||||
const frameHover = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
const frameHover = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const moved = await moveToFrameSelector(selector, options, false);
|
const moved = await moveToFrameSelector(selector, options, false);
|
||||||
if (!moved) return origFrameHover(selector, options);
|
if (!moved) return origFrameHover(selector, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).click = frameClick;
|
(frame as any).click = frameClick;
|
||||||
|
|
||||||
(frame as any).dblclick = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).dblclick = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const moved = await moveToFrameSelector(selector, options);
|
const moved = await moveToFrameSelector(selector, options);
|
||||||
if (!moved) return origFrameDblclick(selector, options);
|
if (!moved) return origFrameDblclick(selector, options);
|
||||||
await raw.down({ clickCount: 2 });
|
await raw.down({ clickCount: 2 });
|
||||||
@@ -639,7 +639,7 @@ function patchSingleFrame(
|
|||||||
|
|
||||||
(frame as any).hover = frameHover;
|
(frame as any).hover = frameHover;
|
||||||
|
|
||||||
(frame as any).type = async (selector: string, text: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).type = async (selector: string, text: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await sleep(randRange(callCfg.field_switch_delay));
|
await sleep(randRange(callCfg.field_switch_delay));
|
||||||
await frameClick(selector, options);
|
await frameClick(selector, options);
|
||||||
@@ -648,7 +648,7 @@ function patchSingleFrame(
|
|||||||
await humanType(page, rawKb, text, callCfg, cdp).catch(() => origFrameType(selector, text, options));
|
await humanType(page, rawKb, text, callCfg, cdp).catch(() => origFrameType(selector, text, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).fill = async (selector: string, value: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).fill = async (selector: string, value: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
await sleep(randRange(callCfg.field_switch_delay));
|
await sleep(randRange(callCfg.field_switch_delay));
|
||||||
await frameClick(selector, options);
|
await frameClick(selector, options);
|
||||||
@@ -661,23 +661,27 @@ function patchSingleFrame(
|
|||||||
await humanType(page, rawKb, value, callCfg, cdp).catch(() => origFrameFill(selector, value, options));
|
await humanType(page, rawKb, value, callCfg, cdp).catch(() => origFrameFill(selector, value, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).check = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).check = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const checked = await firstFrameLocator(frame, selector).isChecked?.().catch(() => false) ?? false;
|
const locator = firstFrameLocator(frame, selector);
|
||||||
|
if (typeof locator.isChecked !== 'function') return origFrameCheck(selector, options);
|
||||||
|
const checked = await locator.isChecked();
|
||||||
if (!checked) await frameClick(selector, options).catch(() => origFrameCheck(selector, options));
|
if (!checked) await frameClick(selector, options).catch(() => origFrameCheck(selector, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).uncheck = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).uncheck = async (selector: string, options?: HumanActionOptions) => {
|
||||||
const checked = await firstFrameLocator(frame, selector).isChecked?.().catch(() => true) ?? true;
|
const locator = firstFrameLocator(frame, selector);
|
||||||
|
if (typeof locator.isChecked !== 'function') return origFrameUncheck(selector, options);
|
||||||
|
const checked = await locator.isChecked();
|
||||||
if (checked) await frameClick(selector, options).catch(() => origFrameUncheck(selector, options));
|
if (checked) await frameClick(selector, options).catch(() => origFrameUncheck(selector, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).selectOption = async (selector: string, values: any, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).selectOption = async (selector: string, values: any, options?: HumanActionOptions) => {
|
||||||
await frameHover(selector, options);
|
await frameHover(selector, options);
|
||||||
await sleep(rand(100, 300));
|
await sleep(rand(100, 300));
|
||||||
return origFrameSelectOption(selector, values, options);
|
return origFrameSelectOption(selector, values, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).press = async (selector: string, key: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).press = async (selector: string, key: string, options?: HumanActionOptions) => {
|
||||||
if (!await isFrameSelectorFocused(frame, selector)) {
|
if (!await isFrameSelectorFocused(frame, selector)) {
|
||||||
await frameClick(selector, options);
|
await frameClick(selector, options);
|
||||||
}
|
}
|
||||||
@@ -685,7 +689,7 @@ function patchSingleFrame(
|
|||||||
await originals.keyboardPress(key);
|
await originals.keyboardPress(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).pressSequentially = async (selector: string, text: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).pressSequentially = async (selector: string, text: string, options?: HumanActionOptions) => {
|
||||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||||
if (!await isFrameSelectorFocused(frame, selector)) {
|
if (!await isFrameSelectorFocused(frame, selector)) {
|
||||||
await frameClick(selector, options);
|
await frameClick(selector, options);
|
||||||
@@ -695,11 +699,11 @@ function patchSingleFrame(
|
|||||||
await humanType(page, rawKb, text, callCfg, cdp).catch(() => origFramePressSequentially?.(selector, text, options));
|
await humanType(page, rawKb, text, callCfg, cdp).catch(() => origFramePressSequentially?.(selector, text, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).tap = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).tap = async (selector: string, options?: HumanActionOptions) => {
|
||||||
await frameClick(selector, options).catch(() => origFrameTap?.(selector, options));
|
await frameClick(selector, options).catch(() => origFrameTap?.(selector, options));
|
||||||
};
|
};
|
||||||
|
|
||||||
(frame as any).clear = async (selector: string, options?: Partial<HumanConfig> & ({ timeout?: number; human_config?: Partial<HumanConfig> })) => {
|
(frame as any).clear = async (selector: string, options?: HumanActionOptions) => {
|
||||||
if (!await isFrameSelectorFocused(frame, selector)) {
|
if (!await isFrameSelectorFocused(frame, selector)) {
|
||||||
await frameClick(selector, options);
|
await frameClick(selector, options);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -143,7 +143,7 @@ export function normalizeSocksStringUrl(urlStr: string): string {
|
|||||||
const credsChanged = encUser !== rawUserEnc
|
const credsChanged = encUser !== rawUserEnc
|
||||||
|| (hasPassword ? encPass !== rawPassEnc : false);
|
|| (hasPassword ? encPass !== rawPassEnc : false);
|
||||||
if (credsChanged) {
|
if (credsChanged) {
|
||||||
console.debug(
|
console.info(
|
||||||
"[cloakbrowser] Auto URL-encoded SOCKS5 proxy credentials (special " +
|
"[cloakbrowser] Auto URL-encoded SOCKS5 proxy credentials (special " +
|
||||||
"characters detected). Pre-encode the URL to suppress this notice.",
|
"characters detected). Pre-encode the URL to suppress this notice.",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -263,10 +263,10 @@ describe("resolveProxyConfig", () => {
|
|||||||
expect(proxyArgs).toEqual(["--proxy-server=socks5://user:a%40b%40c@host:1080"]);
|
expect(proxyArgs).toEqual(["--proxy-server=socks5://user:a%40b%40c@host:1080"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Visibility for #157: when wrapper actually rewrites the URL, surface a
|
// Visibility for #157: when wrapper actually rewrites the URL, surface an
|
||||||
// debug log so users debugging silent SOCKS5 fallback can see what happened.
|
// info log so users debugging silent SOCKS5 fallback can see what happened.
|
||||||
it("logs debug message when SOCKS5 credentials get re-encoded", () => {
|
it("logs info message when SOCKS5 credentials get re-encoded", () => {
|
||||||
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
const debugSpy = vi.spyOn(console, "info").mockImplementation(() => {});
|
||||||
try {
|
try {
|
||||||
resolveProxyConfig("socks5://user:pass=123@host:1080");
|
resolveProxyConfig("socks5://user:pass=123@host:1080");
|
||||||
expect(debugSpy).toHaveBeenCalledWith(
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
@@ -282,7 +282,7 @@ describe("resolveProxyConfig", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("stays silent when SOCKS5 URL is already encoded (no log spam)", () => {
|
it("stays silent when SOCKS5 URL is already encoded (no log spam)", () => {
|
||||||
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
const debugSpy = vi.spyOn(console, "info").mockImplementation(() => {});
|
||||||
try {
|
try {
|
||||||
resolveProxyConfig("socks5://user:pass%3D123@host:1080");
|
resolveProxyConfig("socks5://user:pass%3D123@host:1080");
|
||||||
const reencodedCalls = debugSpy.mock.calls
|
const reencodedCalls = debugSpy.mock.calls
|
||||||
@@ -295,7 +295,7 @@ describe("resolveProxyConfig", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("stays silent when SOCKS5 URL has no credentials", () => {
|
it("stays silent when SOCKS5 URL has no credentials", () => {
|
||||||
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
const debugSpy = vi.spyOn(console, "info").mockImplementation(() => {});
|
||||||
try {
|
try {
|
||||||
resolveProxyConfig("socks5://host:1080");
|
resolveProxyConfig("socks5://host:1080");
|
||||||
const reencodedCalls = debugSpy.mock.calls
|
const reencodedCalls = debugSpy.mock.calls
|
||||||
@@ -310,7 +310,7 @@ describe("resolveProxyConfig", () => {
|
|||||||
it("stays silent when only host case differs (no credential rewrite)", () => {
|
it("stays silent when only host case differs (no credential rewrite)", () => {
|
||||||
// Parity with Python: log condition must track credential changes, not
|
// Parity with Python: log condition must track credential changes, not
|
||||||
// cosmetic URL-string differences (regression for Copilot's PR #209 review).
|
// cosmetic URL-string differences (regression for Copilot's PR #209 review).
|
||||||
const debugSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
const debugSpy = vi.spyOn(console, "info").mockImplementation(() => {});
|
||||||
try {
|
try {
|
||||||
resolveProxyConfig("socks5://USER:pass@HOST.com:1080");
|
resolveProxyConfig("socks5://USER:pass@HOST.com:1080");
|
||||||
const reencodedCalls = debugSpy.mock.calls
|
const reencodedCalls = debugSpy.mock.calls
|
||||||
|
|||||||
Reference in New Issue
Block a user