@hira-core/sdk 1.0.6 → 1.0.8
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/README.md +32 -11
- package/dist/index.d.ts +471 -30
- package/dist/index.js +1349 -128
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -188,17 +188,22 @@ const utils = new BrowserUtils(context);
|
|
|
188
188
|
|
|
189
189
|
#### Navigation & Interaction
|
|
190
190
|
|
|
191
|
-
| Method | Description
|
|
192
|
-
| ------------------------------------------ |
|
|
193
|
-
| `utils.goto(url)` | Navigate to URL
|
|
194
|
-
| `utils.click(selector)` | Wait + scroll + click
|
|
195
|
-
| `utils.
|
|
196
|
-
| `utils.
|
|
197
|
-
| `utils.
|
|
198
|
-
| `utils.
|
|
199
|
-
| `utils.
|
|
200
|
-
| `utils.
|
|
201
|
-
| `utils.
|
|
191
|
+
| Method | Description |
|
|
192
|
+
| ------------------------------------------ | -------------------------------------- |
|
|
193
|
+
| `utils.goto(url)` | Navigate to URL |
|
|
194
|
+
| `utils.click(selector)` | Wait + scroll + click |
|
|
195
|
+
| `utils.click({ x, y })` | Click at specific coordinates |
|
|
196
|
+
| `utils.type(selector, text)` | Wait + clear + type |
|
|
197
|
+
| `utils.select(selector, value)` | Select dropdown option (native `<select>`) |
|
|
198
|
+
| `utils.getText(selector)` | Get text content |
|
|
199
|
+
| `utils.getPosition(selector)` | Get element center coordinates |
|
|
200
|
+
| `utils.exists(selector, timeout?)` | Check element exists |
|
|
201
|
+
| `utils.waitForElement(selector, timeout?)` | Wait for element |
|
|
202
|
+
| `utils.waitForNavigation()` | Wait for page navigation |
|
|
203
|
+
| `utils.screenshot(path?)` | Take screenshot |
|
|
204
|
+
| `utils.sleep(ms)` | Delay (respects abort signal) |
|
|
205
|
+
| `utils.scroll({ deltaY })` | Smooth 60fps scroll (ease-in-out) |
|
|
206
|
+
| `utils.scroll({ deltaY, container })` | Smooth scroll inside overflow container|
|
|
202
207
|
|
|
203
208
|
#### Tab Management
|
|
204
209
|
|
|
@@ -344,6 +349,22 @@ npx @hira-core/cli build
|
|
|
344
349
|
|
|
345
350
|
---
|
|
346
351
|
|
|
352
|
+
## Virtual Cursor
|
|
353
|
+
|
|
354
|
+
The SDK includes a **virtual cursor** — a visible SVG cursor overlay that shows mouse movement, clicks, and scrolling in real-time. This is enabled by default and can be toggled via `IExecutionConfig.virtualCursor`:
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
// In flow runner params
|
|
358
|
+
execution: {
|
|
359
|
+
virtualCursor: true, // default — show cursor overlay
|
|
360
|
+
// virtualCursor: false, // disable cursor overlay
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
When enabled, `BrowserUtils.click()`, `scroll()`, and other interaction methods will show realistic Bézier curve mouse movement powered by [ghost-cursor](https://github.com/nicr9/ghost-cursor).
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
347
368
|
## License
|
|
348
369
|
|
|
349
370
|
ISC
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _packages_shared from '@packages/shared';
|
|
2
2
|
import { ProfileOutputValue, IWorkerLogMessage, ProfileStatus, IWorkerOutputMessage } from '@packages/shared';
|
|
3
|
-
import * as
|
|
3
|
+
import * as puppeteer_core from 'puppeteer-core';
|
|
4
4
|
import { Browser, Page, Frame, ElementHandle } from 'puppeteer-core';
|
|
5
5
|
import { EventEmitter } from 'events';
|
|
6
6
|
|
|
@@ -237,6 +237,12 @@ interface IExecutionConfig {
|
|
|
237
237
|
* Dev mode: dùng constructor `super(AntidetectProvider.GPM, ...)` trong flow class.
|
|
238
238
|
*/
|
|
239
239
|
antidetectProvider?: 'gpm' | 'hidemium' | 'genlogin' | 'adspower';
|
|
240
|
+
/**
|
|
241
|
+
* Enable virtual cursor — SVG arrow with Bézier curve mouse movement.
|
|
242
|
+
* When true, click() and type() will move cursor naturally before interacting.
|
|
243
|
+
* Default: true
|
|
244
|
+
*/
|
|
245
|
+
virtualCursor?: boolean;
|
|
240
246
|
}
|
|
241
247
|
interface IBrowserWindowConfig {
|
|
242
248
|
width: number;
|
|
@@ -314,6 +320,8 @@ interface IScriptContext<TConfig extends IFlowConfig = IFlowConfig> {
|
|
|
314
320
|
page: Page;
|
|
315
321
|
profile: IAntidetectProfile;
|
|
316
322
|
index: number;
|
|
323
|
+
/** Execution config — includes virtualCursor flag etc. */
|
|
324
|
+
execution: IExecutionConfig;
|
|
317
325
|
globalInput: InferGlobalInput<TConfig>;
|
|
318
326
|
profileInput: InferProfileInput<TConfig>;
|
|
319
327
|
/**
|
|
@@ -521,8 +529,8 @@ declare class GpmStandaloneAdapter implements IBrowserAdapter {
|
|
|
521
529
|
constructor(logger: ILogger);
|
|
522
530
|
private getBoundLogger;
|
|
523
531
|
open(profileName: string, index: number, windowConfig: IBrowserWindowConfig): Promise<{
|
|
524
|
-
browser:
|
|
525
|
-
page:
|
|
532
|
+
browser: puppeteer_core.Browser;
|
|
533
|
+
page: puppeteer_core.Page;
|
|
526
534
|
profile: IAntidetectProfile;
|
|
527
535
|
}>;
|
|
528
536
|
close(profileId: string): Promise<void>;
|
|
@@ -595,8 +603,8 @@ declare class HidemiumStandaloneAdapter implements IBrowserAdapter {
|
|
|
595
603
|
constructor(logger: ILogger);
|
|
596
604
|
private getBoundLogger;
|
|
597
605
|
open(profileName: string, index: number, windowConfig: IBrowserWindowConfig): Promise<{
|
|
598
|
-
browser:
|
|
599
|
-
page:
|
|
606
|
+
browser: puppeteer_core.Browser;
|
|
607
|
+
page: puppeteer_core.Page;
|
|
600
608
|
profile: IAntidetectProfile;
|
|
601
609
|
}>;
|
|
602
610
|
close(profileId: string): Promise<void>;
|
|
@@ -606,72 +614,505 @@ declare class HidemiumStandaloneAdapter implements IBrowserAdapter {
|
|
|
606
614
|
declare class BrowserUtils<TConfig extends IFlowConfig = IFlowConfig> {
|
|
607
615
|
private ctx;
|
|
608
616
|
private logger;
|
|
609
|
-
/** Output definitions
|
|
617
|
+
/** Output definitions from flow config — used to validate writeOutput keys */
|
|
610
618
|
private readonly outputDefs;
|
|
611
|
-
/**
|
|
619
|
+
/** Valid output keys set — built once from outputDefs */
|
|
612
620
|
private readonly validOutputKeys;
|
|
621
|
+
/** The initial page when flow starts — activeDefault() returns here */
|
|
622
|
+
private readonly defaultPage;
|
|
623
|
+
/** The currently active page all methods operate on — changed via activeTab() */
|
|
624
|
+
private activePage;
|
|
625
|
+
/** Currently active iframe — null means main frame. Changed via activeIframe() */
|
|
626
|
+
private activeFrame;
|
|
627
|
+
/** Virtual cursor — Bézier movement + SVG visualization */
|
|
628
|
+
private readonly hiraCursor;
|
|
613
629
|
constructor(context: IScriptContext<TConfig>);
|
|
630
|
+
/**
|
|
631
|
+
* CDP trick — Chromium thinks tab is always focused, not throttled
|
|
632
|
+
* when user switches to another tab or clicks elsewhere.
|
|
633
|
+
*/
|
|
634
|
+
private enableFocusEmulation;
|
|
635
|
+
/**
|
|
636
|
+
* Apply stealth scripts to remove automation fingerprints.
|
|
637
|
+
* Uses evaluateOnNewDocument — runs BEFORE any page scripts on every navigation.
|
|
638
|
+
* Persists across navigations on the same page instance.
|
|
639
|
+
*/
|
|
640
|
+
private applyStealthScripts;
|
|
614
641
|
private checkAbort;
|
|
642
|
+
/**
|
|
643
|
+
* Scroll element vào viewport mượt mà — segments + delay.
|
|
644
|
+
* Chỉ scroll nếu element nằm ngoài viewport.
|
|
645
|
+
*/
|
|
646
|
+
private smoothScrollToElement;
|
|
647
|
+
/**
|
|
648
|
+
* Pause execution for the given duration.
|
|
649
|
+
*
|
|
650
|
+
* @param ms - Duration in milliseconds
|
|
651
|
+
* @example await utils.sleep(2000); // wait 2 seconds
|
|
652
|
+
*/
|
|
615
653
|
sleep(ms: number): Promise<void>;
|
|
654
|
+
/**
|
|
655
|
+
* Wait for an element to appear and become visible in the DOM.
|
|
656
|
+
* Returns null if not found (soft fail — does NOT throw).
|
|
657
|
+
* Supports CSS selectors and XPath (auto-detected by `//` or `(` prefix).
|
|
658
|
+
*
|
|
659
|
+
* @param selector - CSS selector or XPath expression
|
|
660
|
+
* @param timeout - Max wait time in ms (default: 8000)
|
|
661
|
+
* @param scope - Optional Frame to search within
|
|
662
|
+
* @returns The element handle, or null if not found
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* const el = await utils.waitForElement("#my-btn");
|
|
666
|
+
* if (el) await el.click();
|
|
667
|
+
*/
|
|
616
668
|
waitForElement(selector: string, timeout?: number, scope?: Frame): Promise<ElementHandle | null>;
|
|
617
|
-
|
|
669
|
+
/**
|
|
670
|
+
* Resolve an element: if waitTimeout > 0, wait for it; otherwise query directly with $().
|
|
671
|
+
*/
|
|
672
|
+
private resolveElement;
|
|
673
|
+
/**
|
|
674
|
+
* Click on an element or at specific coordinates.
|
|
675
|
+
* Scrolls the element into view before clicking.
|
|
676
|
+
* Throws if the element is not found.
|
|
677
|
+
*
|
|
678
|
+
* @param target - CSS selector, XPath, ElementHandle, or `{ x, y }` coordinates
|
|
679
|
+
* @param options.delay - Delay in ms before clicking (default: 1000)
|
|
680
|
+
* @param options.waitTimeout - Max wait time for element to appear (default: 2000)
|
|
681
|
+
* @param options.frame - Optional Frame to search within
|
|
682
|
+
* @returns true on success
|
|
683
|
+
*
|
|
684
|
+
* @example
|
|
685
|
+
* await utils.click("#submit-btn");
|
|
686
|
+
* await utils.click("#btn", { delay: 0 }); // click immediately
|
|
687
|
+
* await utils.click({ x: 500, y: 300 }); // click at coordinates
|
|
688
|
+
* const pos = await utils.getPosition("#btn", { randomXY: true });
|
|
689
|
+
* await utils.click(pos!); // click random point inside element
|
|
690
|
+
*/
|
|
691
|
+
click(target: string | ElementHandle | {
|
|
692
|
+
x: number;
|
|
693
|
+
y: number;
|
|
694
|
+
}, options?: {
|
|
618
695
|
delay?: number;
|
|
619
|
-
|
|
696
|
+
waitTimeout?: number;
|
|
620
697
|
frame?: Frame;
|
|
621
698
|
}): Promise<boolean>;
|
|
699
|
+
/**
|
|
700
|
+
* Get the position (x, y) of an element.
|
|
701
|
+
* Returns center point by default, or a random point within bounds with `randomXY`.
|
|
702
|
+
*
|
|
703
|
+
* @param selector - CSS selector or XPath
|
|
704
|
+
* @param options.randomXY - If true, returns random point within element (10% margin from edges)
|
|
705
|
+
* @param options.waitTimeout - Max wait time for element (default: 2000ms)
|
|
706
|
+
* @param options.frame - Optional Frame to search within
|
|
707
|
+
* @returns `{ x, y }` or null if element not found / no bounding box
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* const center = await utils.getPosition("#btn");
|
|
711
|
+
* const rand = await utils.getPosition("#btn", { randomXY: true });
|
|
712
|
+
* if (rand) await utils.click(rand);
|
|
713
|
+
*/
|
|
714
|
+
getPosition(selector: string, options?: {
|
|
715
|
+
randomXY?: boolean;
|
|
716
|
+
waitTimeout?: number;
|
|
717
|
+
frame?: Frame;
|
|
718
|
+
}): Promise<{
|
|
719
|
+
x: number;
|
|
720
|
+
y: number;
|
|
721
|
+
} | null>;
|
|
722
|
+
/**
|
|
723
|
+
* Select a value from a `<select>` dropdown.
|
|
724
|
+
* Human-like flow: cursor moves to select → click to open → page.select() → close.
|
|
725
|
+
*
|
|
726
|
+
* NOTE: Native `<option>` elements CAN NOT be clicked via Puppeteer
|
|
727
|
+
* ("Node is either not clickable or not an Element").
|
|
728
|
+
* `page.select()` is the ONLY reliable method.
|
|
729
|
+
*
|
|
730
|
+
* @param selector - CSS selector or XPath of the `<select>` element
|
|
731
|
+
* @param value - The `value` attribute of the option to select
|
|
732
|
+
* @param options.delay - Delay before clicking (default: 500ms)
|
|
733
|
+
* @param options.waitTimeout - Max wait for element (default: 2000ms)
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* await utils.select("#country", "vn");
|
|
737
|
+
*/
|
|
738
|
+
select(selector: string, value: string, options?: {
|
|
739
|
+
delay?: number;
|
|
740
|
+
waitTimeout?: number;
|
|
741
|
+
frame?: Frame;
|
|
742
|
+
}): Promise<boolean>;
|
|
743
|
+
/**
|
|
744
|
+
* Type text into an input element. Throws if the element is not found.
|
|
745
|
+
*
|
|
746
|
+
* @param selector - CSS selector or XPath of the input
|
|
747
|
+
* @param text - The text to type
|
|
748
|
+
* @param options.mode - Typing mode:
|
|
749
|
+
* - `"replace"` (default): Clear existing text, then type new text
|
|
750
|
+
* - `"append"`: Type without clearing — appends to existing text
|
|
751
|
+
* - `"paste"`: Set value directly via JS (fast, no keystroke simulation)
|
|
752
|
+
* @param options.delay - Delay between keystrokes in ms (default: 50). Ignored in paste mode.
|
|
753
|
+
* @param options.waitTimeout - Max wait time for element to appear in ms (default: 0 — instant)
|
|
754
|
+
* @param options.frame - Optional Frame to search within
|
|
755
|
+
* @returns true on success
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* await utils.type("#email", "user@example.com"); // replace mode
|
|
759
|
+
* await utils.type("#input", " more text", { mode: "append" }); // append
|
|
760
|
+
* await utils.type("#address", "0x1234...abcd", { mode: "paste" }); // instant paste
|
|
761
|
+
*/
|
|
622
762
|
type(selector: string, text: string, options?: {
|
|
763
|
+
/** Typing mode: replace (default) = clear then type, append = type without clearing, paste = set value directly */
|
|
764
|
+
mode?: "replace" | "append" | "paste";
|
|
623
765
|
delay?: number;
|
|
766
|
+
waitTimeout?: number;
|
|
624
767
|
frame?: Frame;
|
|
625
768
|
}): Promise<boolean>;
|
|
626
|
-
|
|
769
|
+
/**
|
|
770
|
+
* Get the text content of an element. Returns null if not found (soft fail).
|
|
771
|
+
*
|
|
772
|
+
* @param selector - CSS selector or XPath
|
|
773
|
+
* @param options.waitTimeout - Max wait time for element to appear in ms (default: 0 — instant)
|
|
774
|
+
* @param options.frame - Optional Frame to search within
|
|
775
|
+
* @returns Trimmed text content, or null if element not found
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* const price = await utils.getText(".price");
|
|
779
|
+
* const el = await utils.getText(".lazy-el", { waitTimeout: 8000 });
|
|
780
|
+
*/
|
|
781
|
+
getText(selector: string, options?: {
|
|
782
|
+
waitTimeout?: number;
|
|
783
|
+
frame?: Frame;
|
|
784
|
+
}): Promise<string | null>;
|
|
785
|
+
/**
|
|
786
|
+
* Check if an element exists and is visible on the page.
|
|
787
|
+
* Returns false if not found (soft fail — does NOT throw).
|
|
788
|
+
*
|
|
789
|
+
* @param selector - CSS selector or XPath
|
|
790
|
+
* @param timeout - Max wait time in ms (default: 4000)
|
|
791
|
+
* @param frame - Optional Frame to search within
|
|
792
|
+
* @returns true if element exists and is visible
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* if (await utils.exists("#popup-overlay")) {
|
|
796
|
+
* await utils.click("#close-popup");
|
|
797
|
+
* }
|
|
798
|
+
*/
|
|
627
799
|
exists(selector: string, timeout?: number, frame?: Frame): Promise<boolean>;
|
|
800
|
+
/**
|
|
801
|
+
* Navigate the active page to a URL. Waits until the page fully loads.
|
|
802
|
+
* Throws on navigation failure or timeout.
|
|
803
|
+
*
|
|
804
|
+
* @param url - The URL to navigate to
|
|
805
|
+
* @param options.waitUntil - When to consider navigation complete (default: "load")
|
|
806
|
+
* @returns true on success
|
|
807
|
+
*
|
|
808
|
+
* @example
|
|
809
|
+
* await utils.goto("https://example.com");
|
|
810
|
+
* await utils.goto("https://app.com", { waitUntil: "networkidle0" });
|
|
811
|
+
*/
|
|
628
812
|
goto(url: string, options?: {
|
|
629
813
|
waitUntil?: "load" | "domcontentloaded" | "networkidle0" | "networkidle2";
|
|
630
814
|
}): Promise<boolean>;
|
|
815
|
+
/**
|
|
816
|
+
* Scroll the page or a container by a specific amount.
|
|
817
|
+
* Uses CDP mouseWheel events (human-like, not JS scrollBy).
|
|
818
|
+
*
|
|
819
|
+
* @param direction - "up" or "down"
|
|
820
|
+
* @param amount - Pixels to scroll
|
|
821
|
+
* @param options.container - CSS selector of scroll container
|
|
822
|
+
* @param options.speed - Scroll speed 1-100 (default: 50)
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* await utils.scroll("down", 500);
|
|
826
|
+
* await utils.scroll("up", 200, { container: "#chat-messages" });
|
|
827
|
+
*/
|
|
828
|
+
scroll(direction: "up" | "down", amount: number, options?: {
|
|
829
|
+
container?: string;
|
|
830
|
+
speed?: number;
|
|
831
|
+
}): Promise<void>;
|
|
832
|
+
/**
|
|
833
|
+
* Scroll to the top or bottom of the page.
|
|
834
|
+
* Scrolls in segments with pauses — giống người lướt dần đến đích.
|
|
835
|
+
*
|
|
836
|
+
* @param position - "top" or "bottom"
|
|
837
|
+
* @param options.speed - Scroll speed 1-100 (default: 50)
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* await utils.scrollTo("bottom");
|
|
841
|
+
* await utils.scrollTo("top");
|
|
842
|
+
*/
|
|
843
|
+
scrollTo(position: "top" | "bottom", options?: {
|
|
844
|
+
speed?: number;
|
|
845
|
+
}): Promise<void>;
|
|
846
|
+
/**
|
|
847
|
+
* Scroll an element into the viewport.
|
|
848
|
+
* Scrolls in segments with pauses — không nhảy tới đích.
|
|
849
|
+
*
|
|
850
|
+
* @param selector - CSS selector or XPath of the element
|
|
851
|
+
* @param options.speed - Scroll speed 1-100 (default: 50)
|
|
852
|
+
* @returns true if element found and scrolled
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* await utils.scrollToElement("#footer");
|
|
856
|
+
* await utils.scrollToElement("//button[text()='Load more']");
|
|
857
|
+
*/
|
|
858
|
+
scrollToElement(selector: string, options?: {
|
|
859
|
+
speed?: number;
|
|
860
|
+
}): Promise<boolean>;
|
|
861
|
+
/**
|
|
862
|
+
* Simulate natural browsing scroll — cuộn xuống xen kẽ lướt ngược, delay random.
|
|
863
|
+
* Giống người đang đọc/lướt web tự nhiên.
|
|
864
|
+
*
|
|
865
|
+
* @param options.duration - Thời gian scroll tính bằng giây (default: 5)
|
|
866
|
+
* @param options.direction - Main direction (default: "down")
|
|
867
|
+
* @param options.backChance - Chance to scroll back 0-1 (default: 0.15)
|
|
868
|
+
* @param options.backAmount - [min, max] px to scroll back (default: [50, 150])
|
|
869
|
+
* @param options.stepSize - [min, max] px per step (default: [200, 400])
|
|
870
|
+
* @param options.stepDelay - [min, max] ms delay between steps (default: [300, 800])
|
|
871
|
+
* @param options.container - CSS selector of scroll container
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* await utils.randomScroll(); // 5s lướt xuống
|
|
875
|
+
* await utils.randomScroll({ duration: 10 }); // 10s
|
|
876
|
+
* await utils.randomScroll({ backChance: 0.3, container: "#feed" });
|
|
877
|
+
*/
|
|
878
|
+
randomScroll(options?: {
|
|
879
|
+
duration?: number;
|
|
880
|
+
direction?: "down" | "up";
|
|
881
|
+
backChance?: number;
|
|
882
|
+
backAmount?: [number, number];
|
|
883
|
+
stepSize?: [number, number];
|
|
884
|
+
stepDelay?: [number, number];
|
|
885
|
+
container?: string;
|
|
886
|
+
}): Promise<void>;
|
|
887
|
+
/**
|
|
888
|
+
* Wait for the current page to complete a navigation (e.g. after a form submit).
|
|
889
|
+
* Throws on timeout.
|
|
890
|
+
*
|
|
891
|
+
* @param options.timeout - Max wait time in ms (default: 60000)
|
|
892
|
+
* @param options.waitUntil - When to consider navigation complete (default: "load")
|
|
893
|
+
* @returns true on success
|
|
894
|
+
*
|
|
895
|
+
* @example
|
|
896
|
+
* await utils.click("#submit");
|
|
897
|
+
* await utils.waitForNavigation();
|
|
898
|
+
*/
|
|
631
899
|
waitForNavigation(options?: {
|
|
632
900
|
timeout?: number;
|
|
633
901
|
waitUntil?: "load" | "domcontentloaded" | "networkidle0" | "networkidle2";
|
|
634
902
|
}): Promise<boolean>;
|
|
903
|
+
/**
|
|
904
|
+
* Take a screenshot of the active page. Returns null on failure (soft fail).
|
|
905
|
+
*
|
|
906
|
+
* @param path - Optional file path to save the screenshot. If omitted, returns base64 string.
|
|
907
|
+
* @returns Screenshot buffer (if path given) or base64 string, or null on failure
|
|
908
|
+
*
|
|
909
|
+
* @example
|
|
910
|
+
* await utils.screenshot("./debug.png"); // save to file
|
|
911
|
+
* const base64 = await utils.screenshot(); // get base64
|
|
912
|
+
*/
|
|
635
913
|
screenshot(path?: string): Promise<unknown>;
|
|
636
|
-
|
|
637
|
-
|
|
914
|
+
/**
|
|
915
|
+
* Switch scope into an iframe within the current page.
|
|
916
|
+
* After switching, all methods (click, type, exists...) operate inside the iframe.
|
|
917
|
+
* Use `activeMainFrame()` to exit back to the main page.
|
|
918
|
+
* Throws if the iframe is not found.
|
|
919
|
+
*
|
|
920
|
+
* @param selector - CSS selector or XPath of the iframe element
|
|
921
|
+
* @param options.waitTimeout - Max wait time for iframe element to appear in ms (default: 0 — instant)
|
|
922
|
+
* @returns The Frame handle
|
|
923
|
+
*
|
|
924
|
+
* @example
|
|
925
|
+
* await utils.activeIframe("#my-iframe");
|
|
926
|
+
* await utils.click("#btn-inside-iframe");
|
|
927
|
+
* await utils.activeMainFrame();
|
|
928
|
+
*/
|
|
929
|
+
activeIframe(selector: string, options?: {
|
|
930
|
+
waitTimeout?: number;
|
|
931
|
+
}): Promise<Frame | null>;
|
|
932
|
+
/**
|
|
933
|
+
* Exit the current iframe and return to the main frame of the active page.
|
|
934
|
+
* After calling this, all methods operate on the main page (outside any iframe).
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* await utils.activeIframe("#my-iframe");
|
|
938
|
+
* await utils.click("#btn-in-iframe");
|
|
939
|
+
* await utils.activeMainFrame(); // back to main page
|
|
940
|
+
*/
|
|
941
|
+
activeMainFrame(): Promise<void>;
|
|
942
|
+
private _findNewTab;
|
|
943
|
+
private _findPopup;
|
|
944
|
+
/**
|
|
945
|
+
* Wait for a new tab to appear, but do NOT switch to it.
|
|
946
|
+
* The active page remains unchanged. Throws if no new tab appears before timeout.
|
|
947
|
+
*
|
|
948
|
+
* @param opts.matcher - String or RegExp to match the new tab's title or URL. If omitted, any new tab matches.
|
|
949
|
+
* @param opts.timeout - Max wait time in ms (default: 8000)
|
|
950
|
+
* @returns The new Page handle (without switching)
|
|
951
|
+
*
|
|
952
|
+
* @example
|
|
953
|
+
* await utils.click("#open-link");
|
|
954
|
+
* const page = await utils.waitForNewTab();
|
|
955
|
+
* const page = await utils.waitForNewTab({ timeout: 20000 });
|
|
956
|
+
* const page = await utils.waitForNewTab({ matcher: "Google" });
|
|
957
|
+
*/
|
|
958
|
+
waitForNewTab(opts?: {
|
|
959
|
+
matcher?: string | RegExp;
|
|
960
|
+
timeout?: number;
|
|
961
|
+
}): Promise<puppeteer_core.Page | null>;
|
|
962
|
+
/**
|
|
963
|
+
* Switch to a new tab immediately (or wait if timeout is specified).
|
|
964
|
+
* After calling this, all methods operate on the new tab.
|
|
965
|
+
* Use `activeDefault()` to return to the original tab.
|
|
966
|
+
*
|
|
967
|
+
* @param opts.matcher - String or RegExp to match the new tab's title or URL
|
|
968
|
+
* @param opts.timeout - Max wait time in ms (default: 0 — instant, throws if not found)
|
|
969
|
+
* @returns The new Page handle (now active)
|
|
970
|
+
*
|
|
971
|
+
* @example
|
|
972
|
+
* await utils.click("#open-link");
|
|
973
|
+
* await utils.activeNewTab(); // switch immediately
|
|
974
|
+
* await utils.activeNewTab({ timeout: 8000 }); // wait up to 8s
|
|
975
|
+
* await utils.type("#input", "hello"); // types on the new tab
|
|
976
|
+
* await utils.activeDefault(); // back to original tab
|
|
977
|
+
*/
|
|
978
|
+
activeNewTab(opts?: {
|
|
979
|
+
matcher?: string | RegExp;
|
|
980
|
+
timeout?: number;
|
|
981
|
+
}): Promise<puppeteer_core.Page | null>;
|
|
982
|
+
/**
|
|
983
|
+
* Wait for a popup/tab matching the given criteria to appear, but do NOT switch to it.
|
|
984
|
+
* Throws if no matching popup appears before timeout.
|
|
985
|
+
*
|
|
986
|
+
* @param opts.matcher - String or RegExp to match title or URL. If omitted, any new popup matches.
|
|
987
|
+
* @param opts.timeout - Max wait time in ms (default: 8000)
|
|
988
|
+
* @returns The popup Page handle (without switching)
|
|
989
|
+
*
|
|
990
|
+
* @example
|
|
991
|
+
* await utils.click("#connect-wallet");
|
|
992
|
+
* const popup = await utils.waitForPopup({ matcher: "MetaMask" });
|
|
993
|
+
*/
|
|
994
|
+
waitForPopup(opts?: {
|
|
995
|
+
matcher?: string | RegExp;
|
|
996
|
+
timeout?: number;
|
|
997
|
+
}): Promise<puppeteer_core.Page | null>;
|
|
998
|
+
/**
|
|
999
|
+
* Switch to a popup/tab immediately (or wait if timeout is specified).
|
|
1000
|
+
* After calling this, all methods operate on the popup.
|
|
1001
|
+
* Use `activeDefault()` to return to the original tab.
|
|
1002
|
+
*
|
|
1003
|
+
* @param opts.matcher - String or RegExp to match title or URL
|
|
1004
|
+
* @param opts.timeout - Max wait time in ms (default: 0 — instant, throws if not found)
|
|
1005
|
+
* @returns The popup Page handle (now active)
|
|
1006
|
+
*
|
|
1007
|
+
* @example
|
|
1008
|
+
* await utils.click("#connect-wallet");
|
|
1009
|
+
* await utils.activePopup({ matcher: "MetaMask" });
|
|
1010
|
+
* await utils.click("#approve"); // clicks on the popup
|
|
1011
|
+
* await utils.activeDefault(); // back to original tab
|
|
1012
|
+
*/
|
|
1013
|
+
activePopup(opts?: {
|
|
1014
|
+
matcher?: string | RegExp;
|
|
1015
|
+
timeout?: number;
|
|
1016
|
+
}): Promise<puppeteer_core.Page | null>;
|
|
1017
|
+
/**
|
|
1018
|
+
* Switch focus to a tab by its index (0-based, ordered by creation time).
|
|
1019
|
+
* All subsequent methods (click, type, goto...) will operate on this tab.
|
|
1020
|
+
* User interactions (opening tabs, clicking browser) do NOT affect the active tab.
|
|
1021
|
+
* Throws if the index is out of range.
|
|
1022
|
+
*
|
|
1023
|
+
* @param index - Zero-based tab index
|
|
1024
|
+
* @returns The Page handle of the activated tab
|
|
1025
|
+
*
|
|
1026
|
+
* @example
|
|
1027
|
+
* await utils.activeTab(1); // switch to second tab
|
|
1028
|
+
* await utils.click("#btn"); // clicks on tab 1
|
|
1029
|
+
* await utils.activeTab(0); // back to first tab
|
|
1030
|
+
*/
|
|
1031
|
+
activeTab(index: number): Promise<puppeteer_core.Page | null>;
|
|
1032
|
+
/**
|
|
1033
|
+
* Close the currently active tab and switch back to the default page.
|
|
1034
|
+
*
|
|
1035
|
+
* @example
|
|
1036
|
+
* await utils.activeTab(1);
|
|
1037
|
+
* await utils.closeCurrentTab(); // closes tab 1, returns to tab 0
|
|
1038
|
+
*/
|
|
638
1039
|
closeCurrentTab(): Promise<void>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Close all tabs except the currently active one.
|
|
1042
|
+
*
|
|
1043
|
+
* @example
|
|
1044
|
+
* await utils.closeOtherTabs(); // keeps only the active tab open
|
|
1045
|
+
*/
|
|
639
1046
|
closeOtherTabs(): Promise<void>;
|
|
640
1047
|
/**
|
|
641
|
-
* Close ALL tabs
|
|
642
|
-
* Useful for full cleanup before flow ends.
|
|
1048
|
+
* Close ALL tabs including the current one.
|
|
1049
|
+
* Useful for full cleanup before a flow ends.
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* await utils.closeAllTabs();
|
|
643
1053
|
*/
|
|
644
1054
|
closeAllTabs(): Promise<void>;
|
|
645
1055
|
/**
|
|
646
|
-
* Switch back to the default (initial)
|
|
647
|
-
*
|
|
1056
|
+
* Switch back to the default (initial) tab — the first tab opened when the flow started.
|
|
1057
|
+
* Resets both the active page and active frame (exits any iframe).
|
|
1058
|
+
* Typically used after `activePopup()` or `activeTab()` to return to the main tab.
|
|
1059
|
+
*
|
|
1060
|
+
* @returns The default Page handle
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* await utils.activePopup({ matcher: "MetaMask" });
|
|
1064
|
+
* await utils.click("#approve");
|
|
1065
|
+
* await utils.activeDefault(); // back to original tab
|
|
1066
|
+
*/
|
|
1067
|
+
activeDefault(): Promise<puppeteer_core.Page>;
|
|
1068
|
+
/**
|
|
1069
|
+
* Log a config object in a readable format.
|
|
1070
|
+
*
|
|
1071
|
+
* @param config - Key-value object to log
|
|
1072
|
+
* @param label - Label for the log entry (default: "Config")
|
|
648
1073
|
*/
|
|
649
|
-
switchToDefault(): Promise<puppeteer.Page>;
|
|
650
1074
|
logConfig(config: Record<string, unknown>, label?: string): Promise<void>;
|
|
1075
|
+
/** Log the current profile input values for debugging. */
|
|
651
1076
|
logProfileInput(): Promise<void>;
|
|
652
1077
|
/**
|
|
653
|
-
* Log
|
|
654
|
-
*
|
|
1078
|
+
* Log all current output values (including values from previous runs and newly written values).
|
|
1079
|
+
* Useful for debugging — see what outputs have been set.
|
|
655
1080
|
*/
|
|
656
1081
|
logProfileOutput(): Promise<void>;
|
|
1082
|
+
/** Log the current global input values for debugging. */
|
|
657
1083
|
logGlobalInput(): Promise<void>;
|
|
658
1084
|
/**
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
1085
|
+
* Write an output value for the current profile.
|
|
1086
|
+
* Dispatched via a dedicated channel (type: "profile_output") — separate from logs.
|
|
1087
|
+
* Also logs the value to console/UI for debugging.
|
|
1088
|
+
*
|
|
1089
|
+
* ⚠️ Key must be defined in `config.output[]` — throws Error if invalid.
|
|
662
1090
|
*
|
|
663
|
-
*
|
|
1091
|
+
* Accepted value types:
|
|
1092
|
+
* - `string | number | boolean`
|
|
1093
|
+
* - `Array` (max 20 elements, each must be primitive)
|
|
1094
|
+
* - `Object` (max 10 entries, values must be primitive)
|
|
664
1095
|
*
|
|
665
|
-
*
|
|
666
|
-
* -
|
|
667
|
-
*
|
|
668
|
-
*
|
|
1096
|
+
* @param key - Output key (must match config.output definition)
|
|
1097
|
+
* @param value - The value to write
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* await utils.writeOutput("status", "success");
|
|
1101
|
+
* await utils.writeOutput("balance", 1234.56);
|
|
1102
|
+
* await utils.writeOutput("tokens", ["ETH", "USDT"]);
|
|
669
1103
|
*/
|
|
670
1104
|
writeOutput(key: InferOutputKeys<TConfig>, value: ProfileOutputValue): Promise<void>;
|
|
671
1105
|
/**
|
|
672
|
-
*
|
|
673
|
-
* key
|
|
674
|
-
*
|
|
1106
|
+
* Update a profile input field for the currently running profile.
|
|
1107
|
+
* The key must be defined in the profileInput schema.
|
|
1108
|
+
* The updated value is sent to the server to persist in AgentFlowConfig after execution.
|
|
1109
|
+
*
|
|
1110
|
+
* @param key - Profile input key (must match schema definition)
|
|
1111
|
+
* @param value - The new value (string, number, or boolean)
|
|
1112
|
+
*
|
|
1113
|
+
* @example
|
|
1114
|
+
* await utils.writeProfileInput("lastLoginDate", "2024-01-15");
|
|
1115
|
+
* await utils.writeProfileInput("retryCount", 3);
|
|
675
1116
|
*/
|
|
676
1117
|
writeProfileInput(key: InferProfileInputKeys<TConfig>, value: string | number | boolean): Promise<void>;
|
|
677
1118
|
private sanitizeOutputValue;
|