@intuned/browser-dev 0.1.8-dev.0 → 0.1.9-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -143
- package/dist/ai/export.d.ts +291 -143
- package/dist/ai/extractStructuredDataUsingAi.js +24 -1
- package/dist/ai/index.d.ts +291 -143
- package/dist/ai/tests/testExtractStructuredData.spec.js +2 -2
- package/dist/common/Logger/index.js +2 -2
- package/dist/helpers/export.d.ts +702 -575
- package/dist/helpers/index.d.ts +702 -575
- package/dist/helpers/withNetworkSettledWait.js +2 -7
- package/dist/optimized-extractors/export.d.ts +17 -18
- package/dist/optimized-extractors/index.d.ts +17 -18
- package/how-to-generate-docs.md +40 -28
- package/package.json +2 -2
package/dist/helpers/index.d.ts
CHANGED
|
@@ -10,11 +10,11 @@ import { Download } from "playwright";
|
|
|
10
10
|
export interface SanitizeHtmlOptions {
|
|
11
11
|
/** The HTML content to sanitize */
|
|
12
12
|
html: string;
|
|
13
|
-
/** Remove all
|
|
13
|
+
/** Remove all \<script\> elements. Defaults to true. */
|
|
14
14
|
removeScripts?: boolean;
|
|
15
|
-
/** Remove all
|
|
15
|
+
/** Remove all \<style\> elements. Defaults to true. */
|
|
16
16
|
removeStyles?: boolean;
|
|
17
|
-
/** Remove all
|
|
17
|
+
/** Remove all \<svg\> elements. Defaults to true. */
|
|
18
18
|
removeSvgs?: boolean;
|
|
19
19
|
/** Remove HTML comments. Defaults to true. */
|
|
20
20
|
removeComments?: boolean;
|
|
@@ -52,108 +52,101 @@ export interface SanitizeHtmlOptions {
|
|
|
52
52
|
*
|
|
53
53
|
* @example
|
|
54
54
|
* ```typescript Basic Sanitization
|
|
55
|
+
* import { BrowserContext, Page } from "playwright";
|
|
55
56
|
* import { sanitizeHtml } from "@intuned/browser";
|
|
56
|
-
* export default async function handler(params, page, context){
|
|
57
|
-
* const dirtyHtml = `
|
|
58
|
-
* <div>
|
|
59
|
-
* <script>alert('xss')</script>
|
|
60
|
-
* <p style="color: red;">Hello World</p>
|
|
61
|
-
* <span></span>
|
|
62
|
-
* </div>
|
|
63
|
-
* `;
|
|
64
|
-
* const sanitizedHtml = sanitizeHtml({ html: dirtyHtml });
|
|
65
|
-
* // Returns: '<div><p>Hello World</p></div>'
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
57
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
* preserveAttributes: ["class", "src", "style"]
|
|
88
|
-
* });
|
|
89
|
-
* }
|
|
58
|
+
* interface Params {}
|
|
59
|
+
*
|
|
60
|
+
* export default async function handler(
|
|
61
|
+
* params: Params,
|
|
62
|
+
* page: Page,
|
|
63
|
+
* context: BrowserContext
|
|
64
|
+
* ) {
|
|
65
|
+
* await page.goto("https://books.toscrape.com");
|
|
66
|
+
* const firstRow = page.locator("ol.row").locator("li").first();
|
|
67
|
+
* // Get the HTML of the first row.
|
|
68
|
+
* const html = await firstRow.innerHTML();
|
|
69
|
+
* // Sanitize the HTML.
|
|
70
|
+
* const sanitizedHtml = sanitizeHtml({ html });
|
|
71
|
+
* // Log the sanitized HTML.
|
|
72
|
+
* console.log(sanitizedHtml);
|
|
73
|
+
* // Return the sanitized HTML.
|
|
74
|
+
* return sanitizedHtml;
|
|
75
|
+
}
|
|
90
76
|
* ```
|
|
91
77
|
*/
|
|
92
78
|
|
|
93
79
|
export declare function sanitizeHtml(options: SanitizeHtmlOptions): string;
|
|
94
80
|
|
|
95
81
|
/**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* 3. **Custom Callback**: Execute a custom function to trigger the download programmatically
|
|
82
|
+
* Downloads a file from a web page using various trigger methods. This function provides three flexible ways to initiate file downloads:
|
|
83
|
+
*
|
|
84
|
+
* - **URL**: Creates a new page, navigates to the URL, waits for download, then automatically closes the page. Ideal for direct download links.
|
|
85
|
+
* - **Locator**: Uses the current page to click the element and capture the resulting download. Perfect for download buttons or interactive elements.
|
|
86
|
+
* - **Callback**: Executes the provided function with the page object and captures the first triggered download. Offers maximum flexibility for complex download scenarios.
|
|
102
87
|
*
|
|
103
88
|
* @param {Object} input - Configuration object for the download operation
|
|
104
89
|
* @param {Page} input.page - The Playwright Page object to use for the download
|
|
105
|
-
* @param {Trigger} input.trigger - The [Trigger](../type-
|
|
106
|
-
* @param {number} [input.timeoutInMs=5000] - Maximum time in milliseconds to wait for download
|
|
107
|
-
* @returns {Promise<Download>} Promise that resolves to a Playwright Download object
|
|
90
|
+
* @param {Trigger} input.trigger - The [Trigger](../type-references/Trigger) method to initiate the download
|
|
91
|
+
* @param {number} [input.timeoutInMs=5000] - Maximum time in milliseconds to wait for the download to trigger. Defaults to 5000.
|
|
92
|
+
* @returns {Promise<Download>} Promise that resolves to a [Playwright Download object](https://playwright.dev/docs/api/class-download)
|
|
108
93
|
*
|
|
109
94
|
* @example
|
|
110
|
-
* ```typescript URL
|
|
95
|
+
* ```typescript Download from direct URL
|
|
111
96
|
* import { downloadFile } from "@intuned/browser";
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
*
|
|
115
|
-
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
97
|
+
* import { BrowserContext, Page } from "playwright";
|
|
98
|
+
|
|
99
|
+
* interface Params {}
|
|
100
|
+
|
|
101
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
102
|
+
* // Download from a direct URL, this will open the url and automatically download the content in it.
|
|
103
|
+
* const download = await downloadFile({
|
|
104
|
+
* page,
|
|
105
|
+
* trigger: "https://intuned-docs-public-images.s3.amazonaws.com/32UP83A_ENG_US.pdf"
|
|
106
|
+
* });
|
|
107
|
+
* file_name = download.suggestedFilename();
|
|
108
|
+
* return file_name;
|
|
109
|
+
*
|
|
119
110
|
* }
|
|
120
111
|
* ```
|
|
121
112
|
*
|
|
122
113
|
* @example
|
|
123
|
-
* ```typescript Locator
|
|
114
|
+
* ```typescript Locator Trigger
|
|
124
115
|
* import { downloadFile } from "@intuned/browser";
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
116
|
+
* import { BrowserContext, Page } from "playwright";
|
|
117
|
+
*
|
|
118
|
+
* interface Params {}
|
|
119
|
+
|
|
120
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
121
|
+
* await page.goto("https://sandbox.intuned.dev/pdfs");
|
|
122
|
+
* const download = await downloadFile({
|
|
123
|
+
* page,
|
|
124
|
+
* trigger: page.locator("xpath=//tbody/tr[1]//*[name()='svg']")
|
|
125
|
+
* });
|
|
126
|
+
* file_name = download.suggestedFilename();
|
|
127
|
+
* return file_name;
|
|
133
128
|
* }
|
|
134
129
|
* ```
|
|
135
130
|
*
|
|
136
131
|
* @example
|
|
137
|
-
* ```typescript Callback
|
|
132
|
+
* ```typescript Callback Trigger
|
|
138
133
|
* import { downloadFile } from "@intuned/browser";
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
134
|
+
* import { BrowserContext, Page } from "playwright";
|
|
135
|
+
*
|
|
136
|
+
* interface Params {}
|
|
137
|
+
*
|
|
138
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
139
|
+
* await page.goto("https://sandbox.intuned.dev/pdfs");
|
|
140
|
+
* const download = await downloadFile({
|
|
141
|
+
* page,
|
|
142
|
+
* trigger: async (page) => {
|
|
143
|
+
* await page.locator("xpath=//tbody/tr[1]//*[name()='svg']").click();
|
|
144
|
+
* }
|
|
145
|
+
* });
|
|
146
|
+
* file_name = download.suggestedFilename();
|
|
147
|
+
* return file_name;
|
|
149
148
|
* }
|
|
150
149
|
* ```
|
|
151
|
-
*
|
|
152
|
-
* @note
|
|
153
|
-
* **Trigger Behavior:**
|
|
154
|
-
* - **URL**: Creates a new page, navigates to the URL, waits for download, then closes the page
|
|
155
|
-
* - **Locator**: Uses the current page to click the element and capture the resulting download
|
|
156
|
-
* - **Callback**: Executes the provided function with the page object and captures the first triggered downloads
|
|
157
150
|
*/
|
|
158
151
|
export declare function downloadFile(input: {
|
|
159
152
|
page: Page;
|
|
@@ -178,10 +171,26 @@ export declare function downloadFile(input: {
|
|
|
178
171
|
* @example
|
|
179
172
|
* ```typescript Basic Usage
|
|
180
173
|
* import { filterEmptyValues } from "@intuned/browser";
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
174
|
+
* import { BrowserContext, Page } from "playwright";
|
|
175
|
+
*
|
|
176
|
+
* interface Params {}
|
|
177
|
+
*
|
|
178
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
179
|
+
* // Filter empty values from dictionary
|
|
180
|
+
* const result1 = filterEmptyValues({ data: { a: "", b: "hello", c: null } });
|
|
181
|
+
* // Output: { b: "hello" }
|
|
182
|
+
* console.log(result1);
|
|
183
|
+
*
|
|
184
|
+
* // Filter empty values from list
|
|
185
|
+
* const result2 = filterEmptyValues({ data: [1, "", null, [2, ""]] });
|
|
186
|
+
* // Output: [1, [2]]
|
|
187
|
+
* console.log(result2);
|
|
188
|
+
*
|
|
189
|
+
* // Filter nested structures
|
|
190
|
+
* const result3 = filterEmptyValues({ data: { users: [{ name: "" }, { name: "John" }] } });
|
|
191
|
+
* // Output: { users: [{ name: "John" }] }
|
|
192
|
+
* console.log(result3);
|
|
193
|
+
* return "All data filtered successfully";
|
|
185
194
|
* }
|
|
186
195
|
* ```
|
|
187
196
|
*/
|
|
@@ -189,66 +198,78 @@ export declare function filterEmptyValues<T>(input: { data: T }): T;
|
|
|
189
198
|
|
|
190
199
|
/**
|
|
191
200
|
* Navigates to a specified URL with enhanced reliability features including automatic retries with exponential backoff,
|
|
192
|
-
* intelligent timeout
|
|
193
|
-
*
|
|
194
|
-
* This function handles common navigation challenges by automatically retrying failed requests, detecting navigation hangs, and ensuring the page reaches a truly idle state.
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* @param {Object} input - The input object containing the page and url
|
|
199
|
-
* @param {Page} input.page - The Playwright page object to navigate
|
|
200
|
-
* @param {string} input.url - The URL to navigate to
|
|
201
|
-
* @param {number} [input.
|
|
202
|
-
* @param {number} [input.
|
|
203
|
-
* @param {
|
|
204
|
-
* @param {boolean} [input.throwOnTimeout=
|
|
205
|
-
* @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
|
|
206
|
-
*
|
|
207
|
-
* @param {string} [input.
|
|
208
|
-
* @
|
|
201
|
+
* intelligent timeout handling, and optional AI-powered loading verification.
|
|
202
|
+
*
|
|
203
|
+
* This function handles common navigation challenges by automatically retrying failed requests, detecting navigation hangs, and ensuring the page reaches a truly idle state.
|
|
204
|
+
*
|
|
205
|
+
* This method can also use AI vision to verify the page is fully loaded by checking for loading spinners, blank content, or incomplete states.
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} input - The input object containing the page and url.
|
|
208
|
+
* @param {Page} input.page - The Playwright page object to navigate.
|
|
209
|
+
* @param {string} input.url - The URL to navigate to.
|
|
210
|
+
* @param {number} [input.timeoutInMs=30000] - Maximum time in milliseconds to wait for navigation. Defaults to 30000.
|
|
211
|
+
* @param {number} [input.retries=3] - Number of retry attempts with exponential backoff (factor: 2). Defaults to 3.
|
|
212
|
+
* @param {("load"|"domcontentloaded"|"networkidle"|"commit")} [input.waitForLoadState="load"] - When to consider navigation succeeded. Defaults to `"load"`
|
|
213
|
+
* @param {boolean} [input.throwOnTimeout=false] - Whether to throw an error if navigation times out. When true, the function throws an error on navigation timeout. Defaults to false.
|
|
214
|
+
* @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 3 times with 5-second delays. Defaults to false
|
|
215
|
+
* Check [isPageLoaded](../../ai/functions/isPageLoaded) for more details on the AI loading verification.
|
|
216
|
+
* @param {string} [input.model="gpt-5-mini-2025-08-07"] - AI model to use for loading verification. Defaults to `"gpt-5-mini-2025-08-07"`
|
|
217
|
+
* @param {string} [input.apiKey] - Optional API key for the AI check.
|
|
218
|
+
* @returns {Promise<void>} Promise that resolves when navigation completes. If the operation fails and `throwOnTimeout` is false, resolves without error
|
|
209
219
|
*
|
|
210
220
|
* @example
|
|
211
|
-
* ```typescript
|
|
221
|
+
* ```typescript Without options
|
|
212
222
|
* import { goToUrl } from "@intuned/browser";
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
223
|
+
* import { BrowserContext, Page } from "playwright";
|
|
224
|
+
*
|
|
225
|
+
* interface Params {}
|
|
226
|
+
*
|
|
227
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
228
|
+
* await goToUrl({
|
|
229
|
+
* page,
|
|
230
|
+
* url: 'https://sandbox.intuned.dev/'
|
|
231
|
+
* });
|
|
232
|
+
* // At this point, goToUrl has waited for the page to be loaded and the network requests to be settled.
|
|
220
233
|
* }
|
|
221
234
|
* ```
|
|
222
235
|
*
|
|
223
236
|
* @example
|
|
224
|
-
* ```typescript
|
|
237
|
+
* ```typescript With options
|
|
225
238
|
* import { goToUrl } from "@intuned/browser";
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
239
|
+
* import { BrowserContext, Page } from "playwright";
|
|
240
|
+
*
|
|
241
|
+
* interface Params {}
|
|
242
|
+
*
|
|
243
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
244
|
+
* await goToUrl({
|
|
245
|
+
* page,
|
|
246
|
+
* url: 'https://intunedhq.com',
|
|
247
|
+
* waitForLoadState: "domcontentloaded", // Faster than "load" state. The function automatically waits for the page to settle.
|
|
248
|
+
* throwOnTimeout: true,
|
|
249
|
+
* timeoutInMs: 10000,
|
|
250
|
+
* retries: 3
|
|
251
|
+
* });
|
|
252
|
+
* // At this point, DOM content is loaded and goToUrl has waited for network requests to settle.
|
|
236
253
|
* }
|
|
237
254
|
* ```
|
|
238
255
|
*
|
|
239
256
|
* @example
|
|
240
|
-
* ```typescript AI
|
|
257
|
+
* ```typescript With AI Loading Detection
|
|
241
258
|
* import { goToUrl } from "@intuned/browser";
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
259
|
+
* import { BrowserContext, Page } from "playwright";
|
|
260
|
+
*
|
|
261
|
+
* interface Params {}
|
|
262
|
+
*
|
|
263
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
264
|
+
* await goToUrl({
|
|
265
|
+
* page,
|
|
266
|
+
* url: 'https://intunedhq.com',
|
|
267
|
+
* waitForLoadingStateUsingAi: true,
|
|
268
|
+
* model: "gpt-4o"
|
|
269
|
+
* });
|
|
270
|
+
* // The page is loaded and ready to use.
|
|
271
|
+
* // If the AI check fails, the method won't throw even if throwOnTimeout is true.
|
|
272
|
+
* // It only throws if the page times out reaching the default load state and throwOnTimeout is true.
|
|
252
273
|
* }
|
|
253
274
|
* ```
|
|
254
275
|
*/
|
|
@@ -258,7 +279,7 @@ export declare function goToUrl(input: {
|
|
|
258
279
|
timeoutInMs?: number;
|
|
259
280
|
retries?: number;
|
|
260
281
|
throwOnTimeout?: boolean;
|
|
261
|
-
waitForLoadState?: "load" | "domcontentloaded" | "networkidle";
|
|
282
|
+
waitForLoadState?: "load" | "domcontentloaded" | "networkidle" | "commit";
|
|
262
283
|
waitForLoadingStateUsingAi?: boolean;
|
|
263
284
|
model?: string;
|
|
264
285
|
apiKey?: string;
|
|
@@ -268,38 +289,49 @@ export declare function goToUrl(input: {
|
|
|
268
289
|
* Automatically scrolls through infinite scroll content by repeatedly scrolling to the bottom
|
|
269
290
|
* until no new content loads or maximum scroll limit is reached.
|
|
270
291
|
*
|
|
271
|
-
* @param {Object} input - The input object containing the data to scroll to load content
|
|
272
|
-
* @param {Page | Locator} input.source - The Playwright Page or Locator to scroll
|
|
273
|
-
* @param {Function} [input.onScrollProgress] - Optional callback function to call during each scroll iteration
|
|
274
|
-
* @param {number} [input.maxScrolls=50] - Maximum number of scroll attempts before stopping. Defaults to 50
|
|
275
|
-
* @param {number} [input.delayInMs=100] - Delay in milliseconds between scroll attempts. Defaults to 100
|
|
276
|
-
* @param {number} [input.minHeightChange=100] - Minimum height change in pixels required to continue scrolling. Defaults to 100
|
|
277
|
-
*
|
|
292
|
+
* @param {Object} input - The input object containing the data to scroll to load content.
|
|
293
|
+
* @param {Page | Locator} input.source - The Playwright Page or Locator to scroll.
|
|
294
|
+
* @param {Function} [input.onScrollProgress] - Optional callback function to call during each scroll iteration.
|
|
295
|
+
* @param {number} [input.maxScrolls=50] - Maximum number of scroll attempts before stopping. Defaults to 50.
|
|
296
|
+
* @param {number} [input.delayInMs=100] - Delay in milliseconds between scroll attempts. Defaults to 100.
|
|
297
|
+
* @param {number} [input.minHeightChange=100] - Minimum height change in pixels required to continue scrolling. Defaults to 100.
|
|
298
|
+
* If the page has loaded all content and we still haven't reached the maxScrolls, the minHeightChange will detect that no new content is loaded and stop the scrolling.
|
|
299
|
+
* @returns {Promise<void>} Promise that resolves when scrolling is complete.
|
|
278
300
|
*
|
|
279
301
|
* @example
|
|
280
|
-
* ```typescript Basic Infinite Scroll
|
|
302
|
+
* ```typescript Basic Infinite Scroll handling
|
|
281
303
|
* import { scrollToLoadContent } from "@intuned/browser";
|
|
282
|
-
*
|
|
304
|
+
* import { BrowserContext, Page } from "playwright";
|
|
305
|
+
*
|
|
306
|
+
* interface Params {}
|
|
307
|
+
*
|
|
308
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
283
309
|
* // Scroll through entire page content
|
|
284
|
-
* await page.goto("https://
|
|
310
|
+
* await page.goto("https://sandbox.intuned.dev/infinite-scroll")
|
|
285
311
|
* await scrollToLoadContent({
|
|
286
312
|
* source: page,
|
|
287
313
|
* });
|
|
288
|
-
* //
|
|
314
|
+
* // Will keep scrolling until the page has loaded all content or the maxScrolls is reached.
|
|
289
315
|
* }
|
|
290
316
|
* ```
|
|
291
317
|
*
|
|
292
318
|
* @example
|
|
293
319
|
* ```typescript Scroll Specific Container
|
|
294
320
|
* import { scrollToLoadContent } from "@intuned/browser";
|
|
295
|
-
*
|
|
321
|
+
* import { BrowserContext, Page } from "playwright";
|
|
322
|
+
*
|
|
323
|
+
* interface Params {}
|
|
324
|
+
*
|
|
325
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
296
326
|
* // Scroll through a specific scrollable div
|
|
297
|
-
* await page.goto("https://docs.intunedhq.com/docs-
|
|
327
|
+
* await page.goto("https://docs.intunedhq.com/docs/00-getting-started/introduction")
|
|
328
|
+
* // This will scroll the sidebar content only and watch its height to change.
|
|
298
329
|
* const container = page.locator("xpath=//div[@id='sidebar-content']");
|
|
299
330
|
* await scrollToLoadContent({
|
|
300
331
|
* source: container,
|
|
301
332
|
* maxScrolls: 20
|
|
302
333
|
* });
|
|
334
|
+
* // Will keep scrolling until the sidebar content has loaded all content or the maxScrolls is reached.
|
|
303
335
|
* }
|
|
304
336
|
* ```
|
|
305
337
|
*/
|
|
@@ -312,32 +344,6 @@ export declare function scrollToLoadContent(input: {
|
|
|
312
344
|
minHeightChange?: number;
|
|
313
345
|
}): Promise<void>;
|
|
314
346
|
|
|
315
|
-
/**
|
|
316
|
-
* Click a button and wait briefly for content to load.
|
|
317
|
-
*
|
|
318
|
-
* This function clicks a button element and waits for a specified delay, allowing time for
|
|
319
|
-
* any triggered content to load. It automatically waits for network activity to settle.
|
|
320
|
-
*
|
|
321
|
-
* @param {Object} input - Configuration options
|
|
322
|
-
* @param {Page} input.page - Playwright Page object
|
|
323
|
-
* @param {Locator} input.buttonLocator - Locator for the button element to click
|
|
324
|
-
* @param {number} [input.clickDelay=0.5] - Delay after clicking the button (in seconds)
|
|
325
|
-
* @returns {Promise<void>} Promise that resolves when the click and wait is complete
|
|
326
|
-
*
|
|
327
|
-
* @example
|
|
328
|
-
* ```typescript Basic Button Click
|
|
329
|
-
* import { clickButtonAndWait } from "@intuned/browser";
|
|
330
|
-
* export default async function handler(params, page, context){
|
|
331
|
-
* await page.goto("https://example.com/products");
|
|
332
|
-
* const loadMoreButton = page.locator("#load-more-button");
|
|
333
|
-
* await clickButtonAndWait({
|
|
334
|
-
* page,
|
|
335
|
-
* buttonLocator: loadMoreButton,
|
|
336
|
-
* clickDelay: 1.0
|
|
337
|
-
* });
|
|
338
|
-
* }
|
|
339
|
-
* ```
|
|
340
|
-
*/
|
|
341
347
|
export declare function clickButtonAndWait(input: {
|
|
342
348
|
page: Page;
|
|
343
349
|
buttonLocator: Locator;
|
|
@@ -349,8 +355,7 @@ export declare function clickButtonAndWait(input: {
|
|
|
349
355
|
*
|
|
350
356
|
* This function is useful for "Load More" buttons or paginated content where you need to
|
|
351
357
|
* keep clicking until all content is loaded. It provides several stopping conditions:
|
|
352
|
-
* - Button becomes invisible
|
|
353
|
-
* - Button becomes disabled
|
|
358
|
+
* - Button becomes invisible/disabled
|
|
354
359
|
* - Maximum number of clicks reached
|
|
355
360
|
* - No change detected in container content (when containerLocator is provided)
|
|
356
361
|
*
|
|
@@ -359,17 +364,21 @@ export declare function clickButtonAndWait(input: {
|
|
|
359
364
|
* @param {Locator} input.buttonLocator - Locator for the button to click repeatedly
|
|
360
365
|
* @param {CallableFunction} [input.heartbeat] - Optional callback invoked after each click
|
|
361
366
|
* @param {Locator} [input.containerLocator] - Optional content container to detect changes
|
|
362
|
-
* @param {number} [input.maxClicks=50] - Maximum number of times to click the button
|
|
363
|
-
* @param {number} [input.clickDelay=0.5] - Delay after each click (in seconds)
|
|
364
|
-
* @param {number} [input.noChangeThreshold=0] - Minimum change in content size to continue clicking
|
|
367
|
+
* @param {number} [input.maxClicks=50] - Maximum number of times to click the button. Defaults to 50.
|
|
368
|
+
* @param {number} [input.clickDelay=0.5] - Delay after each click (in seconds). Defaults to 0.5.
|
|
369
|
+
* @param {number} [input.noChangeThreshold=0] - Minimum change in content size to continue clicking. Defaults to 0.
|
|
365
370
|
* @returns {Promise<void>} Promise that resolves when clicking is exhausted
|
|
366
371
|
*
|
|
367
372
|
* @example
|
|
368
373
|
* ```typescript Load All Items
|
|
369
374
|
* import { clickUntilExhausted } from "@intuned/browser";
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
375
|
+
* import { BrowserContext, Page } from "playwright";
|
|
376
|
+
*
|
|
377
|
+
* interface Params {}
|
|
378
|
+
*
|
|
379
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
380
|
+
* await page.goto("https://sandbox.intuned.dev/load-more");
|
|
381
|
+
* const loadMoreButton = page.locator("main main button"); // Select the main button in the main content area.
|
|
373
382
|
*
|
|
374
383
|
* // Click until button disappears or is disabled
|
|
375
384
|
* await clickUntilExhausted({
|
|
@@ -377,22 +386,27 @@ export declare function clickButtonAndWait(input: {
|
|
|
377
386
|
* buttonLocator: loadMoreButton,
|
|
378
387
|
* maxClicks: 20
|
|
379
388
|
* });
|
|
389
|
+
* // Will keep clicking the button until the button disappears or is disabled or the maxClicks is reached.
|
|
380
390
|
* }
|
|
381
391
|
* ```
|
|
382
392
|
*
|
|
383
393
|
* @example
|
|
384
394
|
* ```typescript Track Container Changes
|
|
385
395
|
* import { clickUntilExhausted } from "@intuned/browser";
|
|
386
|
-
*
|
|
387
|
-
* await page.goto("https://example.com/products");
|
|
388
|
-
* const loadMoreButton = page.locator("#load-more");
|
|
389
|
-
* const productsContainer = page.locator("#products-list");
|
|
396
|
+
* import { BrowserContext, Page } from "playwright";
|
|
390
397
|
*
|
|
398
|
+
* interface Params {}
|
|
399
|
+
*
|
|
400
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
401
|
+
* await page.goto("https://sandbox.intuned.dev/load-more");
|
|
402
|
+
* const loadMoreButton = page.locator("aside button"); // Select the button in the sidebar.
|
|
403
|
+
* const container = page.locator('xpath=//*[@id="root"]/div[1]/main/slot/div/aside/div/div/slot/slot'); // Watch the sidebar container to detect changes.
|
|
404
|
+
* // This will count the elements under the container given before each click and after, if the count is the same, the function will stop.
|
|
391
405
|
* let clickCount = 0;
|
|
392
406
|
* await clickUntilExhausted({
|
|
393
407
|
* page,
|
|
394
408
|
* buttonLocator: loadMoreButton,
|
|
395
|
-
* containerLocator:
|
|
409
|
+
* containerLocator: container,
|
|
396
410
|
* heartbeat: () => {
|
|
397
411
|
* clickCount++;
|
|
398
412
|
* console.log(`Clicked ${clickCount} times`);
|
|
@@ -401,6 +415,7 @@ export declare function clickButtonAndWait(input: {
|
|
|
401
415
|
* clickDelay: 0.5,
|
|
402
416
|
* noChangeThreshold: 0
|
|
403
417
|
* });
|
|
418
|
+
* // Will keep clicking the button until the button disappears or is disabled or the maxClicks is reached or no more content is loaded.
|
|
404
419
|
* }
|
|
405
420
|
* ```
|
|
406
421
|
*/
|
|
@@ -415,30 +430,76 @@ export declare function clickUntilExhausted(input: {
|
|
|
415
430
|
}): Promise<void>;
|
|
416
431
|
|
|
417
432
|
/**
|
|
418
|
-
* Parses various date string formats into Date objects.
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* -
|
|
424
|
-
* -
|
|
425
|
-
* -
|
|
426
|
-
* -
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
433
|
+
* Parses various date string formats into Date objects, returning only the date part with time set to midnight.
|
|
434
|
+
* This utility function provides robust date parsing capabilities for a wide range of common formats.
|
|
435
|
+
*
|
|
436
|
+
* ## Key features
|
|
437
|
+
*
|
|
438
|
+
* - Returns only the date part (year, month, day)
|
|
439
|
+
* - Time is always set to 00:00:00
|
|
440
|
+
* - Supports multiple international formats
|
|
441
|
+
* - Handles timezones and AM/PM formats
|
|
442
|
+
*
|
|
443
|
+
* ## Supported formats
|
|
444
|
+
*
|
|
445
|
+
* The function handles these date format categories:
|
|
446
|
+
*
|
|
447
|
+
* ### Standard date formats
|
|
448
|
+
* - `DD/MM/YYYY`: "22/11/2024", "13/12/2024"
|
|
449
|
+
* - `MM/DD/YYYY`: "01/17/2025", "10/25/2024"
|
|
450
|
+
* - Single-digit variants: "8/16/2019", "9/28/2024"
|
|
451
|
+
*
|
|
452
|
+
* ### Date-time combinations
|
|
453
|
+
* - With 24-hour time: "22/11/2024 21:19:05"
|
|
454
|
+
* - With AM/PM: "12/09/2024 9:00 AM"
|
|
455
|
+
* - With dash separator: "12/19/2024 - 2:00 PM"
|
|
456
|
+
*
|
|
457
|
+
* ### Timezone support
|
|
458
|
+
* - With timezone abbreviations: "10/23/2024 12:06 PM CST"
|
|
459
|
+
* - With timezone offset: "01/17/2025 3:00:00 PM CT"
|
|
460
|
+
*
|
|
461
|
+
* ### Text month formats
|
|
462
|
+
* - Short month: "5 Dec 2024", "11 Sep 2024"
|
|
463
|
+
* - With time: "5 Dec 2024 8:00 AM PST"
|
|
464
|
+
* - Full month: "November 14, 2024", "January 31, 2025, 5:00 pm"
|
|
431
465
|
*
|
|
432
466
|
* @param {Object} input - The input object containing the date to process
|
|
433
467
|
* @param {string} input.date - A string containing a date in various possible formats
|
|
434
|
-
* @returns {Date | null} Date object with only date components (time set to 00:00:00
|
|
468
|
+
* @returns {Date | null} Returns a `Date` object with only date components preserved (year, month, day), time always set to 00:00:00, or `null` if parsing fails
|
|
435
469
|
*
|
|
436
470
|
* @example
|
|
437
|
-
* ```typescript Basic
|
|
471
|
+
* ```typescript Basic Usage
|
|
438
472
|
* import { processDate } from "@intuned/browser";
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
473
|
+
* import { BrowserContext, Page } from "playwright";
|
|
474
|
+
*
|
|
475
|
+
* interface Params {}
|
|
476
|
+
*
|
|
477
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
478
|
+
* // Basic date string
|
|
479
|
+
* const date1 = processDate({ date: "22/11/2024" });
|
|
480
|
+
* console.log(date1); // 2024-11-22 00:00:00
|
|
481
|
+
*
|
|
482
|
+
* // Date with time (time is ignored)
|
|
483
|
+
* const date2 = processDate({ date: "5 Dec 2024 8:00 AM PST" });
|
|
484
|
+
* console.log(date2); // 2024-12-05 00:00:00
|
|
485
|
+
* }
|
|
486
|
+
* ```
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```typescript Invalid Date
|
|
490
|
+
* import { processDate } from "@intuned/browser";
|
|
491
|
+
* import { BrowserContext, Page } from "playwright";
|
|
492
|
+
*
|
|
493
|
+
* interface Params {}
|
|
494
|
+
*
|
|
495
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
496
|
+
* // Invalid date returns null
|
|
497
|
+
* const invalidDate = processDate({ date: "invalid date" });
|
|
498
|
+
* console.log(invalidDate); // will return null.
|
|
499
|
+
* if (invalidDate === null) {
|
|
500
|
+
* throw new Error("Invalid date");
|
|
501
|
+
* }
|
|
502
|
+
* return "should not reach here";
|
|
442
503
|
* }
|
|
443
504
|
* ```
|
|
444
505
|
*/
|
|
@@ -448,81 +509,83 @@ export declare function processDate(input: { date: string }): Date | null;
|
|
|
448
509
|
* Uploads files to AWS S3 storage with flexible configuration options.
|
|
449
510
|
*
|
|
450
511
|
* This function accepts various file types including Playwright Download objects, binary data,
|
|
451
|
-
*
|
|
512
|
+
* making it versatile for different upload scenarios. It automatically
|
|
452
513
|
* handles file metadata and provides comprehensive S3 configuration options.
|
|
453
514
|
*
|
|
515
|
+
* ## S3 configuration fallback
|
|
516
|
+
*
|
|
517
|
+
* The function uses a fallback system to determine S3 settings:
|
|
518
|
+
*
|
|
519
|
+
* 1. **S3Configs Parameter** - If provided, uses the explicit `configs` object with your custom settings.
|
|
520
|
+
* 2. **Environment Variables** - If no configs provided, automatically reads from environment variables:
|
|
521
|
+
* - `AWS_ACCESS_KEY_ID` - Your AWS access key
|
|
522
|
+
* - `AWS_SECRET_ACCESS_KEY` - Your AWS secret key
|
|
523
|
+
* - `AWS_REGION` - AWS region (e.g., "us-west-1")
|
|
524
|
+
* - `AWS_BUCKET` - S3 bucket name
|
|
525
|
+
* - `AWS_ENDPOINT_URL` - Optional custom S3 endpoint
|
|
526
|
+
* - Check [Environment Variables & Secrets](https://docs.intunedhq.com/docs/02-features/environment-variables-secrets) to learn more about setting environment variables.
|
|
527
|
+
* 3. **Intuned Defaults** - If environment variables aren't set, falls back to Intuned's managed S3 storage. See [S3 Attachment Storage](https://docs.intunedhq.com/docs/04-integrations/s3/s3-attachment-storage) for more details.
|
|
528
|
+
*
|
|
454
529
|
* @param {Object} input - Configuration object for the upload operation
|
|
455
|
-
* @param {FileType} input.file - The file to upload. Accepts [FileType](../type-
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
* - ReadStream (file streams)
|
|
459
|
-
* @param {S3Configs} [input.configs] - Optional [S3Configs](../interfaces/S3Configs) for customizing the S3 upload. If not provided, uses environment variables or default configuration
|
|
460
|
-
* @param {string} [input.fileNameOverride] - Optional custom filename for the uploaded file. If not provided, uses the original filename
|
|
530
|
+
* @param {FileType} input.file - The file to upload. Accepts [FileType](../type-references/FileType) types including Playwright Download objects, Uint8Array, Buffer, or ReadStream
|
|
531
|
+
* @param {S3Configs} [input.configs] - Optional [S3Configs](../type-references/S3Configs) for customizing the S3 upload. If not provided, uses environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `AWS_ENDPOINT_URL`, `AWS_BUCKET`). If environment variables aren't set, uses default Intuned S3 settings.
|
|
532
|
+
* @param {string} [input.fileNameOverride] - Optional custom filename for the uploaded file. If not provided, uses the original filename or generates a unique name.
|
|
461
533
|
* @param {string} [input.contentType] - Optional MIME type for the uploaded file (e.g., "application/pdf", "image/png")
|
|
462
|
-
* @returns {Promise<Attachment>} Promise that resolves to an [Attachment](../
|
|
534
|
+
* @returns {Promise<Attachment>} Promise that resolves to an [Attachment](../type-references/Attachment) object with file metadata and utility methods
|
|
463
535
|
*
|
|
464
536
|
* @example
|
|
465
537
|
* ```typescript Upload Downloaded File
|
|
466
538
|
* import { downloadFile, uploadFileToS3 } from "@intuned/browser";
|
|
467
|
-
*
|
|
468
|
-
* // Download and upload a file with custom S3 configuration
|
|
469
|
-
* await page.goto("https://sandbox.intuned.dev/pdfs")
|
|
470
|
-
* const download = await downloadFile({
|
|
471
|
-
* page,
|
|
472
|
-
* trigger: page.locator("xpath=//tbody/tr[1]//*[name()='svg']")
|
|
473
|
-
* });
|
|
539
|
+
* import { BrowserContext, Page } from "playwright";
|
|
474
540
|
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
541
|
+
* interface Params {}
|
|
542
|
+
*
|
|
543
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
544
|
+
* await page.goto("https://sandbox.intuned.dev/pdfs");
|
|
545
|
+
* const download = await downloadFile({
|
|
546
|
+
* page,
|
|
547
|
+
* trigger: page.locator("xpath=//tbody/tr[1]//*[name()='svg']")
|
|
548
|
+
* });
|
|
549
|
+
* // Set your environment variables for the AWS credentials.
|
|
550
|
+
* // Check https://docs.intunedhq.com/docs/02-features/environment-variables-secrets to learn more about setting environment variables.
|
|
551
|
+
* const uploadedFile = await uploadFileToS3({
|
|
552
|
+
* file: download,
|
|
553
|
+
* configs: {
|
|
554
|
+
* bucket: process.env.AWS_BUCKET,
|
|
555
|
+
* region: process.env.AWS_REGION,
|
|
556
|
+
* accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
557
|
+
* secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
|
|
482
558
|
* },
|
|
483
559
|
* fileNameOverride: 'reports/monthly-report.pdf'
|
|
484
|
-
* }
|
|
485
|
-
* });
|
|
560
|
+
* });
|
|
486
561
|
*
|
|
487
|
-
*
|
|
488
|
-
* console.log(`S3 URL: ${uploadedFile.getS3Key()}`);
|
|
562
|
+
* console.log(`File uploaded: ${uploadedFile.suggestedFileName}`);
|
|
489
563
|
* }
|
|
490
564
|
* ```
|
|
491
565
|
*
|
|
492
566
|
* @example
|
|
493
567
|
* ```typescript Upload Binary Data
|
|
494
568
|
* import { uploadFileToS3 } from "@intuned/browser";
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
* }
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
* });
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
*
|
|
569
|
+
* import { BrowserContext, Page } from "playwright";
|
|
570
|
+
*
|
|
571
|
+
* interface Params {}
|
|
572
|
+
*
|
|
573
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
574
|
+
* const fileBuffer = Buffer.from('Hello World', 'utf8');
|
|
575
|
+
* const uploadedFile = await uploadFileToS3({
|
|
576
|
+
* file: fileBuffer,
|
|
577
|
+
* fileNameOverride: 'data/text-file.txt',
|
|
578
|
+
* contentType: 'text/plain'
|
|
579
|
+
* });
|
|
580
|
+
*
|
|
581
|
+
* // Generate a temporary download URL
|
|
582
|
+
* const downloadUrl = await uploadedFile.getSignedUrl();
|
|
583
|
+
* console.log(`Download URL: ${downloadUrl}`);
|
|
584
|
+
* return {
|
|
585
|
+
* downloadUrl: downloadUrl
|
|
586
|
+
* };
|
|
513
587
|
* }
|
|
514
588
|
* ```
|
|
515
|
-
*
|
|
516
|
-
* @note
|
|
517
|
-
* **S3 Configuration Priority:**
|
|
518
|
-
* 1. **Explicit configs**: Values provided in `input.configs.s3Configs`
|
|
519
|
-
* 2. **Environment variables**: Standard AWS environment variables:
|
|
520
|
-
* - `AWS_BUCKET`
|
|
521
|
-
* - `AWS_REGION`
|
|
522
|
-
* - `AWS_ACCESS_KEY_ID`
|
|
523
|
-
* - `AWS_SECRET_ACCESS_KEY`
|
|
524
|
-
* - `AWS_ENDPOINT_URL`
|
|
525
|
-
* 3. **Default fallback**: Intuned's default S3 configuration
|
|
526
589
|
*/
|
|
527
590
|
|
|
528
591
|
export declare function uploadFileToS3(input: {
|
|
@@ -534,41 +597,58 @@ export declare function uploadFileToS3(input: {
|
|
|
534
597
|
|
|
535
598
|
/**
|
|
536
599
|
* Validates data against a JSON schema using the AJV validator.
|
|
537
|
-
* This function can validate any given data against a given schema. It supports validating custom data types such as the [Attachment](../
|
|
600
|
+
* This function can validate any given data against a given schema. It supports validating custom data types such as the [Attachment](../type-references/Attachment) type.
|
|
538
601
|
*
|
|
539
602
|
* @param {Object} input - The input object containing data and schema
|
|
540
603
|
* @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
|
|
541
604
|
* @param {Record<string, any>} input.schema - JSON schema object defining validation rules
|
|
542
605
|
* @returns {void} Returns nothing if validation passes, throws ValidationError if it fails
|
|
606
|
+
* @throws {ValidationError} If validation fails
|
|
543
607
|
*
|
|
544
608
|
* @example
|
|
545
|
-
* ```typescript Basic
|
|
609
|
+
* ```typescript Basic Validation
|
|
546
610
|
* import { validateDataUsingSchema } from "@intuned/browser";
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
*
|
|
611
|
+
* import { BrowserContext, Page } from "playwright";
|
|
612
|
+
*
|
|
613
|
+
* interface Params {}
|
|
614
|
+
*
|
|
615
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
616
|
+
* const uploadData = {
|
|
617
|
+
* file: {
|
|
618
|
+
* fileName: "documents/report.pdf",
|
|
619
|
+
* bucket: "my-bucket",
|
|
620
|
+
* region: "us-east-1",
|
|
621
|
+
* key: "documents/report.pdf",
|
|
622
|
+
* endpoint: null,
|
|
623
|
+
* suggestedFileName: "Monthly Report.pdf",
|
|
624
|
+
* fileType: "document"
|
|
625
|
+
* },
|
|
626
|
+
* name: "Test File Upload"
|
|
552
627
|
* };
|
|
553
628
|
*
|
|
554
|
-
* const
|
|
629
|
+
* const uploadSchema = {
|
|
555
630
|
* type: "object",
|
|
556
|
-
* required: ["
|
|
631
|
+
* required: ["file", "name"],
|
|
557
632
|
* properties: {
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
* age: { type: "number", minimum: 0 }
|
|
633
|
+
* file: { type: "attachment" },
|
|
634
|
+
* name: { type: "string" }
|
|
561
635
|
* }
|
|
562
636
|
* };
|
|
563
637
|
*
|
|
564
|
-
* validateDataUsingSchema({ data:
|
|
565
|
-
* // Validation passes
|
|
638
|
+
* validateDataUsingSchema({ data: uploadData, schema: uploadSchema });
|
|
639
|
+
* // Validation passes with Attachment type
|
|
640
|
+
* console.log("Validation passed");
|
|
641
|
+
* return "Validation passed";
|
|
566
642
|
* }
|
|
567
643
|
* ```
|
|
568
644
|
* @example
|
|
569
645
|
* ```typescript Invalid Data Validation
|
|
570
646
|
* import { validateDataUsingSchema } from "@intuned/browser";
|
|
571
|
-
*
|
|
647
|
+
* import { BrowserContext, Page } from "playwright";
|
|
648
|
+
*
|
|
649
|
+
* interface Params {}
|
|
650
|
+
*
|
|
651
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
572
652
|
* const userData = {
|
|
573
653
|
* name: "John Doe",
|
|
574
654
|
* email: "john@example.com",
|
|
@@ -584,8 +664,10 @@ export declare function uploadFileToS3(input: {
|
|
|
584
664
|
* }
|
|
585
665
|
* };
|
|
586
666
|
*
|
|
587
|
-
* validateDataUsingSchema({ data: userData, schema: userSchema });
|
|
667
|
+
* validateDataUsingSchema({ data: userData, schema: userSchema }); // this will throw
|
|
588
668
|
* // Validation fails, throws ValidationError
|
|
669
|
+
* console.log("Never reached");
|
|
670
|
+
* return "Never reached";
|
|
589
671
|
* }
|
|
590
672
|
* ```
|
|
591
673
|
*/
|
|
@@ -595,11 +677,11 @@ export declare function validateDataUsingSchema(input: {
|
|
|
595
677
|
}): void;
|
|
596
678
|
|
|
597
679
|
/**
|
|
598
|
-
* Executes a callback function and waits for network
|
|
680
|
+
* Executes a callback function and waits for network activity to settle before returning.
|
|
599
681
|
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
682
|
+
* ## `withNetworkSettledWait` vs `waitForDomSettled`
|
|
683
|
+
* - Use `withNetworkSettledWait` when watching **network requests** (API calls, form submissions, resource loading)
|
|
684
|
+
* - Use [waitForDomSettled](../functions/waitForDomSettled) when watching **DOM mutations** (elements added/removed/modified, loading spinners, dynamic content injection)
|
|
603
685
|
*
|
|
604
686
|
* @param {Function} callback - The callback function to execute. Receives the page object as parameter
|
|
605
687
|
* @param {Object} [options] - Configuration options for network monitoring
|
|
@@ -608,21 +690,59 @@ export declare function validateDataUsingSchema(input: {
|
|
|
608
690
|
* @param {number} [options.maxInflightRequests=0] - Maximum number of pending requests to consider as "settled". Defaults to 0 (waits for all requests to complete)
|
|
609
691
|
* @returns {Promise<T>} Promise that resolves to the callback's return value after network settles
|
|
610
692
|
* @example
|
|
611
|
-
* ```typescript
|
|
693
|
+
* ```typescript Wrapper with Inline Function
|
|
612
694
|
* import { withNetworkSettledWait } from "@intuned/browser";
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
* );
|
|
695
|
+
* import { BrowserContext, Page } from "playwright";
|
|
696
|
+
*
|
|
697
|
+
* interface Params {}
|
|
698
|
+
*
|
|
699
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
700
|
+
* await page.goto('https://sandbox.intuned.dev/infinite-scroll');
|
|
701
|
+
*
|
|
702
|
+
* // Execute action and wait for network to settle
|
|
703
|
+
* const result = await withNetworkSettledWait(
|
|
704
|
+
* async (page) => {
|
|
705
|
+
* // scroll to load more content
|
|
706
|
+
* await page.evaluate(() => {
|
|
707
|
+
* window.scrollTo(0, document.body.scrollHeight);
|
|
708
|
+
* });
|
|
709
|
+
* return "scrolled";
|
|
710
|
+
* },
|
|
711
|
+
* {
|
|
712
|
+
* page,
|
|
713
|
+
* timeoutInMs: 15000,
|
|
714
|
+
* maxInflightRequests: 0
|
|
715
|
+
* }
|
|
716
|
+
* );
|
|
717
|
+
* console.log(result); // "scrolled"
|
|
718
|
+
* return result;
|
|
719
|
+
* }
|
|
720
|
+
* ```
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* ```typescript Click Link with Network Wait
|
|
724
|
+
* import { withNetworkSettledWait } from "@intuned/browser";
|
|
725
|
+
* import { BrowserContext, Page } from "playwright";
|
|
726
|
+
*
|
|
727
|
+
* interface Params {}
|
|
728
|
+
*
|
|
729
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
730
|
+
* await page.goto('https://sandbox.intuned.dev/');
|
|
731
|
+
*
|
|
732
|
+
* // Click Object Extractors link and wait for page to load
|
|
733
|
+
* await withNetworkSettledWait(
|
|
734
|
+
* async (page) => {
|
|
735
|
+
* await page.getByText('Object Extractors').click();
|
|
736
|
+
* },
|
|
737
|
+
* {
|
|
738
|
+
* page,
|
|
739
|
+
* timeoutInMs: 10000,
|
|
740
|
+
* maxInflightRequests: 0
|
|
741
|
+
* }
|
|
742
|
+
* );
|
|
743
|
+
* // Object Extractors page loaded
|
|
744
|
+
* const title = await page.locator('div h2').innerText();
|
|
745
|
+
* return title;
|
|
626
746
|
* }
|
|
627
747
|
* ```
|
|
628
748
|
*/
|
|
@@ -636,57 +756,70 @@ export declare function withNetworkSettledWait<T>(
|
|
|
636
756
|
): Promise<T>;
|
|
637
757
|
|
|
638
758
|
/**
|
|
639
|
-
* Waits for
|
|
640
|
-
* that loads progressively or elements that appear/update after initial page load.
|
|
759
|
+
* Waits for DOM mutations to settle without executing any function first. This helper uses a MutationObserver to monitor DOM changes and waits until the DOM has been stable (no mutations) for the specified settle duration.
|
|
641
760
|
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
761
|
+
* ## `waitForDomSettled` vs `withNetworkSettledWait`
|
|
762
|
+
*
|
|
763
|
+
* - Use `waitForDomSettled` when watching **DOM mutations** (elements added/removed/modified, loading spinners, dynamic content injection)
|
|
764
|
+
* - Use [withNetworkSettledWait](../functions/withNetworkSettledWait) when watching **network requests** (API calls, form submissions, resource loading)
|
|
645
765
|
*
|
|
646
766
|
* @param {Object} options - Configuration object for DOM settlement monitoring
|
|
647
|
-
* @param {Page | Locator} options.source - The Playwright Page or Locator to monitor for DOM changes. When a Page is provided, monitors the entire document
|
|
767
|
+
* @param {Page | Locator} options.source - The Playwright Page or Locator to monitor for DOM changes. When a Page is provided, monitors the entire document. When a Locator is provided, monitors only that specific element.
|
|
648
768
|
* @param {number} [options.settleDurationMs=500] - Milliseconds the DOM must remain unchanged to be considered settled. Defaults to 500
|
|
649
769
|
* @param {number} [options.timeoutInMs=30000] - Maximum milliseconds to wait before giving up. Defaults to 30000
|
|
650
770
|
* @returns {Promise<boolean>} Promise that resolves to true if DOM settled within timeout, false if timeout or error occurred
|
|
651
771
|
*
|
|
652
772
|
* @example
|
|
653
|
-
* ```typescript Wait
|
|
773
|
+
* ```typescript Wait After Navigation
|
|
654
774
|
* import { waitForDomSettled } from '@intuned/browser';
|
|
655
|
-
*
|
|
656
|
-
* // Navigate to a dynamic page
|
|
657
|
-
* await page.goto('https://docs.intunedhq.com/docs-old/getting-started/introduction');
|
|
775
|
+
* import { BrowserContext, Page } from "playwright";
|
|
658
776
|
*
|
|
659
|
-
*
|
|
660
|
-
* const settled = await waitForDomSettled({
|
|
661
|
-
* source: page,
|
|
662
|
-
* settleDurationMs: 1000
|
|
663
|
-
* });
|
|
777
|
+
* interface Params {}
|
|
664
778
|
*
|
|
665
|
-
*
|
|
666
|
-
* //
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
779
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
780
|
+
* // Navigate to page with dynamic content
|
|
781
|
+
* await page.goto('https://sandbox.intuned.dev/lists/table');
|
|
782
|
+
*
|
|
783
|
+
* // Wait for all DOM mutations to complete
|
|
784
|
+
* const settled = await waitForDomSettled({
|
|
785
|
+
* source: page,
|
|
786
|
+
* settleDurationMs: 1000,
|
|
787
|
+
* timeoutInMs: 20000
|
|
788
|
+
* });
|
|
789
|
+
*
|
|
790
|
+
* if (settled) {
|
|
791
|
+
* // DOM is stable, safe to extract data
|
|
792
|
+
* const rows = await page.locator('table tr').all();
|
|
793
|
+
* return rows.length;
|
|
794
|
+
* }
|
|
795
|
+
* return 0;
|
|
671
796
|
* }
|
|
672
797
|
* ```
|
|
673
798
|
*
|
|
674
799
|
* @example
|
|
675
|
-
* ```typescript
|
|
800
|
+
* ```typescript Watch Specific Container
|
|
676
801
|
* import { waitForDomSettled } from '@intuned/browser';
|
|
677
|
-
*
|
|
678
|
-
* await page.goto("https://docs.intunedhq.com/")
|
|
679
|
-
* // Wait for a specific feed container to stop updating
|
|
680
|
-
* const settled = await waitForDomSettled({
|
|
681
|
-
* source: page.locator("xpath=//div[@id='sidebar-content']"),
|
|
682
|
-
* settleDurationMs: 2000,
|
|
683
|
-
* timeoutInMs: 15000,
|
|
684
|
-
* });
|
|
802
|
+
* import { BrowserContext, Page } from "playwright";
|
|
685
803
|
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
804
|
+
* interface Params {}
|
|
805
|
+
*
|
|
806
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
807
|
+
* await page.goto("https://sandbox.intuned.dev/lists/table");
|
|
808
|
+
*
|
|
809
|
+
* // Only watch table container (ignore header/footer changes)
|
|
810
|
+
* const table = page.locator("table");
|
|
811
|
+
* const settled = await waitForDomSettled({
|
|
812
|
+
* source: table,
|
|
813
|
+
* settleDurationMs: 800,
|
|
814
|
+
* timeoutInMs: 15000,
|
|
815
|
+
* });
|
|
816
|
+
*
|
|
817
|
+
* if (settled) {
|
|
818
|
+
* // Table has finished loading
|
|
819
|
+
* const rows = await table.locator('tr').count();
|
|
820
|
+
* return rows;
|
|
821
|
+
* }
|
|
822
|
+
* return 0;
|
|
690
823
|
* }
|
|
691
824
|
* ```
|
|
692
825
|
*/
|
|
@@ -700,53 +833,71 @@ export declare function waitForDomSettled(options: {
|
|
|
700
833
|
* Converts HTML content from a Playwright Page or Locator to semantic markdown format.
|
|
701
834
|
*
|
|
702
835
|
* @param {Object} input - The input object containing the source of the HTML content
|
|
703
|
-
* @param {Page | Locator} input.source - The source of the HTML content.
|
|
836
|
+
* @param {Page | Locator} input.source - The source of the HTML content. When a Page is provided, extracts from the entire page. When a Locator is provided, extracts from that specific element.
|
|
704
837
|
* @returns {Promise<string>} Promise that resolves to the markdown representation of the HTML content
|
|
838
|
+
*
|
|
705
839
|
* @example
|
|
706
|
-
* ```typescript
|
|
840
|
+
* ```typescript Extract Markdown from Locator
|
|
707
841
|
* import { extractMarkdown } from "@intuned/browser";
|
|
708
|
-
*
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
842
|
+
* import { BrowserContext, Page } from "playwright";
|
|
843
|
+
*
|
|
844
|
+
* interface Params {}
|
|
845
|
+
*
|
|
846
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
847
|
+
* await page.goto("https://books.toscrape.com/");
|
|
848
|
+
* const headerLocator = page.locator('h1').first(); // First title on the page
|
|
849
|
+
* const markdown = await extractMarkdown({ source: headerLocator }); // Extract markdown from the first title
|
|
850
|
+
* console.log(markdown);
|
|
851
|
+
* return markdown;
|
|
713
852
|
* }
|
|
714
853
|
* ```
|
|
854
|
+
*
|
|
715
855
|
* @example
|
|
716
|
-
* ```typescript
|
|
856
|
+
* ```typescript Extract Markdown from Page
|
|
717
857
|
* import { extractMarkdown } from "@intuned/browser";
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
858
|
+
* import { BrowserContext, Page } from "playwright";
|
|
859
|
+
*
|
|
860
|
+
* interface Params {}
|
|
861
|
+
*
|
|
862
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
863
|
+
* await page.goto("https://sandbox.intuned.dev/pdfs");
|
|
864
|
+
* const markdown = await extractMarkdown({ source: page });
|
|
865
|
+
* console.log(markdown);
|
|
866
|
+
* return markdown;
|
|
722
867
|
* }
|
|
723
868
|
* ```
|
|
724
|
-
*
|
|
725
869
|
*/
|
|
726
870
|
export declare function extractMarkdown(input: {
|
|
727
871
|
source: Page | Locator;
|
|
728
872
|
}): Promise<string>;
|
|
729
873
|
|
|
730
874
|
/**
|
|
731
|
-
* Converts any URL source to an absolute, properly encoded URL
|
|
875
|
+
* Converts any URL source to an absolute, properly encoded URL.
|
|
876
|
+
*
|
|
877
|
+
* @overload Base URL String
|
|
878
|
+
*
|
|
879
|
+
* Combines a relative URL with a base URL string. Use when you have an explicit base URL string to resolve relative paths against.
|
|
732
880
|
*
|
|
733
|
-
* @overload From Base URL String
|
|
734
881
|
* @param {Object} input - Configuration object with different properties based on the overload
|
|
735
882
|
* @param {string} input.url - The relative or absolute URL to resolve
|
|
736
883
|
* @param {string} input.baseUrl - Base URL string to resolve relative URLs against
|
|
737
884
|
* @returns {Promise<string>} Promise that resolves to the absolute, properly encoded URL string
|
|
738
885
|
* @example
|
|
739
|
-
* ```typescript String
|
|
886
|
+
* ```typescript Resolve from Base URL String
|
|
740
887
|
* import { resolveUrl } from '@intuned/browser';
|
|
741
|
-
*
|
|
742
|
-
*
|
|
888
|
+
* import { BrowserContext, Page } from "playwright";
|
|
889
|
+
*
|
|
890
|
+
* interface Params {}
|
|
743
891
|
*
|
|
744
|
-
*
|
|
892
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
893
|
+
* // Resolve from base URL string
|
|
745
894
|
* const absoluteUrl = await resolveUrl({
|
|
746
|
-
* url: "/
|
|
747
|
-
* baseUrl: "https://
|
|
895
|
+
* url: "/lists/table",
|
|
896
|
+
* baseUrl: "https://sandbox.intuned.dev"
|
|
748
897
|
* });
|
|
749
|
-
* // Returns: "https://
|
|
898
|
+
* // Returns: "https://sandbox.intuned.dev/lists/table"
|
|
899
|
+
* console.log(absoluteUrl);
|
|
900
|
+
* return absoluteUrl;
|
|
750
901
|
* }
|
|
751
902
|
* ```
|
|
752
903
|
*/
|
|
@@ -756,24 +907,33 @@ export declare function resolveUrl(input: {
|
|
|
756
907
|
}): Promise<string>;
|
|
757
908
|
|
|
758
909
|
/**
|
|
759
|
-
* Converts any URL source to an absolute, properly encoded URL
|
|
910
|
+
* Converts any URL source to an absolute, properly encoded URL.
|
|
911
|
+
*
|
|
912
|
+
* @overload Current Page's URL
|
|
913
|
+
*
|
|
914
|
+
* Uses the current page's URL as the base URL. Use when resolving URLs relative to the current page.
|
|
760
915
|
*
|
|
761
|
-
* @overload From The Current Page's URL
|
|
762
916
|
* @param {Object} input - Configuration object with different properties based on the overload
|
|
763
917
|
* @param {string} input.url - The relative or absolute URL to resolve
|
|
764
918
|
* @param {Page} input.page - Playwright Page object to extract base URL from. The current page URL will be used as the base URL
|
|
765
919
|
* @returns {Promise<string>} Promise that resolves to the absolute, properly encoded URL string
|
|
766
920
|
* @example
|
|
767
|
-
* ```typescript Page
|
|
921
|
+
* ```typescript Resolve from the Current Page's URL
|
|
768
922
|
* import { resolveUrl } from '@intuned/browser';
|
|
769
|
-
*
|
|
770
|
-
*
|
|
771
|
-
*
|
|
923
|
+
* import { BrowserContext, Page } from "playwright";
|
|
924
|
+
*
|
|
925
|
+
* interface Params {}
|
|
926
|
+
*
|
|
927
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
928
|
+
* await page.goto("https://sandbox.intuned.dev/");
|
|
929
|
+
* // Resolve from the current page's URL
|
|
772
930
|
* const absoluteUrl = await resolveUrl({
|
|
773
|
-
* url: "/
|
|
931
|
+
* url: "/lists/table",
|
|
774
932
|
* page: page
|
|
775
933
|
* });
|
|
776
|
-
* // Returns: "https://
|
|
934
|
+
* // Returns: "https://sandbox.intuned.dev/lists/table"
|
|
935
|
+
* console.log(absoluteUrl);
|
|
936
|
+
* return absoluteUrl;
|
|
777
937
|
* }
|
|
778
938
|
* ```
|
|
779
939
|
*/
|
|
@@ -783,21 +943,31 @@ export declare function resolveUrl(input: {
|
|
|
783
943
|
}): Promise<string>;
|
|
784
944
|
|
|
785
945
|
/**
|
|
786
|
-
* Converts any URL source to an absolute, properly encoded URL
|
|
946
|
+
* Converts any URL source to an absolute, properly encoded URL.
|
|
947
|
+
*
|
|
948
|
+
* @overload Anchor Elements
|
|
949
|
+
*
|
|
950
|
+
* Extracts the href attribute from a Playwright Locator pointing to an anchor element. Use when extracting and resolving URLs from anchor (`<a>`) elements.
|
|
787
951
|
*
|
|
788
|
-
* @overload From Anchor Element
|
|
789
952
|
* @param {Object} input - Configuration object with different properties based on the overload
|
|
790
|
-
* @param {Locator} input.url - Playwright Locator pointing to an anchor element. The href attribute will be extracted and resolved
|
|
953
|
+
* @param {Locator} input.url - Playwright Locator pointing to an anchor element. The href attribute will be extracted and resolved relative to the current page.
|
|
791
954
|
* @returns {Promise<string>} Promise that resolves to the absolute, properly encoded URL string
|
|
792
955
|
* @example
|
|
793
|
-
* ```typescript
|
|
956
|
+
* ```typescript Resolve from Anchor Element
|
|
794
957
|
* import { resolveUrl } from '@intuned/browser';
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
958
|
+
* import { BrowserContext, Page } from "playwright";
|
|
959
|
+
*
|
|
960
|
+
* interface Params {}
|
|
961
|
+
*
|
|
962
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
963
|
+
* await page.goto("https://sandbox.intuned.dev/");
|
|
964
|
+
* // Resolve from Anchor Element
|
|
965
|
+
* const absoluteUrl = await resolveUrl({
|
|
966
|
+
* url: page.locator("xpath=//a[normalize-space()='Steps Form']"),
|
|
967
|
+
* });
|
|
968
|
+
* // Returns: "https://sandbox.intuned.dev/steps-form"
|
|
969
|
+
* console.log(absoluteUrl);
|
|
970
|
+
* return absoluteUrl;
|
|
801
971
|
* }
|
|
802
972
|
* ```
|
|
803
973
|
*/
|
|
@@ -806,31 +976,64 @@ export declare function resolveUrl(input: { url: Locator }): Promise<string>;
|
|
|
806
976
|
/**
|
|
807
977
|
* Represents an uploaded file stored in AWS S3 with metadata and utility methods.
|
|
808
978
|
*
|
|
809
|
-
*
|
|
810
|
-
* in S3, including methods for generating presigned URLs, serialization, and accessing
|
|
811
|
-
* file metadata.
|
|
979
|
+
* Provides a structured way to handle file information for files stored in S3, including methods for generating presigned URLs, serialization, and accessing file metadata.
|
|
812
980
|
*
|
|
813
981
|
* @interface Attachment
|
|
982
|
+
*
|
|
814
983
|
* @example
|
|
815
|
-
* ```typescript
|
|
816
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
817
|
-
*
|
|
818
|
-
* // Typically returned from uploadFileToS3 or saveFileToS3
|
|
984
|
+
* ```typescript Basic Usage
|
|
985
|
+
* import { uploadFileToS3, Attachment } from "@intuned/browser";
|
|
986
|
+
* import { BrowserContext, Page } from "playwright";
|
|
819
987
|
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
988
|
+
* interface Params {}
|
|
989
|
+
*
|
|
990
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
991
|
+
* const uploadedFile: Attachment = await uploadFileToS3({
|
|
992
|
+
* file: myFile,
|
|
993
|
+
* configs: s3Config
|
|
994
|
+
* });
|
|
995
|
+
*
|
|
996
|
+
* // Access file properties
|
|
997
|
+
* console.log(uploadedFile.fileName);
|
|
998
|
+
* console.log(uploadedFile.suggestedFileName);
|
|
999
|
+
* }
|
|
1000
|
+
* ```
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* ```typescript Working with Presigned URLs
|
|
1004
|
+
* import { uploadFileToS3, Attachment } from "@intuned/browser";
|
|
1005
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1006
|
+
*
|
|
1007
|
+
* interface Params {}
|
|
824
1008
|
*
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
1009
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1010
|
+
* const uploadedFile: Attachment = await uploadFileToS3({
|
|
1011
|
+
* file: myFile
|
|
1012
|
+
* });
|
|
828
1013
|
*
|
|
829
|
-
*
|
|
830
|
-
*
|
|
1014
|
+
* // Generate a presigned URL for temporary access
|
|
1015
|
+
* const downloadUrl = await uploadedFile.getSignedUrl(3600); // 1 hour expiration
|
|
831
1016
|
*
|
|
832
|
-
*
|
|
833
|
-
*
|
|
1017
|
+
* // Get the permanent S3 URL
|
|
1018
|
+
* const s3Url = uploadedFile.getS3Key();
|
|
1019
|
+
* }
|
|
1020
|
+
* ```
|
|
1021
|
+
*
|
|
1022
|
+
* @example
|
|
1023
|
+
* ```typescript Serialization
|
|
1024
|
+
* import { uploadFileToS3, Attachment } from "@intuned/browser";
|
|
1025
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1026
|
+
*
|
|
1027
|
+
* interface Params {}
|
|
1028
|
+
*
|
|
1029
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1030
|
+
* const uploadedFile: Attachment = await uploadFileToS3({
|
|
1031
|
+
* file: myFile
|
|
1032
|
+
* });
|
|
1033
|
+
*
|
|
1034
|
+
* // Convert to dictionary for storage or API responses
|
|
1035
|
+
* const fileDict = uploadedFile.toDict();
|
|
1036
|
+
* const fileJson = uploadedFile.toJSON();
|
|
834
1037
|
* }
|
|
835
1038
|
* ```
|
|
836
1039
|
*/
|
|
@@ -859,96 +1062,36 @@ export interface Attachment {
|
|
|
859
1062
|
/**
|
|
860
1063
|
* Returns a JSON-serializable record representation of the file.
|
|
861
1064
|
*
|
|
862
|
-
* @
|
|
863
|
-
* @returns {Record<string, string>} Complete model data including all fields
|
|
864
|
-
*
|
|
865
|
-
* @example
|
|
866
|
-
* ```typescript
|
|
867
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
868
|
-
* export default async function handler(params, page, context){
|
|
869
|
-
* file.toJSON()
|
|
870
|
-
* // {
|
|
871
|
-
* // 'fileName': 'docs/report.pdf',
|
|
872
|
-
* // 'bucket': 'uploads',
|
|
873
|
-
* // 'region': 'us-east-1',
|
|
874
|
-
* // 'endpoint': undefined,
|
|
875
|
-
* // 'suggestedFileName': 'Report.pdf'
|
|
876
|
-
* // }
|
|
877
|
-
* }
|
|
878
|
-
* ```
|
|
1065
|
+
* @returns `Record<string, string>` - Complete model data including all fields
|
|
879
1066
|
*/
|
|
880
1067
|
toJSON(): Record<string, string>;
|
|
881
1068
|
|
|
882
1069
|
/**
|
|
883
|
-
* Converts the file metadata to a record
|
|
884
|
-
*
|
|
885
|
-
* @method Attachment.toDict
|
|
886
|
-
* @returns {Record<string, string>} Record with fileName, bucket, region, and suggestedFileName
|
|
1070
|
+
* Converts the file metadata to a record.
|
|
887
1071
|
*
|
|
888
|
-
* @
|
|
889
|
-
* ```typescript
|
|
890
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
891
|
-
* export default async function handler(params, page, context){
|
|
892
|
-
* file.toDict()
|
|
893
|
-
* // {
|
|
894
|
-
* // 'fileName': 'docs/report.pdf',
|
|
895
|
-
* // 'bucket': 'uploads',
|
|
896
|
-
* // 'region': 'us-east-1',
|
|
897
|
-
* // 'suggestedFileName': 'Report.pdf'
|
|
898
|
-
* // }
|
|
899
|
-
* }
|
|
900
|
-
* ```
|
|
1072
|
+
* @returns `Record<string, string>` - Record with fileName, key, bucket, region, endpoint, suggestedFileName, and fileType
|
|
901
1073
|
*/
|
|
902
1074
|
toDict(): Record<string, string>;
|
|
903
1075
|
|
|
904
1076
|
/**
|
|
905
1077
|
* Returns the full S3 URL for the file.
|
|
906
1078
|
*
|
|
907
|
-
* @
|
|
908
|
-
* @returns {string} Complete S3 URL
|
|
909
|
-
*
|
|
910
|
-
* @example
|
|
911
|
-
* ```typescript
|
|
912
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
913
|
-
* export default async function handler(params, page, context){
|
|
914
|
-
* file.getS3Key()
|
|
915
|
-
* // "https://uploads.s3.us-east-1.amazonaws.com/docs/report.pdf"
|
|
916
|
-
* }
|
|
917
|
-
* ```
|
|
1079
|
+
* @returns `string` - Complete S3 URL in format: https://bucket.s3.region.amazonaws.com/filename
|
|
918
1080
|
*/
|
|
919
1081
|
getS3Key(): string;
|
|
920
1082
|
|
|
921
1083
|
/**
|
|
922
1084
|
* Returns the file path/key within the S3 bucket.
|
|
923
1085
|
*
|
|
924
|
-
* @
|
|
925
|
-
* @returns {string} The fileName property (S3 object key)
|
|
926
|
-
*
|
|
927
|
-
* @example
|
|
928
|
-
* ```typescript
|
|
929
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
930
|
-
* export default async function handler(params, page, context){
|
|
931
|
-
* file.getFilePath()
|
|
932
|
-
* // "docs/report.pdf"
|
|
933
|
-
* }
|
|
934
|
-
* ```
|
|
1086
|
+
* @returns `string` - The fileName property (S3 object key)
|
|
935
1087
|
*/
|
|
936
1088
|
getFilePath(): string;
|
|
937
1089
|
|
|
938
1090
|
/**
|
|
939
1091
|
* Generates a presigned URL for secure, temporary access to the file.
|
|
940
1092
|
*
|
|
941
|
-
* @
|
|
942
|
-
* @
|
|
943
|
-
* @returns {Promise<string>} Promise that resolves to presigned URL for downloading the file
|
|
944
|
-
*
|
|
945
|
-
* @example
|
|
946
|
-
* ```typescript
|
|
947
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
948
|
-
* export default async function handler(params, page, context){
|
|
949
|
-
* const url = await file.getSignedUrl(3600); // 1 hour expiration
|
|
950
|
-
* }
|
|
951
|
-
* ```
|
|
1093
|
+
* @param expiration - URL expiration time in seconds. Defaults to 432000 (5 days)
|
|
1094
|
+
* @returns `Promise<string>` - Presigned URL for downloading the file
|
|
952
1095
|
*/
|
|
953
1096
|
getSignedUrl(expiration?: number): Promise<string>;
|
|
954
1097
|
}
|
|
@@ -956,124 +1099,129 @@ export interface Attachment {
|
|
|
956
1099
|
/**
|
|
957
1100
|
* A union type representing different methods to trigger file downloads in web automation.
|
|
958
1101
|
*
|
|
959
|
-
* This type
|
|
960
|
-
* multiple approaches to suit different automation scenarios.
|
|
961
|
-
*
|
|
962
|
-
* @type Trigger
|
|
1102
|
+
* This type standardizes how download operations can be initiated, providing multiple approaches for different automation scenarios.
|
|
963
1103
|
*
|
|
964
|
-
* **Type
|
|
1104
|
+
* **Type variants:**
|
|
965
1105
|
* - `string`: Direct URL string to download from
|
|
966
1106
|
* - `Locator`: Playwright Locator object pointing to a clickable download element
|
|
967
|
-
* - `(page: Page) => Promise<void>`: Custom function that takes a Page and triggers the download
|
|
1107
|
+
* - `(page: Page) => Promise<void>`: Custom async function that takes a Page and triggers the download
|
|
968
1108
|
*
|
|
969
1109
|
* @example
|
|
970
1110
|
* ```typescript URL String Trigger
|
|
971
1111
|
* import { downloadFile } from "@intuned/browser";
|
|
972
|
-
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
*
|
|
1112
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1113
|
+
*
|
|
1114
|
+
* interface Params {}
|
|
1115
|
+
*
|
|
1116
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1117
|
+
* // Direct download from URL
|
|
1118
|
+
* const download = await downloadFile({
|
|
1119
|
+
* page,
|
|
1120
|
+
* trigger: "https://example.com/report.pdf"
|
|
1121
|
+
* });
|
|
978
1122
|
* }
|
|
979
1123
|
* ```
|
|
980
1124
|
*
|
|
981
1125
|
* @example
|
|
982
1126
|
* ```typescript Locator Trigger
|
|
983
1127
|
* import { downloadFile } from "@intuned/browser";
|
|
984
|
-
*
|
|
985
|
-
*
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
-
*
|
|
1128
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1129
|
+
*
|
|
1130
|
+
* interface Params {}
|
|
1131
|
+
*
|
|
1132
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1133
|
+
* // Click a download button
|
|
1134
|
+
* const download = await downloadFile({
|
|
1135
|
+
* page,
|
|
1136
|
+
* trigger: page.locator("#download-btn")
|
|
1137
|
+
* });
|
|
991
1138
|
* }
|
|
992
1139
|
* ```
|
|
993
1140
|
*
|
|
994
1141
|
* @example
|
|
995
|
-
* ```typescript
|
|
1142
|
+
* ```typescript Callback Trigger
|
|
996
1143
|
* import { downloadFile } from "@intuned/browser";
|
|
997
|
-
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1003
|
-
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1144
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1145
|
+
*
|
|
1146
|
+
* interface Params {}
|
|
1147
|
+
*
|
|
1148
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1149
|
+
* // Custom download logic
|
|
1150
|
+
* const download = await downloadFile({
|
|
1151
|
+
* page,
|
|
1152
|
+
* trigger: async (p) => {
|
|
1153
|
+
* await p.locator("button.prepare").click();
|
|
1154
|
+
* await p.waitForSelector(".ready");
|
|
1155
|
+
* await p.locator("a.download-link").click();
|
|
1156
|
+
* }
|
|
1157
|
+
* });
|
|
1007
1158
|
* }
|
|
1008
1159
|
* ```
|
|
1009
|
-
*
|
|
1010
|
-
* @note
|
|
1011
|
-
* All download functions in the helpers module accept Trigger for consistency.
|
|
1012
|
-
* The trigger method determines how the download operation is initiated.
|
|
1013
1160
|
*/
|
|
1014
1161
|
export type Trigger = string | Locator | ((page: Page) => Promise<void>);
|
|
1015
1162
|
|
|
1016
1163
|
/**
|
|
1017
|
-
* Configuration
|
|
1164
|
+
* Configuration for AWS S3 storage operations.
|
|
1018
1165
|
*
|
|
1019
|
-
*
|
|
1020
|
-
* for connecting to and performing operations with AWS S3 storage. All properties
|
|
1021
|
-
* are optional and will fall back to environment variables or default configuration.
|
|
1166
|
+
* Defines the parameters needed to connect to and interact with AWS S3 storage services. Supports both standard AWS S3 and S3-compatible storage services through custom endpoints.
|
|
1022
1167
|
*
|
|
1023
1168
|
* @interface S3Configs
|
|
1024
|
-
* @example
|
|
1025
|
-
* ```typescript S3 Configuration
|
|
1026
|
-
* import { uploadFileToS3 } from "@intuned/browser";
|
|
1027
|
-
* export default async function handler(params, page, context){
|
|
1028
|
-
* // Basic S3 configuration
|
|
1029
|
-
* const s3Config: S3Configs = {
|
|
1030
|
-
* bucket: "my-app-uploads",
|
|
1031
|
-
* region: "us-east-1",
|
|
1032
|
-
* accessKeyId: "accessKeyId",
|
|
1033
|
-
* secretAccessKey: "SecretAccessKeyId"
|
|
1034
|
-
* };
|
|
1035
1169
|
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1170
|
+
* @example
|
|
1171
|
+
* ```typescript Basic Configuration
|
|
1172
|
+
* import { uploadFileToS3, S3Configs } from "@intuned/browser";
|
|
1173
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1174
|
+
*
|
|
1175
|
+
* interface Params {}
|
|
1176
|
+
*
|
|
1177
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1178
|
+
* // Using explicit credentials
|
|
1179
|
+
* const s3Config: S3Configs = {
|
|
1180
|
+
* accessKeyId: "accessKeyId",
|
|
1181
|
+
* secretAccessKey: "SecretAccessKeyId",
|
|
1182
|
+
* bucket: "my-app-uploads",
|
|
1183
|
+
* region: "us-east-1"
|
|
1184
|
+
* };
|
|
1185
|
+
* }
|
|
1186
|
+
* ```
|
|
1041
1187
|
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1188
|
+
* @example
|
|
1189
|
+
* ```typescript Environment Variables Configuration
|
|
1190
|
+
* import { uploadFileToS3, S3Configs } from "@intuned/browser";
|
|
1191
|
+
* export default async function handler(params, page, context){
|
|
1192
|
+
* // Credentials will be picked up from environment or IAM roles
|
|
1193
|
+
* const s3Config: S3Configs = {
|
|
1194
|
+
* bucket: "my-app-uploads",
|
|
1195
|
+
* region: "us-west-2"
|
|
1196
|
+
* };
|
|
1048
1197
|
* }
|
|
1049
1198
|
* ```
|
|
1050
1199
|
*/
|
|
1051
1200
|
export interface S3Configs {
|
|
1052
|
-
/**
|
|
1201
|
+
/** Name of the S3 bucket to store files in. Must be a valid S3 bucket name following AWS naming conventions. */
|
|
1053
1202
|
bucket?: string;
|
|
1054
1203
|
|
|
1055
|
-
/**
|
|
1204
|
+
/** AWS region where the S3 bucket is located. Examples: "us-east-1", "eu-west-1", "ap-southeast-1" */
|
|
1056
1205
|
region?: string;
|
|
1057
1206
|
|
|
1058
|
-
/** AWS access key ID for authentication
|
|
1207
|
+
/** AWS access key ID for authentication. If undefined, will attempt to use default AWS credentials or environment variables. */
|
|
1059
1208
|
accessKeyId?: string;
|
|
1060
1209
|
|
|
1061
|
-
/** AWS secret access key for authentication
|
|
1210
|
+
/** AWS secret access key for authentication. If undefined, will attempt to use default AWS credentials or environment variables. */
|
|
1062
1211
|
secretAccessKey?: string;
|
|
1063
1212
|
|
|
1064
|
-
/** Custom
|
|
1213
|
+
/** Custom endpoint URL for S3-compatible storage services. Use this for services like MinIO, DigitalOcean Spaces, or other S3-compatible APIs. For standard AWS S3, leave this undefined. */
|
|
1065
1214
|
endpoint?: string;
|
|
1066
1215
|
}
|
|
1067
1216
|
|
|
1068
1217
|
/**
|
|
1069
1218
|
* A union type representing different file formats that can be processed by the SDK.
|
|
1070
1219
|
*
|
|
1071
|
-
*
|
|
1072
|
-
* supporting multiple input formats for maximum convenience.
|
|
1220
|
+
* Provides flexibility in how files can be passed to various functions, supporting multiple input formats.
|
|
1073
1221
|
*
|
|
1074
1222
|
* @type FileType
|
|
1075
1223
|
*
|
|
1076
|
-
* **Type
|
|
1224
|
+
* **Type variants:**
|
|
1077
1225
|
* - `Download`: Playwright Download object from browser download operations
|
|
1078
1226
|
* - `Uint8Array`: Binary data as Uint8Array
|
|
1079
1227
|
* - `Buffer`: Node.js Buffer containing binary data
|
|
@@ -1129,79 +1277,59 @@ export type FileType = Download | Uint8Array | Buffer | ReadStream;
|
|
|
1129
1277
|
/**
|
|
1130
1278
|
* Downloads a file from a web page and automatically uploads it to AWS S3 storage in a single operation.
|
|
1131
1279
|
*
|
|
1132
|
-
*
|
|
1133
|
-
* providing a streamlined workflow for capturing
|
|
1134
|
-
* It supports the same flexible trigger methods as `downloadFile` with additional S3 upload configuration.
|
|
1280
|
+
* Combines [downloadFile](./downloadFile) (for trigger methods) and [uploadFileToS3](./uploadFileToS3)
|
|
1281
|
+
* (for S3 configuration), providing a streamlined workflow for capturing and storing files.
|
|
1135
1282
|
*
|
|
1136
1283
|
* @param {Object} input - Configuration object for the download and upload operation
|
|
1137
1284
|
* @param {Page} input.page - The Playwright Page object to use for downloading
|
|
1138
|
-
* @param {Trigger} input.trigger - The [Trigger](../type-
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
* @param {
|
|
1143
|
-
* @
|
|
1144
|
-
* @param {string} [input.fileNameOverride] - Optional filename override for the uploaded file
|
|
1145
|
-
* @param {string} [input.contentType] - Optional content type for the uploaded file
|
|
1146
|
-
* @returns {Promise<Attachment>} Promise that resolves to an [Attachment](../interfaces/Attachment) object with file metadata and S3 utilities
|
|
1285
|
+
* @param {Trigger} input.trigger - The [Trigger](../type-references/Trigger) method to initiate the download
|
|
1286
|
+
* @param {number} [input.timeoutInMs=5000] - Maximum time in milliseconds to wait for download to start. Defaults to 5000.
|
|
1287
|
+
* @param {S3Configs} [input.configs] - Optional [S3Configs](../type-references/S3Configs) to customize the S3 upload. If not provided, uses environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_ENDPOINT_URL, AWS_BUCKET). If environment variables aren't set, uses default Intuned S3 settings.
|
|
1288
|
+
* @param {string} [input.fileNameOverride] - Optional custom filename for the uploaded file. If not provided, uses the original filename or generates a unique name.
|
|
1289
|
+
* @param {string} [input.contentType] - Optional MIME type for the uploaded file (e.g., “application/pdf”, “image/png”).
|
|
1290
|
+
* @returns {Promise<Attachment>} Promise that resolves to an [Attachment](../type-references/Attachment) object with file metadata and S3 utilities
|
|
1147
1291
|
*
|
|
1148
1292
|
* @example
|
|
1149
|
-
* ```typescript URL
|
|
1150
|
-
* import { saveFileToS3 } from "@intuned/browser"
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1157
|
-
*
|
|
1293
|
+
* ```typescript URL Trigger
|
|
1294
|
+
* import { saveFileToS3 } from "@intuned/browser"
|
|
1295
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1296
|
+
*
|
|
1297
|
+
* interface Params {}
|
|
1298
|
+
*
|
|
1299
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1300
|
+
* const uploadedFile = await saveFileToS3({
|
|
1301
|
+
* page,
|
|
1302
|
+
* trigger: "https://sandbox.intuned.dev/pdfs/report.pdf",
|
|
1303
|
+
* configs: {
|
|
1304
|
+
* bucket: 'document-storage',
|
|
1158
1305
|
* region: 'us-east-1',
|
|
1159
1306
|
* accessKeyId: 'accessKeyId',
|
|
1160
1307
|
* secretAccessKey: 'SecretAccessKeyId'
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1164
|
-
* });
|
|
1165
|
-
*
|
|
1166
|
-
* console.log(`File uploaded to: ${uploadedFile.getS3Key()}`);
|
|
1308
|
+
* },
|
|
1309
|
+
* fileNameOverride: 'reports/monthly-report.pdf'
|
|
1310
|
+
* });
|
|
1311
|
+
* console.log(`File uploaded to: ${uploadedFile.getS3Key()}`);
|
|
1167
1312
|
* }
|
|
1168
1313
|
* ```
|
|
1169
1314
|
*
|
|
1170
1315
|
* @example
|
|
1171
|
-
* ```typescript Locator
|
|
1316
|
+
* ```typescript Locator Trigger
|
|
1172
1317
|
* import { saveFileToS3 } from "@intuned/browser";
|
|
1173
|
-
*
|
|
1174
|
-
* // Click download link and save to S3
|
|
1175
|
-
* await page.goto("https://sandbox.intuned.dev/pdfs")
|
|
1176
|
-
* const uploadedFile = await saveFileToS3({
|
|
1177
|
-
* page,
|
|
1178
|
-
* trigger: page.locator("xpath=//tbody/tr[1]//*[name()='svg']"),
|
|
1179
|
-
* timeoutInMs: 10000,
|
|
1180
|
-
* configs: {
|
|
1181
|
-
* bucket: 'invoice-archive',
|
|
1182
|
-
* region: 'us-west-2',
|
|
1183
|
-
* accessKeyId: 'accessKeyId',
|
|
1184
|
-
* secretAccessKey: 'SecretAccessKeyId'
|
|
1185
|
-
* },
|
|
1186
|
-
* fileNameOverride: 'invoices/invoice.pdf',
|
|
1187
|
-
* contentType: 'application/pdf'
|
|
1188
|
-
* });
|
|
1318
|
+
* import { BrowserContext, Page } from "playwright";
|
|
1189
1319
|
*
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1320
|
+
* interface Params {}
|
|
1321
|
+
*
|
|
1322
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext){
|
|
1323
|
+
* await page.goto("https://sandbox.intuned.dev/pdfs");
|
|
1324
|
+
* const uploadedFile = await saveFileToS3({
|
|
1325
|
+
* page,
|
|
1326
|
+
* trigger: page.locator("xpath=//tbody/tr[1]//*[name()='svg']"),
|
|
1327
|
+
* timeoutInMs: 10000
|
|
1328
|
+
* });
|
|
1329
|
+
* const downloadUrl = await uploadedFile.getSignedUrl(7200); // 2 hours
|
|
1330
|
+
* console.log(`Temporary access: ${downloadUrl}`);
|
|
1193
1331
|
* }
|
|
1194
1332
|
* ```
|
|
1195
|
-
* @note
|
|
1196
|
-
* **S3 Configuration hierarchy:** (same as `uploadFileToS3`):
|
|
1197
|
-
* 1. Explicit `configs` values from the input
|
|
1198
|
-
* 2. Standard AWS environment variables (`AWS_BUCKET`, `AWS_REGION`, etc.)
|
|
1199
|
-
* 3. Intuned's default S3 configuration as fallback
|
|
1200
|
-
*
|
|
1201
|
-
* **Trigger Behavior** (same as `downloadFile`):
|
|
1202
|
-
* - **URL**: Creates temporary page, navigates to URL, captures download, closes page
|
|
1203
|
-
* - **Locator**: Uses current page to click element and capture download
|
|
1204
|
-
* - **Callback**: Executes custom function and captures any resulting downloads
|
|
1205
1333
|
*/
|
|
1206
1334
|
export declare function saveFileToS3(input: {
|
|
1207
1335
|
page: Page;
|
|
@@ -1215,7 +1343,6 @@ export declare function saveFileToS3(input: {
|
|
|
1215
1343
|
/**
|
|
1216
1344
|
* Union type representing the supported attachment file types.
|
|
1217
1345
|
*
|
|
1218
|
-
* @type AttachmentType
|
|
1219
1346
|
* Currently supported types:
|
|
1220
1347
|
* - `"document"`: Document files (PDFs, Word docs, etc.)
|
|
1221
1348
|
*/
|