@intuned/browser-dev 0.1.4-dev.1 → 0.1.5-dev.1

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.
Files changed (36) hide show
  1. package/README.md +0 -1
  2. package/dist/ai/export.d.ts +1 -1
  3. package/dist/ai/index.d.ts +1 -1
  4. package/dist/ai/isPageLoaded.js +14 -3
  5. package/dist/ai/tests/testIsPageLoaded.spec.js +3 -3
  6. package/dist/helpers/downloadFile.js +37 -0
  7. package/dist/helpers/export.d.ts +10 -7
  8. package/dist/helpers/frame_utils/constants.js +8 -0
  9. package/dist/helpers/frame_utils/findAllIframes.js +79 -0
  10. package/dist/helpers/frame_utils/getContainerFrame.js +22 -0
  11. package/dist/helpers/frame_utils/index.js +44 -0
  12. package/dist/helpers/frame_utils/tests/testFindAllIframes.spec.js +170 -0
  13. package/dist/helpers/gotoUrl.js +1 -1
  14. package/dist/helpers/index.d.ts +10 -7
  15. package/dist/helpers/index.js +0 -19
  16. package/dist/helpers/tests/testDownloadFile.spec.js +41 -6
  17. package/dist/helpers/tests/testInjectAttachmentType.spec.js +482 -0
  18. package/dist/helpers/tests/testValidateDataUsingSchema.spec.js +35 -31
  19. package/dist/helpers/tests/testWithDomSettledWait.spec.js +119 -0
  20. package/dist/helpers/types/Attachment.js +11 -6
  21. package/dist/helpers/types/index.js +1 -20
  22. package/dist/helpers/uploadFileToS3.js +2 -2
  23. package/dist/helpers/validateDataUsingSchema.js +30 -71
  24. package/dist/helpers/waitForDomSettled.js +57 -40
  25. package/dist/intunedServices/ApiGateway/tests/testApiGateway.spec.js +4 -4
  26. package/dist/optimized-extractors/listExtractionHelpers/__tests__/testArrayExtractorFromPage.spec.js +271 -2
  27. package/dist/optimized-extractors/listExtractionHelpers/runAiExtraction.js +55 -8
  28. package/generated-docs/ai/functions/extractStructuredData.mdx +5 -5
  29. package/generated-docs/ai/functions/isPageLoaded.mdx +1 -0
  30. package/generated-docs/helpers/functions/clickButtonAndWait.mdx +63 -0
  31. package/generated-docs/helpers/functions/clickUntilExhausted.mdx +112 -0
  32. package/generated-docs/helpers/functions/scrollToLoadContent.mdx +1 -7
  33. package/generated-docs/helpers/functions/validateDataUsingSchema.mdx +5 -5
  34. package/how-to-generate-docs.md +1 -0
  35. package/package.json +2 -2
  36. package/dist/helpers/types/CustomTypeRegistry.js +0 -48
package/README.md CHANGED
@@ -50,7 +50,6 @@ The Intuned Browser SDK provides a comprehensive set of tools for browser automa
50
50
 
51
51
  - **Schema Validation** - Validate data structures with `validateDataUsingSchema()`
52
52
  - **Empty Value Filtering** - Filter empty values with `filterEmptyValues()`
53
- - **Custom Type Registry** - Define custom validators with `CustomTypeRegistry`
54
53
 
55
54
  ### ⚡ Optimized Extractors
56
55
 
@@ -535,7 +535,7 @@ export type SUPPORTED_MODELS =
535
535
  * @param {Object} input - Input object containing the page to check
536
536
  * @param {Page} input.page - The Playwright page to check
537
537
  * @param {number} [input.timeoutInMs=10000] - Screenshot timeout in milliseconds. Defaults to 10000
538
- * @param {SUPPORTED_MODELS} [input.model="gpt-4o-2024-08-06"] - AI model to use for the check. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-4o-2024-08-06"
538
+ * @param {SUPPORTED_MODELS} [input.model="gpt-5-mini-2025-08-07"] - AI model to use for the check. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-5-mini-2025-08-07"
539
539
  * @param {string} [input.apiKey] - Optional API key for the AI service (if provided, will not be billed to your account)
