@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 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.type(selector, text)` | Wait + clear + type |
196
- | `utils.getText(selector)` | Get text content |
197
- | `utils.exists(selector, timeout?)` | Check element exists |
198
- | `utils.waitForElement(selector, timeout?)` | Wait for element |
199
- | `utils.waitForNavigation()` | Wait for page navigation |
200
- | `utils.screenshot(path?)` | Take screenshot |
201
- | `utils.sleep(ms)` | Delay (respects abort signal) |
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 puppeteer from 'puppeteer-core';
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: puppeteer.Browser;
525
- page: puppeteer.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: puppeteer.Browser;
599
- page: puppeteer.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 từ flow config — dùng để validate writeOutput key */
617
+ /** Output definitions from flow config — used to validate writeOutput keys */
610
618
  private readonly outputDefs;
611
- /** Set chứa các key hợp lệ build 1 lần từ outputDefs */
619
+ /** Valid output keys setbuilt 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
- click(target: string | ElementHandle, options?: {
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
- timeout?: number;
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
- getText(selector: string, frame?: Frame): Promise<string | null>;
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
- switchToPopup(matcher: string | RegExp, timeout?: number): Promise<puppeteer.Page | null>;
637
- switchToTabIndex(index: number): Promise<puppeteer.Page | null>;
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 (including the current one).
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) page — the page stored in context.
647
- * Typically used after switchToPopup() to return to the main tab.
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 toàn bộ output hiện tại (bao gồm cả giá trị từ lần chạy trước và giá trị mới ghi).
654
- * Dùng để debugxem giá trị output hiện tại.
1078
+ * Log all current output values (including values from previous runs and newly written values).
1079
+ * Useful for debuggingsee 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
- * Ghi kết quả tự do cho profile đang chạy.
660
- * Gửi qua kênh riêng (type: "profile_output") — không lẫn log.
661
- * Đồng thời log ra console/UI để flow dev dễ debug.
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
- * ⚠️ Key phải được định nghĩa trong config.output[] — nếu không sẽ throw Error.
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
- * value hợp lệ:
666
- * - string | number | boolean
667
- * - array tối đa 20 phần tử (primitive)
668
- * - object 1 cấp tối đa 10 entry (value phải là primitive)
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
- * Cập nhật lại một field trong profileInput của profile đang chạy.
673
- * key phải field đã được định nghĩa trong profileInput schema.
674
- * Kết quả được gửi về server để update AgentFlowConfig sau khi execution xong.
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;