@agnocon/piece-browserless 0.1.7
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/LICENSE.MIT-AP +24 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/actions/capture-screenshot.d.ts +20 -0
- package/dist/lib/actions/capture-screenshot.d.ts.map +1 -0
- package/dist/lib/actions/capture-screenshot.js +176 -0
- package/dist/lib/actions/capture-screenshot.js.map +1 -0
- package/dist/lib/actions/generate-pdf.d.ts +38 -0
- package/dist/lib/actions/generate-pdf.d.ts.map +1 -0
- package/dist/lib/actions/generate-pdf.js +346 -0
- package/dist/lib/actions/generate-pdf.js.map +1 -0
- package/dist/lib/actions/get-website-performance.d.ts +20 -0
- package/dist/lib/actions/get-website-performance.d.ts.map +1 -0
- package/dist/lib/actions/get-website-performance.js +306 -0
- package/dist/lib/actions/get-website-performance.js.map +1 -0
- package/dist/lib/actions/run-bql-query.d.ts +26 -0
- package/dist/lib/actions/run-bql-query.d.ts.map +1 -0
- package/dist/lib/actions/run-bql-query.js +273 -0
- package/dist/lib/actions/run-bql-query.js.map +1 -0
- package/dist/lib/actions/scrape-url.d.ts +27 -0
- package/dist/lib/actions/scrape-url.d.ts.map +1 -0
- package/dist/lib/actions/scrape-url.js +277 -0
- package/dist/lib/actions/scrape-url.js.map +1 -0
- package/dist/lib/common/auth.d.ts +6 -0
- package/dist/lib/common/auth.d.ts.map +1 -0
- package/dist/lib/common/auth.js +62 -0
- package/dist/lib/common/auth.js.map +1 -0
- package/dist/lib/common/client.d.ts +18 -0
- package/dist/lib/common/client.d.ts.map +1 -0
- package/dist/lib/common/client.js +56 -0
- package/dist/lib/common/client.js.map +1 -0
- package/package.json +46 -0
- package/src/index.ts +26 -0
- package/src/lib/actions/capture-screenshot.ts +176 -0
- package/src/lib/actions/generate-pdf.ts +364 -0
- package/src/lib/actions/get-website-performance.ts +321 -0
- package/src/lib/actions/run-bql-query.ts +295 -0
- package/src/lib/actions/scrape-url.ts +291 -0
- package/src/lib/common/auth.ts +57 -0
- package/src/lib/common/client.ts +72 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { createAction, Property } from '@agnocon/pieces-framework';
|
|
2
|
+
import { HttpMethod } from '@agnocon/pieces-common';
|
|
3
|
+
import { browserlessAuth } from '../common/auth';
|
|
4
|
+
import { browserlessCommon } from '../common/client';
|
|
5
|
+
|
|
6
|
+
export const getWebsitePerformance = createAction({
|
|
7
|
+
name: 'get_website_performance',
|
|
8
|
+
displayName: 'Get Website Performance',
|
|
9
|
+
description: 'Analyze website performance metrics using Lighthouse',
|
|
10
|
+
audience: 'both',
|
|
11
|
+
aiMetadata: { description: 'Runs a Lighthouse audit on a public URL in a headless browser and returns performance, accessibility, best-practices, SEO, and PWA scores plus key metrics. Use to measure a page\'s quality; the URL is required, and you can scope the audit to specific categories and simulate a desktop or mobile device with network throttling. Read-only analysis: re-running with the same input re-audits the page without side effects (scores may vary slightly run to run).', idempotent: true },
|
|
12
|
+
auth: browserlessAuth,
|
|
13
|
+
props: {
|
|
14
|
+
url: Property.ShortText({
|
|
15
|
+
displayName: 'URL',
|
|
16
|
+
description: 'The URL of the website to analyze',
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
categories: Property.Array({
|
|
20
|
+
displayName: 'Performance Categories',
|
|
21
|
+
description: 'Select which performance categories to analyze (performance, accessibility, best-practices, seo, pwa)',
|
|
22
|
+
required: false,
|
|
23
|
+
properties: {
|
|
24
|
+
category: Property.StaticDropdown({
|
|
25
|
+
displayName: 'Category',
|
|
26
|
+
required: true,
|
|
27
|
+
options: {
|
|
28
|
+
options: [
|
|
29
|
+
{ label: 'Performance', value: 'performance' },
|
|
30
|
+
{ label: 'Accessibility', value: 'accessibility' },
|
|
31
|
+
{ label: 'Best Practices', value: 'best-practices' },
|
|
32
|
+
{ label: 'SEO', value: 'seo' },
|
|
33
|
+
{ label: 'PWA', value: 'pwa' }
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}),
|
|
39
|
+
device: Property.StaticDropdown({
|
|
40
|
+
displayName: 'Device Type',
|
|
41
|
+
description: 'Device type for performance analysis',
|
|
42
|
+
required: false,
|
|
43
|
+
defaultValue: 'desktop',
|
|
44
|
+
options: {
|
|
45
|
+
options: [
|
|
46
|
+
{ label: 'Desktop', value: 'desktop' },
|
|
47
|
+
{ label: 'Mobile', value: 'mobile' }
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}),
|
|
51
|
+
throttling: Property.StaticDropdown({
|
|
52
|
+
displayName: 'Network Throttling',
|
|
53
|
+
description: 'Network throttling simulation',
|
|
54
|
+
required: false,
|
|
55
|
+
defaultValue: 'mobileSlow4G',
|
|
56
|
+
options: {
|
|
57
|
+
options: [
|
|
58
|
+
{ label: 'No Throttling', value: 'none' },
|
|
59
|
+
{ label: 'Slow 4G', value: 'mobileSlow4G' },
|
|
60
|
+
{ label: 'Regular 4G', value: 'mobileRegular4G' },
|
|
61
|
+
{ label: 'Fast 4G', value: 'mobileFast4G' }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
onlyCategories: Property.Checkbox({
|
|
66
|
+
displayName: 'Only Category Scores',
|
|
67
|
+
description: 'Return only category scores without detailed audit results',
|
|
68
|
+
required: false,
|
|
69
|
+
defaultValue: false,
|
|
70
|
+
}),
|
|
71
|
+
locale: Property.ShortText({
|
|
72
|
+
displayName: 'Locale',
|
|
73
|
+
description: 'Locale for the analysis (e.g., en-US, de-DE)',
|
|
74
|
+
required: false,
|
|
75
|
+
defaultValue: 'en-US',
|
|
76
|
+
}),
|
|
77
|
+
userAgent: Property.ShortText({
|
|
78
|
+
displayName: 'User Agent',
|
|
79
|
+
description: 'Custom user agent string',
|
|
80
|
+
required: false,
|
|
81
|
+
}),
|
|
82
|
+
timeout: Property.Number({
|
|
83
|
+
displayName: 'Timeout (ms)',
|
|
84
|
+
description: 'Maximum time to wait for the analysis to complete',
|
|
85
|
+
required: false,
|
|
86
|
+
defaultValue: 60000,
|
|
87
|
+
}),
|
|
88
|
+
waitForSelector: Property.ShortText({
|
|
89
|
+
displayName: 'Wait for Selector',
|
|
90
|
+
description: 'CSS selector to wait for before running performance analysis',
|
|
91
|
+
required: false,
|
|
92
|
+
}),
|
|
93
|
+
emulateMediaType: Property.StaticDropdown({
|
|
94
|
+
displayName: 'Emulate Media Type',
|
|
95
|
+
description: 'Emulate CSS media type',
|
|
96
|
+
required: false,
|
|
97
|
+
options: {
|
|
98
|
+
options: [
|
|
99
|
+
{ label: 'Screen', value: 'screen' },
|
|
100
|
+
{ label: 'Print', value: 'print' }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
}),
|
|
104
|
+
budgets: Property.Array({
|
|
105
|
+
displayName: 'Performance Budgets',
|
|
106
|
+
description: 'Lighthouse performance budgets for resource sizes',
|
|
107
|
+
required: false,
|
|
108
|
+
properties: {
|
|
109
|
+
resourceType: Property.StaticDropdown({
|
|
110
|
+
displayName: 'Resource Type',
|
|
111
|
+
description: 'Type of resource to budget',
|
|
112
|
+
required: true,
|
|
113
|
+
options: {
|
|
114
|
+
options: [
|
|
115
|
+
{ label: 'Document', value: 'document' },
|
|
116
|
+
{ label: 'Script', value: 'script' },
|
|
117
|
+
{ label: 'Stylesheet', value: 'stylesheet' },
|
|
118
|
+
{ label: 'Image', value: 'image' },
|
|
119
|
+
{ label: 'Media', value: 'media' },
|
|
120
|
+
{ label: 'Font', value: 'font' },
|
|
121
|
+
{ label: 'Other', value: 'other' },
|
|
122
|
+
{ label: 'Third-party', value: 'third-party' }
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
}),
|
|
126
|
+
budget: Property.Number({
|
|
127
|
+
displayName: 'Budget Size (KB)',
|
|
128
|
+
description: 'Maximum allowed size in kilobytes',
|
|
129
|
+
required: true,
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
}),
|
|
133
|
+
stealth: Property.Checkbox({
|
|
134
|
+
displayName: 'Stealth Mode',
|
|
135
|
+
description: 'Enable stealth mode for bot detection bypass',
|
|
136
|
+
required: false,
|
|
137
|
+
defaultValue: false,
|
|
138
|
+
}),
|
|
139
|
+
blockAds: Property.Checkbox({
|
|
140
|
+
displayName: 'Block Ads',
|
|
141
|
+
description: 'Enable ad blocker during performance analysis',
|
|
142
|
+
required: false,
|
|
143
|
+
defaultValue: false,
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
async run(context) {
|
|
147
|
+
const requestBody: any = {
|
|
148
|
+
url: context.propsValue.url,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const lighthouseConfig: any = {
|
|
152
|
+
extends: 'lighthouse:default',
|
|
153
|
+
settings: {}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
if (context.propsValue.categories && context.propsValue.categories.length > 0) {
|
|
157
|
+
lighthouseConfig.settings.onlyCategories = context.propsValue.categories.map((cat: any) => cat.category);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (context.propsValue.locale) {
|
|
161
|
+
lighthouseConfig.settings.locale = context.propsValue.locale;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (context.propsValue.device) {
|
|
165
|
+
lighthouseConfig.settings.formFactor = context.propsValue.device;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (context.propsValue.throttling && context.propsValue.throttling !== 'none') {
|
|
169
|
+
lighthouseConfig.settings.throttling = { rttMs: 150, throughputKbps: 1638.4, cpuSlowdownMultiplier: 4 };
|
|
170
|
+
|
|
171
|
+
switch (context.propsValue.throttling) {
|
|
172
|
+
case 'mobileSlow4G':
|
|
173
|
+
lighthouseConfig.settings.throttling = { rttMs: 150, throughputKbps: 1638.4, cpuSlowdownMultiplier: 4 };
|
|
174
|
+
break;
|
|
175
|
+
case 'mobileRegular4G':
|
|
176
|
+
lighthouseConfig.settings.throttling = { rttMs: 100, throughputKbps: 2048, cpuSlowdownMultiplier: 3 };
|
|
177
|
+
break;
|
|
178
|
+
case 'mobileFast4G':
|
|
179
|
+
lighthouseConfig.settings.throttling = { rttMs: 50, throughputKbps: 4096, cpuSlowdownMultiplier: 2 };
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (context.propsValue.userAgent) {
|
|
185
|
+
lighthouseConfig.settings.userAgent = context.propsValue.userAgent;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (context.propsValue.timeout) {
|
|
189
|
+
lighthouseConfig.settings.timeout = context.propsValue.timeout;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (context.propsValue.waitForSelector) {
|
|
193
|
+
lighthouseConfig.settings.waitForSelector = context.propsValue.waitForSelector;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (context.propsValue.emulateMediaType) {
|
|
197
|
+
lighthouseConfig.settings.emulatedFormFactor = context.propsValue.emulateMediaType;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (context.propsValue.onlyCategories && !lighthouseConfig.settings.onlyCategories) {
|
|
201
|
+
lighthouseConfig.settings.onlyCategories = ['performance', 'accessibility', 'best-practices', 'seo', 'pwa'];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
requestBody.config = lighthouseConfig;
|
|
205
|
+
|
|
206
|
+
if (context.propsValue.budgets && context.propsValue.budgets.length > 0) {
|
|
207
|
+
requestBody.budgets = context.propsValue.budgets.map((budget: any) => ({
|
|
208
|
+
resourceType: budget.resourceType,
|
|
209
|
+
budget: budget.budget * 1024
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let resourceUri = '/performance';
|
|
214
|
+
const queryParams: string[] = [];
|
|
215
|
+
|
|
216
|
+
if (context.propsValue.stealth) {
|
|
217
|
+
queryParams.push('stealth=true');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (context.propsValue.blockAds) {
|
|
221
|
+
queryParams.push('blockAds=true');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (queryParams.length > 0) {
|
|
225
|
+
resourceUri += `?${queryParams.join('&')}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const response = await browserlessCommon.apiCall({
|
|
229
|
+
auth: context.auth.props,
|
|
230
|
+
method: HttpMethod.POST,
|
|
231
|
+
resourceUri,
|
|
232
|
+
body: requestBody,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const performanceData = response.body;
|
|
236
|
+
|
|
237
|
+
const summary: any = {
|
|
238
|
+
url: context.propsValue.url,
|
|
239
|
+
formFactor: context.propsValue.device || 'desktop',
|
|
240
|
+
timestamp: new Date().toISOString(),
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
if (performanceData.lhr && performanceData.lhr.categories) {
|
|
244
|
+
const categories = performanceData.lhr.categories;
|
|
245
|
+
summary.scores = {
|
|
246
|
+
performance: categories.performance?.score ? Math.round(categories.performance.score * 100) : null,
|
|
247
|
+
accessibility: categories.accessibility?.score ? Math.round(categories.accessibility.score * 100) : null,
|
|
248
|
+
bestPractices: categories['best-practices']?.score ? Math.round(categories['best-practices'].score * 100) : null,
|
|
249
|
+
seo: categories.seo?.score ? Math.round(categories.seo.score * 100) : null,
|
|
250
|
+
pwa: categories.pwa?.score ? Math.round(categories.pwa.score * 100) : null,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (performanceData.lhr && performanceData.lhr.audits) {
|
|
255
|
+
const audits = performanceData.lhr.audits;
|
|
256
|
+
summary.metrics = {
|
|
257
|
+
firstContentfulPaint: {
|
|
258
|
+
value: audits['first-contentful-paint']?.displayValue || null,
|
|
259
|
+
score: audits['first-contentful-paint']?.score ? Math.round(audits['first-contentful-paint'].score * 100) : null
|
|
260
|
+
},
|
|
261
|
+
largestContentfulPaint: {
|
|
262
|
+
value: audits['largest-contentful-paint']?.displayValue || null,
|
|
263
|
+
score: audits['largest-contentful-paint']?.score ? Math.round(audits['largest-contentful-paint'].score * 100) : null
|
|
264
|
+
},
|
|
265
|
+
firstMeaningfulPaint: {
|
|
266
|
+
value: audits['first-meaningful-paint']?.displayValue || null,
|
|
267
|
+
score: audits['first-meaningful-paint']?.score ? Math.round(audits['first-meaningful-paint'].score * 100) : null
|
|
268
|
+
},
|
|
269
|
+
speedIndex: {
|
|
270
|
+
value: audits['speed-index']?.displayValue || null,
|
|
271
|
+
score: audits['speed-index']?.score ? Math.round(audits['speed-index'].score * 100) : null
|
|
272
|
+
},
|
|
273
|
+
timeToInteractive: {
|
|
274
|
+
value: audits['interactive']?.displayValue || null,
|
|
275
|
+
score: audits['interactive']?.score ? Math.round(audits['interactive'].score * 100) : null
|
|
276
|
+
},
|
|
277
|
+
totalBlockingTime: {
|
|
278
|
+
value: audits['total-blocking-time']?.displayValue || null,
|
|
279
|
+
score: audits['total-blocking-time']?.score ? Math.round(audits['total-blocking-time'].score * 100) : null
|
|
280
|
+
},
|
|
281
|
+
cumulativeLayoutShift: {
|
|
282
|
+
value: audits['cumulative-layout-shift']?.displayValue || null,
|
|
283
|
+
score: audits['cumulative-layout-shift']?.score ? Math.round(audits['cumulative-layout-shift'].score * 100) : null
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
summary.opportunities = [];
|
|
288
|
+
if (audits['unused-css-rules']?.details?.items?.length > 0) {
|
|
289
|
+
summary.opportunities.push({
|
|
290
|
+
type: 'unused-css',
|
|
291
|
+
title: 'Remove unused CSS',
|
|
292
|
+
potentialSavings: audits['unused-css-rules'].displayValue || 'Unknown'
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (audits['unused-javascript']?.details?.items?.length > 0) {
|
|
296
|
+
summary.opportunities.push({
|
|
297
|
+
type: 'unused-javascript',
|
|
298
|
+
title: 'Remove unused JavaScript',
|
|
299
|
+
potentialSavings: audits['unused-javascript'].displayValue || 'Unknown'
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (audits['render-blocking-resources']?.details?.items?.length > 0) {
|
|
303
|
+
summary.opportunities.push({
|
|
304
|
+
type: 'render-blocking',
|
|
305
|
+
title: 'Eliminate render-blocking resources',
|
|
306
|
+
potentialSavings: audits['render-blocking-resources'].displayValue || 'Unknown'
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
success: true,
|
|
313
|
+
summary,
|
|
314
|
+
fullReport: performanceData,
|
|
315
|
+
metadata: {
|
|
316
|
+
analysisTime: response.headers?.['x-response-time'] || 'unknown',
|
|
317
|
+
lighthouseVersion: performanceData.lhr?.lighthouseVersion || 'unknown',
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
});
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { createAction, Property } from '@agnocon/pieces-framework';
|
|
2
|
+
import { HttpMethod } from '@agnocon/pieces-common';
|
|
3
|
+
import { browserlessAuth } from '../common/auth';
|
|
4
|
+
import { browserlessCommon } from '../common/client';
|
|
5
|
+
|
|
6
|
+
export const runBqlQuery = createAction({
|
|
7
|
+
name: 'run_bql_query',
|
|
8
|
+
displayName: 'Run BQL Query',
|
|
9
|
+
description: 'Execute Browser Query Language (BQL) GraphQL-based queries for advanced browser automation',
|
|
10
|
+
audience: 'both',
|
|
11
|
+
aiMetadata: { description: 'Runs a raw Browser Query Language (BQL) GraphQL query against a headless Chromium browser for advanced automation such as navigation, clicking, typing, and multi-step scripted browser flows. Use when the simpler screenshot/scrape/PDF actions cannot express the interaction; requires a valid BQL query string and supports session options like stealth, proxy, and cookies. Not idempotent: the query can perform stateful browser actions and side-effecting navigation, so repeating it may not yield the same result.', idempotent: false },
|
|
12
|
+
auth: browserlessAuth,
|
|
13
|
+
props: {
|
|
14
|
+
query: Property.LongText({
|
|
15
|
+
displayName: 'BQL Query',
|
|
16
|
+
description: 'GraphQL-based BQL query for browser automation. Example: mutation { goto(url: "https://example.com") { status } }',
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
variables: Property.Object({
|
|
20
|
+
displayName: 'Query Variables',
|
|
21
|
+
description: 'Variables to pass to the BQL query (JSON object)',
|
|
22
|
+
required: false,
|
|
23
|
+
}),
|
|
24
|
+
operationName: Property.ShortText({
|
|
25
|
+
displayName: 'Operation Name',
|
|
26
|
+
description: 'Name of the GraphQL operation to execute',
|
|
27
|
+
required: false,
|
|
28
|
+
}),
|
|
29
|
+
timeout: Property.Number({
|
|
30
|
+
displayName: 'Timeout (ms)',
|
|
31
|
+
description: 'Maximum execution time in milliseconds',
|
|
32
|
+
required: false,
|
|
33
|
+
defaultValue: 30000,
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
stealth: Property.Checkbox({
|
|
37
|
+
displayName: 'Stealth Mode',
|
|
38
|
+
description: 'Enable stealth mode for bot detection bypass',
|
|
39
|
+
required: false,
|
|
40
|
+
defaultValue: true,
|
|
41
|
+
}),
|
|
42
|
+
headless: Property.Checkbox({
|
|
43
|
+
displayName: 'Headless Mode',
|
|
44
|
+
description: 'Run browser in headless mode (set to false for GUI)',
|
|
45
|
+
required: false,
|
|
46
|
+
defaultValue: true,
|
|
47
|
+
}),
|
|
48
|
+
humanlike: Property.Checkbox({
|
|
49
|
+
displayName: 'Human-like Behavior',
|
|
50
|
+
description: 'Enable human-like mouse movement, typing, and delays',
|
|
51
|
+
required: false,
|
|
52
|
+
defaultValue: false,
|
|
53
|
+
}),
|
|
54
|
+
proxy: Property.StaticDropdown({
|
|
55
|
+
displayName: 'Proxy Type',
|
|
56
|
+
description: 'Type of proxy to use',
|
|
57
|
+
required: false,
|
|
58
|
+
options: {
|
|
59
|
+
options: [
|
|
60
|
+
{ label: 'Residential', value: 'residential' },
|
|
61
|
+
{ label: 'None', value: 'none' }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}),
|
|
65
|
+
proxyCountry: Property.ShortText({
|
|
66
|
+
displayName: 'Proxy Country',
|
|
67
|
+
description: 'Country code for residential proxy (e.g., us, gb, de)',
|
|
68
|
+
required: false,
|
|
69
|
+
}),
|
|
70
|
+
proxySticky: Property.Checkbox({
|
|
71
|
+
displayName: 'Sticky Proxy',
|
|
72
|
+
description: 'Maintain same proxy IP across session',
|
|
73
|
+
required: false,
|
|
74
|
+
defaultValue: false,
|
|
75
|
+
}),
|
|
76
|
+
blockAds: Property.Checkbox({
|
|
77
|
+
displayName: 'Block Ads',
|
|
78
|
+
description: 'Enable ad blocker (uBlock Origin)',
|
|
79
|
+
required: false,
|
|
80
|
+
defaultValue: false,
|
|
81
|
+
}),
|
|
82
|
+
blockConsentModals: Property.Checkbox({
|
|
83
|
+
displayName: 'Block Consent Modals',
|
|
84
|
+
description: 'Automatically block/dismiss cookie consent banners',
|
|
85
|
+
required: false,
|
|
86
|
+
defaultValue: false,
|
|
87
|
+
}),
|
|
88
|
+
record: Property.Checkbox({
|
|
89
|
+
displayName: 'Record Session',
|
|
90
|
+
description: 'Enable session recording for debugging',
|
|
91
|
+
required: false,
|
|
92
|
+
defaultValue: false,
|
|
93
|
+
}),
|
|
94
|
+
slowMo: Property.Number({
|
|
95
|
+
displayName: 'Slow Motion (ms)',
|
|
96
|
+
description: 'Add delays between browser actions in milliseconds',
|
|
97
|
+
required: false,
|
|
98
|
+
}),
|
|
99
|
+
ignoreHTTPSErrors: Property.Checkbox({
|
|
100
|
+
displayName: 'Ignore HTTPS Errors',
|
|
101
|
+
description: 'Ignore HTTPS certificate errors during navigation',
|
|
102
|
+
required: false,
|
|
103
|
+
defaultValue: false,
|
|
104
|
+
}),
|
|
105
|
+
userAgent: Property.ShortText({
|
|
106
|
+
displayName: 'User Agent',
|
|
107
|
+
description: 'Custom user agent string',
|
|
108
|
+
required: false,
|
|
109
|
+
}),
|
|
110
|
+
viewportWidth: Property.Number({
|
|
111
|
+
displayName: 'Viewport Width',
|
|
112
|
+
description: 'Browser viewport width',
|
|
113
|
+
required: false,
|
|
114
|
+
}),
|
|
115
|
+
viewportHeight: Property.Number({
|
|
116
|
+
displayName: 'Viewport Height',
|
|
117
|
+
description: 'Browser viewport height',
|
|
118
|
+
required: false,
|
|
119
|
+
}),
|
|
120
|
+
cookies: Property.Array({
|
|
121
|
+
displayName: 'Cookies',
|
|
122
|
+
description: 'Cookies to set before executing BQL query',
|
|
123
|
+
required: false,
|
|
124
|
+
properties: {
|
|
125
|
+
name: Property.ShortText({
|
|
126
|
+
displayName: 'Cookie Name',
|
|
127
|
+
required: true,
|
|
128
|
+
}),
|
|
129
|
+
value: Property.ShortText({
|
|
130
|
+
displayName: 'Cookie Value',
|
|
131
|
+
required: true,
|
|
132
|
+
}),
|
|
133
|
+
url: Property.ShortText({
|
|
134
|
+
displayName: 'URL',
|
|
135
|
+
description: 'Request-URI to associate with the cookie',
|
|
136
|
+
required: false,
|
|
137
|
+
}),
|
|
138
|
+
domain: Property.ShortText({
|
|
139
|
+
displayName: 'Domain',
|
|
140
|
+
required: false,
|
|
141
|
+
}),
|
|
142
|
+
path: Property.ShortText({
|
|
143
|
+
displayName: 'Path',
|
|
144
|
+
required: false,
|
|
145
|
+
}),
|
|
146
|
+
secure: Property.Checkbox({
|
|
147
|
+
displayName: 'Secure',
|
|
148
|
+
description: 'Indicates if the cookie is secure',
|
|
149
|
+
required: false,
|
|
150
|
+
defaultValue: false,
|
|
151
|
+
}),
|
|
152
|
+
httpOnly: Property.Checkbox({
|
|
153
|
+
displayName: 'HTTP Only',
|
|
154
|
+
description: 'Indicates if the cookie is HTTP-only',
|
|
155
|
+
required: false,
|
|
156
|
+
defaultValue: false,
|
|
157
|
+
}),
|
|
158
|
+
sameSite: Property.StaticDropdown({
|
|
159
|
+
displayName: 'SameSite',
|
|
160
|
+
description: 'SameSite policy for the cookie',
|
|
161
|
+
required: false,
|
|
162
|
+
options: {
|
|
163
|
+
options: [
|
|
164
|
+
{ label: 'Strict', value: 'Strict' },
|
|
165
|
+
{ label: 'Lax', value: 'Lax' },
|
|
166
|
+
{ label: 'None', value: 'None' }
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
}),
|
|
170
|
+
expires: Property.Number({
|
|
171
|
+
displayName: 'Expires',
|
|
172
|
+
description: 'Expiration date as timestamp (session cookie if not set)',
|
|
173
|
+
required: false,
|
|
174
|
+
}),
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
177
|
+
},
|
|
178
|
+
async run(context) {
|
|
179
|
+
const requestBody: any = {
|
|
180
|
+
query: context.propsValue.query,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
if (context.propsValue.variables) {
|
|
184
|
+
requestBody.variables = context.propsValue.variables;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (context.propsValue.operationName) {
|
|
188
|
+
requestBody.operationName = context.propsValue.operationName;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let resourceUri = '/chromium/bql';
|
|
192
|
+
|
|
193
|
+
const queryParams: string[] = [];
|
|
194
|
+
|
|
195
|
+
if (context.propsValue.timeout) {
|
|
196
|
+
queryParams.push(`timeout=${context.propsValue.timeout}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (context.propsValue.stealth !== undefined) {
|
|
200
|
+
queryParams.push(`stealth=${context.propsValue.stealth}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (context.propsValue.headless !== undefined) {
|
|
204
|
+
queryParams.push(`headless=${context.propsValue.headless}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (context.propsValue.humanlike) {
|
|
208
|
+
queryParams.push(`humanlike=true`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (context.propsValue.proxy && context.propsValue.proxy !== 'none') {
|
|
212
|
+
queryParams.push(`proxy=${context.propsValue.proxy}`);
|
|
213
|
+
if (context.propsValue.proxyCountry) {
|
|
214
|
+
queryParams.push(`proxyCountry=${context.propsValue.proxyCountry}`);
|
|
215
|
+
}
|
|
216
|
+
if (context.propsValue.proxySticky) {
|
|
217
|
+
queryParams.push(`proxySticky=true`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (context.propsValue.blockAds) {
|
|
222
|
+
queryParams.push(`blockAds=true`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (context.propsValue.blockConsentModals) {
|
|
226
|
+
queryParams.push(`blockConsentModals=true`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (context.propsValue.record) {
|
|
230
|
+
queryParams.push(`record=true`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (context.propsValue.slowMo) {
|
|
234
|
+
queryParams.push(`slowMo=${context.propsValue.slowMo}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (context.propsValue.ignoreHTTPSErrors) {
|
|
238
|
+
queryParams.push(`ignoreHTTPSErrors=true`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (context.propsValue.userAgent) {
|
|
242
|
+
queryParams.push(`userAgent=${encodeURIComponent(context.propsValue.userAgent)}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (context.propsValue.viewportWidth && context.propsValue.viewportHeight) {
|
|
246
|
+
queryParams.push(`viewport=${context.propsValue.viewportWidth}x${context.propsValue.viewportHeight}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (context.propsValue.cookies && context.propsValue.cookies.length > 0) {
|
|
250
|
+
const cookiesJson = JSON.stringify(context.propsValue.cookies.map((cookie: any) => ({
|
|
251
|
+
name: cookie.name,
|
|
252
|
+
value: cookie.value,
|
|
253
|
+
...(cookie.url && { url: cookie.url }),
|
|
254
|
+
...(cookie.domain && { domain: cookie.domain }),
|
|
255
|
+
...(cookie.path && { path: cookie.path }),
|
|
256
|
+
...(cookie.secure !== undefined && { secure: cookie.secure }),
|
|
257
|
+
...(cookie.httpOnly !== undefined && { httpOnly: cookie.httpOnly }),
|
|
258
|
+
...(cookie.sameSite && { sameSite: cookie.sameSite }),
|
|
259
|
+
...(cookie.expires !== undefined && { expires: cookie.expires })
|
|
260
|
+
})));
|
|
261
|
+
queryParams.push(`cookies=${encodeURIComponent(cookiesJson)}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (queryParams.length > 0) {
|
|
265
|
+
resourceUri += `?${queryParams.join('&')}`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const response = await browserlessCommon.apiCall({
|
|
269
|
+
auth: context.auth.props,
|
|
270
|
+
method: HttpMethod.POST,
|
|
271
|
+
resourceUri,
|
|
272
|
+
body: requestBody,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
let parsedResult;
|
|
276
|
+
try {
|
|
277
|
+
parsedResult = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
parsedResult = response.body;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
success: true,
|
|
284
|
+
data: parsedResult?.data || null,
|
|
285
|
+
errors: parsedResult?.errors || null,
|
|
286
|
+
result: parsedResult,
|
|
287
|
+
metadata: {
|
|
288
|
+
browserType: 'chromium',
|
|
289
|
+
executionTime: response.headers?.['x-response-time'] || 'unknown',
|
|
290
|
+
timestamp: new Date().toISOString(),
|
|
291
|
+
stealth: context.propsValue.stealth || false,
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
},
|
|
295
|
+
});
|