540
540
  * @returns {Promise<boolean>} Promise resolving to true if page is loaded, false if still loading
541
541
  * @example
@@ -535,7 +535,7 @@ export type SUPPORTED_MODELS =
535
535
  * @param {Object} input - Input object containing the page to check
536
536
  * @param {Page} input.page - The Playwright page to check
537
537
  * @param {number} [input.timeoutInMs=10000] - Screenshot timeout in milliseconds. Defaults to 10000
538
- * @param {SUPPORTED_MODELS} [input.model="gpt-4o-2024-08-06"] - AI model to use for the check. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-4o-2024-08-06"
538
+ * @param {SUPPORTED_MODELS} [input.model="gpt-5-mini-2025-08-07"] - AI model to use for the check. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-5-mini-2025-08-07"
539
539
  * @param {string} [input.apiKey] - Optional API key for the AI service (if provided, will not be billed to your account)
540
540
  * @returns {Promise<boolean>} Promise resolving to true if page is loaded, false if still loading
541
541
  * @example
@@ -20,7 +20,7 @@ const isPageLoaded = async options => {
20
20
  });
21
21
  const gateway = _utils.GatewayFactory.createAIGateway({
22
22
  apiKey: options === null || options === void 0 ? void 0 : options.apiKey,
23
- model: (options === null || options === void 0 ? void 0 : options.model) ?? "gpt-4o-2024-08-06"
23
+ model: (options === null || options === void 0 ? void 0 : options.model) ?? "gpt-5-mini-2025-08-07"
24
24
  });
25
25
  const gatewayModel = await gateway.getModel();
26
26
  const base64Image = Buffer.from(screenshotBytes).toString("base64");
@@ -30,11 +30,22 @@ const isPageLoaded = async options => {
30
30
  role: "system",
31
31
  content: `You are a helpful assistant that determines if a webpage finished loading. If the page finished loading, start your answer with 'True'. If the page is loading, start your answer with 'False'. If you are not sure, start your answer with 'Dont know'. In a new line, add a reason to your response.
32
32
 
33
- Some good cues for determining if a page is loading:
33
+ ## Some good cues for determining if a page is loading (return 'False'):
34
34
  - Loading spinner
35
35
  - Page is blank
36
36
  - Some content looks like it's missing
37
- - Not on splash screen`
37
+ - Not on splash screen
38
+
39
+ ## Special cases for LOADED pages (return 'True')
40
+ - CAPTCHA challenges are considered loaded, because it is indeed loaded and waiting for the user to solve the captcha.
41
+ - Bot detection screens (e.g., "Checking your browser", Cloudflare verification) are considered loaded, because it is indeed loaded and waiting for the user to solve the captcha.
42
+ - Static error pages (404 Not Found, 403 Forbidden, 500 Internal Server Error, etc.)
43
+ - Login/authentication screens
44
+ - Complete forms ready for user input
45
+ - Fully rendered articles, product pages, or dashboards
46
+ - Cookie consent banners or popups over complete content
47
+ - Payment or checkout pages with all fields visible
48
+ `
38
49
  }, {
39
50
  role: "user",
40
51
  content: [{
@@ -175,7 +175,7 @@ const ERROR_PAGE = `
175
175
  </body>
176
176
  </html>
177
177
  `;
178
- (0, _extendedTest.describe)("isPageLoaded Tests", () => {
178
+ _extendedTest.describe.skip("isPageLoaded Tests", () => {
179
179
  let browser;
180
180
  let page;
181
181
  (0, _extendedTest.beforeAll)(async () => {
@@ -263,11 +263,11 @@ const ERROR_PAGE = `
263
263
  });
264
264
  });
265
265
  (0, _extendedTest.describe)("Different model types", () => {
266
- (0, _extendedTest.test)("should work with claude-3-5-sonnet-20240620", async () => {
266
+ (0, _extendedTest.test)("should work with claude-3-7-sonnet-latest", async () => {
267
267
  await page.setContent(FULLY_LOADED_PAGE);
268
268
  const result = await (0, _isPageLoaded.isPageLoaded)({
269
269
  page,
270
- model: "claude-3-5-sonnet-20240620",
270
+ model: "claude-3-7-sonnet-latest",
271
271
  apiKey: process.env.ANTHROPIC_API_KEY,
272
272
  timeoutInMs: 10000
273
273
  });
@@ -62,6 +62,7 @@ const downloadFile = async input => {
62
62
  downloadPromise = pageToDownloadFrom.waitForEvent("download", {
63
63
  timeout: (timeoutInMs ?? 5000) + 1000
64
64
  });
65
+ await page.evaluate("(() => {window.waitForPrintDialog = new Promise(f => window.print = f);})()");
65
66
  if (isUrlTrigger(trigger)) {
66
67
  absoluteUrl = await getAbsoluteUrl(page, trigger);
67
68
  if (!isValidURL(absoluteUrl)) {
@@ -92,8 +93,44 @@ const downloadFile = async input => {
92
93
  }
93
94
  } else if (isCallableTrigger(trigger)) {
94
95
  action = await trigger(page);
96
+ try {
97
+ await pageToDownloadFrom.waitForFunction("window.waitForPrintDialog", undefined, {
98
+ timeout: 1000
99
+ });
100
+ const pdf = await pageToDownloadFrom.pdf({
101
+ format: "A4"
102
+ });
103
+ const pdfBase64 = pdf.toString("base64");
104
+ await pageToDownloadFrom.evaluate(base64 => {
105
+ const dataUrl = `data:application/pdf;base64,${base64}`;
106
+ const link = document.createElement("a");
107
+ link.href = dataUrl;
108
+ link.download = "print.pdf";
109
+ document.body.appendChild(link);
110
+ link.click();
111
+ document.body.removeChild(link);
112
+ }, pdfBase64);
113
+ } catch (error) {}
95
114
  } else if (isLocatorTrigger(trigger)) {
96
115
  action = await trigger.click();
116
+ try {
117
+ await pageToDownloadFrom.waitForFunction("window.waitForPrintDialog", undefined, {
118
+ timeout: 1000
119
+ });
120
+ const pdf = await pageToDownloadFrom.pdf({
121
+ format: "A4"
122
+ });
123
+ const pdfBase64 = pdf.toString("base64");
124
+ await pageToDownloadFrom.evaluate(base64 => {
125
+ const dataUrl = `data:application/pdf;base64,${base64}`;
126
+ const link = document.createElement("a");
127
+ link.href = dataUrl;
128
+ link.download = "print.pdf";
129
+ document.body.appendChild(link);
130
+ link.click();
131
+ document.body.removeChild(link);
132
+ }, pdfBase64);
133
+ } catch (error) {}
97
134
  }
98
135
  const download = await downloadPromise;
99
136
  if ((0, _utils.isGenerateCodeMode)()) {
@@ -204,7 +204,7 @@ export declare function filterEmptyValues<T>(input: { data: T }): T;
204
204
  * @param {string} [input.waitForLoadState="load"] - When to consider navigation succeeded. Options: "load", "domcontentloaded", "networkidle", "commit". Defaults to "load"
205
205
  * @param {boolean} [input.throwOnTimeout=true] - Whether to throw an error if navigation times out. When false, the function returns without throwing, allowing continued execution. Defaults to true.
206
206
  * @param {boolean} [input.waitForLoadingStateUsingAi=false] - When true, uses AI vision to verify the page is fully loaded by checking for loading spinners, blank content, or incomplete states. Retries up to 4 times with 5-second delays. Defaults to false
207
- * @param {SUPPORTED_MODELS} [input.model="gpt-4o-2024-08-06"] - AI model to use for loading verification. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-4o-2024-08-06"
207
+ * @param {SUPPORTED_MODELS} [input.model="gpt-5-mini-2025-08-07"] - AI model to use for loading verification. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-5-mini-2025-08-07"
208
208
  * @param {string} [input.apiKey] - Optional API key for the AI service (if provided, will not be billed to your account)
209
209
  * @returns {Promise<void>} Promise that resolves when navigation completes successfully. If the operation fails and `throwOnTimeout` is false, resolves without error
210
210
  *
@@ -540,7 +540,7 @@ export declare function uploadFileToS3(input: {
540
540
  * @param {Object} input - The input object containing data and schema
541
541
  * @param {Record<string, any> | Record<string, any>[]} input.data - The data to validate. Can be a single data object or an array of data objects
542
542
  * @param {Record<string, any>} input.schema - JSON schema object defining validation rules
543
- * @returns {Promise<void>} Promise that resolves if validation passes, throws ValidationError if it fails
543
+ * @returns {void} Returns nothing if validation passes, throws ValidationError if it fails
544
544
  *
545
545
  * @example
546
546
  * ```typescript Basic User Data Validation
@@ -562,7 +562,7 @@ export declare function uploadFileToS3(input: {
562
562
  * }
563
563
  * };
564
564
  *
565
- * await validateDataUsingSchema({ data: userData, schema: userSchema });
565
+ * validateDataUsingSchema({ data: userData, schema: userSchema });
566
566
  * // Validation passes, no error thrown
567
567
  * }
568
568
  * ```
@@ -585,7 +585,7 @@ export declare function uploadFileToS3(input: {
585
585
  * }
586
586
  * };
587
587
  *
588
- * await validateDataUsingSchema({ data: userData, schema: userSchema });
588
+ * validateDataUsingSchema({ data: userData, schema: userSchema });
589
589
  * // Validation fails, throws ValidationError
590
590
  * }
591
591
  * ```
@@ -593,7 +593,7 @@ export declare function uploadFileToS3(input: {
593
593
  export declare function validateDataUsingSchema(input: {
594
594
  data: Record<string, any>[] | Record<string, any>;
595
595
  schema: Record<string, any>;
596
- }): Promise<void>;
596
+ }): void;
597
597
 
598
598
  /**
599
599
  * Executes a callback function and waits for network requests to settle before returning.
@@ -839,6 +839,9 @@ export interface Attachment {
839
839
  /** The name/key of the file in the S3 bucket */
840
840
  fileName: string;
841
841
 
842
+ /** The S3 object key/path */
843
+ key: string;
844
+
842
845
  /** The S3 bucket name where the file is stored */
843
846
  bucket: string;
844
847
 
@@ -846,13 +849,13 @@ export interface Attachment {
846
849
  region: string;
847
850
 
848
851
  /** Optional custom S3 endpoint URL. Defaults to undefined for standard AWS S3 */
849
- endpoint?: string;
852
+ endpoint?: string | null;
850
853
 
851
854
  /** A human-readable filename suggestion for downloads or display */
852
855
  suggestedFileName: string;
853
856
 
854
857
  /** The file type of the file */
855
- fileType?: AttachmentType;
858
+ fileType?: AttachmentType | null;
856
859
 
857
860
  /**
858
861
  * Returns a JSON-serializable record representation of the file.
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.IFRAME_TAGS = exports.ALL_IFRAMES_CSS_SELECTOR = void 0;
7
+ const IFRAME_TAGS = exports.IFRAME_TAGS = ["iframe", "frame"];
8
+ const ALL_IFRAMES_CSS_SELECTOR = exports.ALL_IFRAMES_CSS_SELECTOR = IFRAME_TAGS.join(", ");
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findAllIframes = findAllIframes;
7
+ exports.findAllIframesList = findAllIframesList;
8
+ var _Logger = require("../../common/Logger");
9
+ var _constants = require("./constants");
10
+ async function findAllIframes(root, iframeTimeoutMs = 10000) {
11
+ const processed = new Set();
12
+ return await processFrameRecursive(root, processed, iframeTimeoutMs);
13
+ }
14
+ async function findAllIframesList(root, iframeTimeoutMs = 10000) {
15
+ const iframeNodes = await findAllIframes(root, iframeTimeoutMs);
16
+ return flattenIframeTree(iframeNodes);
17
+ }
18
+ async function processFrameRecursive(root, processedRoots, iframeTimeoutMs) {
19
+ if (processedRoots.has(root)) {
20
+ return [];
21
+ }
22
+ processedRoots.add(root);
23
+ const iframeNodes = [];
24
+ try {
25
+ const iframeLocator = root.locator(_constants.ALL_IFRAMES_CSS_SELECTOR);
26
+ let iframeCount;
27
+ try {
28
+ iframeCount = await Promise.race([iframeLocator.count(), new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), iframeTimeoutMs))]);
29
+ } catch (error) {
30
+ _Logger.logger.error("Timeout counting iframes in context, skipping");
31
+ return [];
32
+ }
33
+ for (let i = 0; i < iframeCount; i++) {
34
+ try {
35
+ const processSingleIframe = async index => {
36
+ const iframeElementLocator = iframeLocator.nth(index);
37
+ const iframeElement = await iframeElementLocator.elementHandle();
38
+ if (!iframeElement) {
39
+ _Logger.logger.error(`Could not get element handle for iframe: ${iframeElement}`);
40
+ return null;
41
+ }
42
+ const contentFrame = await iframeElement.contentFrame();
43
+ if (!contentFrame) {
44
+ _Logger.logger.error(`Could not access content_frame for iframe: ${iframeElement}`);
45
+ return null;
46
+ }
47
+ const nestedIframes = await processFrameRecursive(contentFrame, processedRoots, iframeTimeoutMs);
48
+ return {
49
+ frame: contentFrame,
50
+ nestedIframes: nestedIframes
51
+ };
52
+ };
53
+ const iframeNode = await Promise.race([processSingleIframe(i), new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), iframeTimeoutMs))]);
54
+ if (iframeNode !== null) {
55
+ iframeNodes.push(iframeNode);
56
+ }
57
+ } catch (error) {
58
+ _Logger.logger.error(`Timeout processing iframe ${i} in context, skipping`);
59
+ continue;
60
+ }
61
+ }
62
+ } catch (error) {
63
+ _Logger.logger.error(`Error processing frames in context: ${error}`);
64
+ }
65
+ return iframeNodes;
66
+ }
67
+ function flattenIframeTree(iframeNodes) {
68
+ const flattened = [];
69
+ function flattenRecursive(nodes) {
70
+ for (const node of nodes) {
71
+ flattened.push(node);
72
+ if (node.nestedIframes && node.nestedIframes.length > 0) {
73
+ flattenRecursive(node.nestedIframes);
74
+ }
75
+ }
76
+ }
77
+ flattenRecursive(iframeNodes);
78
+ return flattened;
79
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getContainerFrame = getContainerFrame;
7
+ async function getContainerFrame(element) {
8
+ let handle;
9
+ if ("elementHandle" in element) {
10
+ handle = await element.elementHandle();
11
+ } else {
12
+ handle = element;
13
+ }
14
+ if (!handle) {
15
+ throw new Error("Could not get element handle");
16
+ }
17
+ const frame = await handle.ownerFrame();
18
+ if (!frame) {
19
+ throw new Error("Could not get owner frame for element");
20
+ }
21
+ return frame;
22
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "ALL_IFRAMES_CSS_SELECTOR", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _constants.ALL_IFRAMES_CSS_SELECTOR;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "IFRAME_TAGS", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _constants.IFRAME_TAGS;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "IframeNode", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _findAllIframes.IframeNode;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "findAllIframes", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _findAllIframes.findAllIframes;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "findAllIframesList", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _findAllIframes.findAllIframesList;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "getContainerFrame", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _getContainerFrame.getContainerFrame;
40
+ }
41
+ });
42
+ var _findAllIframes = require("./findAllIframes");
43
+ var _getContainerFrame = require("./getContainerFrame");
44
+ var _constants = require("./constants");
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+
3
+ var _extendedTest = require("../../../common/extendedTest");
4
+ var _playwrightCore = require("playwright-core");
5
+ var _findAllIframes = require("../findAllIframes");
6
+ (0, _extendedTest.describe)("Test findAllIframes", () => {
7
+ let browser;
8
+ let page;
9
+ (0, _extendedTest.beforeAll)(async () => {
10
+ browser = await _playwrightCore.chromium.launch({
11
+ headless: true
12
+ });
13
+ });
14
+ (0, _extendedTest.afterAll)(async () => {
15
+ await browser.close();
16
+ });
17
+ (0, _extendedTest.beforeEach)(async () => {
18
+ page = await browser.newPage();
19
+ });
20
+ (0, _extendedTest.afterEach)(async () => {
21
+ await page.close();
22
+ });
23
+ (0, _extendedTest.test)("should find all iframes - basic", async () => {
24
+ await page.goto(`data:text/html,
25
+ <html>
26
+ <body>
27
+ <h1>Main Content</h1>
28
+ <iframe id="iframe-1"
29
+ src="data:text/html,<html><body><h2>Iframe 1</h2></body></html>"
30
+ width="300"
31
+ height="200">
32
+ </iframe>
33
+ <iframe id="iframe-2"
34
+ src="data:text/html,<html><body><h2>Iframe 2</h2></body></html>"
35
+ width="300"
36
+ height="200">
37
+ </iframe>
38
+ </body>
39
+ </html>`, {
40
+ waitUntil: "domcontentloaded"
41
+ });
42
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page);
43
+ (0, _extendedTest.expect)(iframeNodes.length).toBe(2);
44
+ (0, _extendedTest.expect)(iframeNodes[0].frame).toBeDefined();
45
+ (0, _extendedTest.expect)(iframeNodes[1].frame).toBeDefined();
46
+ (0, _extendedTest.expect)(iframeNodes[0].nestedIframes.length).toBe(0);
47
+ (0, _extendedTest.expect)(iframeNodes[1].nestedIframes.length).toBe(0);
48
+ });
49
+ (0, _extendedTest.test)("should find nested iframes", async () => {
50
+ await page.goto(`data:text/html,
51
+ <html>
52
+ <body>
53
+ <h1>Main Content</h1>
54
+ <iframe id="outer-iframe"
55
+ src="data:text/html,<html><body><h2>Outer</h2><iframe src='data:text/html,<html><body><h3>Inner</h3></body></html>'></iframe></body></html>"
56
+ width="400"
57
+ height="300">
58
+ </iframe>
59
+ </body>
60
+ </html>`, {
61
+ waitUntil: "domcontentloaded"
62
+ });
63
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page);
64
+ (0, _extendedTest.expect)(iframeNodes.length).toBe(1);
65
+ (0, _extendedTest.expect)(iframeNodes[0].nestedIframes.length).toBe(1);
66
+ (0, _extendedTest.expect)(iframeNodes[0].nestedIframes[0].nestedIframes.length).toBe(0);
67
+ });
68
+ (0, _extendedTest.test)("should handle page with no iframes", async () => {
69
+ await page.goto(`data:text/html,
70
+ <html>
71
+ <body>
72
+ <h1>Main Content</h1>
73
+ <p>No iframes here</p>
74
+ </body>
75
+ </html>`, {
76
+ waitUntil: "domcontentloaded"
77
+ });
78
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page);
79
+ (0, _extendedTest.expect)(iframeNodes.length).toBe(0);
80
+ });
81
+ (0, _extendedTest.test)("should handle problematic iframe sources", async () => {
82
+ await page.goto(`data:text/html,
83
+ <html>
84
+ <body>
85
+ <h1>Main Content</h1>
86
+ <iframe id="javascript-iframe"
87
+ src="javascript:"
88
+ width="300"
89
+ height="200">
90
+ </iframe>
91
+ <iframe id="blob-iframe"
92
+ src="blob:null/invalid"
93
+ width="300"
94
+ height="200">
95
+ </iframe>
96
+ <iframe id="about-blank-iframe"
97
+ src="about:blank"
98
+ width="300"
99
+ height="200">
100
+ </iframe>
101
+ </body>
102
+ </html>`, {
103
+ waitUntil: "domcontentloaded",
104
+ timeout: 5000
105
+ });
106
+ const startTime = Date.now();
107
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page, 2000);
108
+ const elapsedTime = Date.now() - startTime;
109
+ (0, _extendedTest.expect)(elapsedTime).toBeLessThan(10000);
110
+ (0, _extendedTest.expect)(iframeNodes.length).toBeLessThan(3);
111
+ });
112
+ (0, _extendedTest.test)("should find iframes with srcdoc attribute", async () => {
113
+ await page.goto(`data:text/html,
114
+ <html>
115
+ <body>
116
+ <h1>Main Content</h1>
117
+ <iframe id="srcdoc-iframe"
118
+ srcdoc="<html><body><h2>Srcdoc Content</h2></body></html>"
119
+ width="300"
120
+ height="200">
121
+ </iframe>
122
+ </body>
123
+ </html>`, {
124
+ waitUntil: "domcontentloaded"
125
+ });
126
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page);
127
+ (0, _extendedTest.expect)(iframeNodes.length).toBe(1);
128
+ });
129
+ (0, _extendedTest.test)("should handle legacy frame elements", async () => {
130
+ await page.goto(`data:text/html,
131
+ <html>
132
+ <head><title>Legacy Frameset</title></head>
133
+ <frameset cols="50%,50%">
134
+ <frame id="frame-1"
135
+ src="data:text/html,<html><body><h2>Frame 1</h2></body></html>">
136
+ </frame>
137
+ <frame id="frame-2"
138
+ src="data:text/html,<html><body><h2>Frame 2</h2></body></html>">
139
+ </frame>
140
+ </frameset>
141
+ </html>`, {
142
+ waitUntil: "domcontentloaded"
143
+ });
144
+ const iframeNodes = await (0, _findAllIframes.findAllIframes)(page);
145
+ (0, _extendedTest.expect)(iframeNodes.length).toBeGreaterThanOrEqual(0);
146
+ for (const node of iframeNodes) {
147
+ (0, _extendedTest.expect)(node.frame).toBeDefined();
148
+ }
149
+ });
150
+ (0, _extendedTest.test)("findAllIframesList should return flat list", async () => {
151
+ await page.goto(`data:text/html,
152
+ <html>
153
+ <body>
154
+ <h1>Main Content</h1>
155
+ <iframe id="outer-iframe"
156
+ src="data:text/html,<html><body><h2>Outer</h2><iframe id='inner-iframe' src='data:text/html,<html><body><h3>Inner</h3></body></html>'></iframe></body></html>"
157
+ width="400"
158
+ height="300">
159
+ </iframe>
160
+ </body>
161
+ </html>`, {
162
+ waitUntil: "domcontentloaded"
163
+ });
164
+ const iframeList = await (0, _findAllIframes.findAllIframesList)(page);
165
+ (0, _extendedTest.expect)(iframeList.length).toBe(2);
166
+ for (const node of iframeList) {
167
+ (0, _extendedTest.expect)(node.frame).toBeDefined();
168
+ }
169
+ });
170
+ });
@@ -20,7 +20,7 @@ const goToUrl = async input => {
20
20
  throwOnTimeout = true,
21
21
  waitForLoadingStateUsingAi = false,
22
22
  retries = 3,
23
- model = "gpt-4o-2024-08-06",
23
+ model = "gpt-5-mini-2025-08-07",
24
24
  apiKey,
25
25
  waitForLoadState = "load"
26
26
  } = input || {};
@@ -204,7 +204,7 @@ export declare function filterEmptyValues<T>(input: { data: T }): T;
204
204
  * @param {string} [input.waitForLoadState="load"] - When to consider navigation succeeded. Options: "load", "domcontentloaded", "networkidle", "commit". Defaults to "load"
205
205
  * @param {boolean} [input.throwOnTimeout=true] - Whether to throw an error if navigation times out. When false, the function returns without throwing, allowing continued execution. Defaults to true.
206
206
  * @param {boolean} [input.waitForLoadingStateUsingAi=false] - When true, uses AI vision to verify the page is fully loaded by checking for loading spinners, blank content, or incomplete states. Retries up to 4 times with 5-second delays. Defaults to false
207
- * @param {SUPPORTED_MODELS} [input.model="gpt-4o-2024-08-06"] - AI model to use for loading verification. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-4o-2024-08-06"
207
+ * @param {SUPPORTED_MODELS} [input.model="gpt-5-mini-2025-08-07"] - AI model to use for loading verification. See [SUPPORTED_MODELS](../type-aliases/SUPPORTED_MODELS) for all supported models. Defaults to "gpt-5-mini-2025-08-07"
208
208
  * @param {string} [input.apiKey] - Optional API key for the AI service (if provided, will not be billed to your account)
209
209
  * @returns {Promise<void>} Promise that resolves when navigation completes successfully. If the operation fails and `throwOnTimeout` is false, resolves without error
210
210
  *
@@ -540,7 +540,7 @@ export declare function uploadFileToS3(input: {
540
540
  * @param {Object} input - The input object containing data and schema
541
541
  * @param {Record<string, any> | Record<string, any>[]} input.data - The data to validate. Can be a single data object or an array of data objects
542
542
  * @param {Record<string, any>} input.schema - JSON schema object defining validation rules
543
- * @returns {Promise<void>} Promise that resolves if validation passes, throws ValidationError if it fails
543
+ * @returns {void} Returns nothing if validation passes, throws ValidationError if it fails
544
544
  *
545
545
  * @example
546
546
  * ```typescript Basic User Data Validation
@@ -562,7 +562,7 @@ export declare function uploadFileToS3(input: {
562
562
  * }
563
563
  * };
564
564
  *
565
- * await validateDataUsingSchema({ data: userData, schema: userSchema });
565
+ * validateDataUsingSchema({ data: userData, schema: userSchema });
566
566
  * // Validation passes, no error thrown
567
567
  * }
568
568
  * ```
@@ -585,7 +585,7 @@ export declare function uploadFileToS3(input: {
585
585
  * }
586
586
  * };
587
587
  *
588
- * await validateDataUsingSchema({ data: userData, schema: userSchema });
588
+ * validateDataUsingSchema({ data: userData, schema: userSchema });
589
589
  * // Validation fails, throws ValidationError
590
590
  * }
591
591
  * ```
@@ -593,7 +593,7 @@ export declare function uploadFileToS3(input: {
593
593
  export declare function validateDataUsingSchema(input: {
594
594
  data: Record<string, any>[] | Record<string, any>;
595
595
  schema: Record<string, any>;
596
- }): Promise<void>;
596
+ }): void;
597
597
 
598
598
  /**
599
599
  * Executes a callback function and waits for network requests to settle before returning.
@@ -839,6 +839,9 @@ export interface Attachment {
839
839
  /** The name/key of the file in the S3 bucket */
840
840
  fileName: string;
841
841
 
842
+ /** The S3 object key/path */
843
+ key: string;
844
+
842
845
  /** The S3 bucket name where the file is stored */
843
846
  bucket: string;
844
847
 
@@ -846,13 +849,13 @@ export interface Attachment {
846
849
  region: string;
847
850
 
848
851
  /** Optional custom S3 endpoint URL. Defaults to undefined for standard AWS S3 */
849
- endpoint?: string;
852
+ endpoint?: string | null;
850
853
 
851
854
  /** A human-readable filename suggestion for downloads or display */
852
855
  suggestedFileName: string;
853
856
 
854
857
  /** The file type of the file */
855
- fileType?: AttachmentType;
858
+ fileType?: AttachmentType | null;
856
859
 
857
860
  /**
858
861
  * Returns a JSON-serializable record representation of the file.
@@ -3,24 +3,6 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- Object.defineProperty(exports, "AttachmentValidator", {
7
- enumerable: true,
8
- get: function () {
9
- return _types.AttachmentValidator;
10
- }
11
- });
12
- Object.defineProperty(exports, "CustomTypeRegistry", {
13
- enumerable: true,
14
- get: function () {
15
- return _types.CustomTypeRegistry;
16
- }
17
- });
18
- Object.defineProperty(exports, "CustomTypeValidator", {
19
- enumerable: true,
20
- get: function () {
21
- return _types.CustomTypeValidator;
22
- }
23
- });
24
6
  Object.defineProperty(exports, "clickUntilExhausted", {
25
7
  enumerable: true,
26
8
  get: function () {
@@ -109,7 +91,6 @@ var _gotoUrl = require("./gotoUrl");
109
91
  var _uploadFileToS = require("./uploadFileToS3");
110
92
  var _withNetworkSettledWait = require("./withNetworkSettledWait");
111
93
  var _validateDataUsingSchema = require("./validateDataUsingSchema");
112
- var _types = require("./types");
113
94
  var _downloadFile = require("./downloadFile");
114
95
  var _filterEmptyValues = require("./filterEmptyValues");
115
96
  var _processDate = require("./processDate");