@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,176 @@
|
|
|
1
|
+
import { createAction, Property } from '@agnocon/pieces-framework';
|
|
2
|
+
import { HttpMethod } from '@agnocon/pieces-common';
|
|
3
|
+
import { browserlessAuth } from '../common/auth';
|
|
4
|
+
import { browserlessCommon, convertBinaryToBase64, isBinaryResponse } from '../common/client';
|
|
5
|
+
|
|
6
|
+
export const captureScreenshot = createAction({
|
|
7
|
+
name: 'capture_screenshot',
|
|
8
|
+
displayName: 'Capture Screenshot',
|
|
9
|
+
description: 'Take a screenshot of a web page',
|
|
10
|
+
audience: 'both',
|
|
11
|
+
aiMetadata: { description: 'Renders a web page in a headless browser and returns a PNG or JPEG screenshot of it. Use to capture the visual state of a public URL; the page URL is required, and options like full-page capture, viewport size, clipping region, and waiting for a CSS selector control what is rendered. Not idempotent: each call runs a fresh headless-browser render, so the returned image reflects the live page at the moment of the call.', idempotent: false },
|
|
12
|
+
auth: browserlessAuth,
|
|
13
|
+
props: {
|
|
14
|
+
url: Property.ShortText({
|
|
15
|
+
displayName: 'URL',
|
|
16
|
+
description: 'The URL of the page to capture',
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
imageType: Property.StaticDropdown({
|
|
20
|
+
displayName: 'Image Type',
|
|
21
|
+
description: 'Format of the screenshot image',
|
|
22
|
+
required: false,
|
|
23
|
+
defaultValue: 'png',
|
|
24
|
+
options: {
|
|
25
|
+
options: [
|
|
26
|
+
{ label: 'PNG', value: 'png' },
|
|
27
|
+
{ label: 'JPEG', value: 'jpeg' }
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
quality: Property.Number({
|
|
32
|
+
displayName: 'Quality',
|
|
33
|
+
description: 'Image quality (0-100, only for JPEG)',
|
|
34
|
+
required: false,
|
|
35
|
+
}),
|
|
36
|
+
fullPage: Property.Checkbox({
|
|
37
|
+
displayName: 'Full Page',
|
|
38
|
+
description: 'Capture the full scrollable page',
|
|
39
|
+
required: false,
|
|
40
|
+
defaultValue: false,
|
|
41
|
+
}),
|
|
42
|
+
width: Property.Number({
|
|
43
|
+
displayName: 'Viewport Width',
|
|
44
|
+
description: 'Width of the browser viewport in pixels',
|
|
45
|
+
required: false,
|
|
46
|
+
}),
|
|
47
|
+
height: Property.Number({
|
|
48
|
+
displayName: 'Viewport Height',
|
|
49
|
+
description: 'Height of the browser viewport in pixels',
|
|
50
|
+
required: false,
|
|
51
|
+
}),
|
|
52
|
+
waitForSelector: Property.ShortText({
|
|
53
|
+
displayName: 'Wait for Selector',
|
|
54
|
+
description: 'CSS selector to wait for before taking screenshot',
|
|
55
|
+
required: false,
|
|
56
|
+
}),
|
|
57
|
+
delay: Property.Number({
|
|
58
|
+
displayName: 'Delay (ms)',
|
|
59
|
+
description: 'Delay in milliseconds before taking screenshot',
|
|
60
|
+
required: false,
|
|
61
|
+
}),
|
|
62
|
+
omitBackground: Property.Checkbox({
|
|
63
|
+
displayName: 'Omit Background',
|
|
64
|
+
description: 'Hide default white background for transparent screenshots',
|
|
65
|
+
required: false,
|
|
66
|
+
defaultValue: false,
|
|
67
|
+
}),
|
|
68
|
+
clipX: Property.Number({
|
|
69
|
+
displayName: 'Clip X Position',
|
|
70
|
+
description: 'X coordinate of the top-left corner for clipping',
|
|
71
|
+
required: false,
|
|
72
|
+
}),
|
|
73
|
+
clipY: Property.Number({
|
|
74
|
+
displayName: 'Clip Y Position',
|
|
75
|
+
description: 'Y coordinate of the top-left corner for clipping',
|
|
76
|
+
required: false,
|
|
77
|
+
}),
|
|
78
|
+
clipWidth: Property.Number({
|
|
79
|
+
displayName: 'Clip Width',
|
|
80
|
+
description: 'Width of the clipping area',
|
|
81
|
+
required: false,
|
|
82
|
+
}),
|
|
83
|
+
clipHeight: Property.Number({
|
|
84
|
+
displayName: 'Clip Height',
|
|
85
|
+
description: 'Height of the clipping area',
|
|
86
|
+
required: false,
|
|
87
|
+
}),
|
|
88
|
+
},
|
|
89
|
+
async run(context) {
|
|
90
|
+
const requestBody: any = {
|
|
91
|
+
url: context.propsValue.url,
|
|
92
|
+
options: {
|
|
93
|
+
type: context.propsValue.imageType || 'png',
|
|
94
|
+
fullPage: context.propsValue.fullPage || false,
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (context.propsValue.quality && context.propsValue.imageType === 'jpeg') {
|
|
99
|
+
requestBody.options.quality = context.propsValue.quality;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (context.propsValue.width && context.propsValue.height) {
|
|
103
|
+
requestBody.viewport = {
|
|
104
|
+
width: context.propsValue.width,
|
|
105
|
+
height: context.propsValue.height,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (context.propsValue.waitForSelector) {
|
|
110
|
+
requestBody.waitForSelector = {
|
|
111
|
+
selector: context.propsValue.waitForSelector,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (context.propsValue.delay) {
|
|
116
|
+
requestBody.waitForTimeout = context.propsValue.delay;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (context.propsValue.omitBackground) {
|
|
120
|
+
requestBody.options.omitBackground = context.propsValue.omitBackground;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (context.propsValue.clipX !== undefined &&
|
|
124
|
+
context.propsValue.clipY !== undefined &&
|
|
125
|
+
context.propsValue.clipWidth !== undefined &&
|
|
126
|
+
context.propsValue.clipHeight !== undefined) {
|
|
127
|
+
requestBody.options.clip = {
|
|
128
|
+
x: context.propsValue.clipX,
|
|
129
|
+
y: context.propsValue.clipY,
|
|
130
|
+
width: context.propsValue.clipWidth,
|
|
131
|
+
height: context.propsValue.clipHeight,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const response = await browserlessCommon.apiCall({
|
|
136
|
+
auth: context.auth.props,
|
|
137
|
+
method: HttpMethod.POST,
|
|
138
|
+
resourceUri: '/screenshot',
|
|
139
|
+
body: requestBody,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const imageType = context.propsValue.imageType || 'png';
|
|
143
|
+
const fileName = `screenshot.${imageType}`;
|
|
144
|
+
|
|
145
|
+
let fileData: Buffer;
|
|
146
|
+
|
|
147
|
+
if (response.body instanceof ArrayBuffer) {
|
|
148
|
+
fileData = Buffer.from(response.body);
|
|
149
|
+
} else if (Buffer.isBuffer(response.body)) {
|
|
150
|
+
fileData = response.body;
|
|
151
|
+
} else if (typeof response.body === 'string') {
|
|
152
|
+
fileData = Buffer.from(response.body, 'latin1');
|
|
153
|
+
} else {
|
|
154
|
+
fileData = Buffer.from(String(response.body), 'latin1');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const file = await context.files.write({
|
|
158
|
+
data: fileData,
|
|
159
|
+
fileName: fileName,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
success: true,
|
|
164
|
+
file: file,
|
|
165
|
+
screenshotBase64: convertBinaryToBase64(fileData),
|
|
166
|
+
metadata: {
|
|
167
|
+
url: context.propsValue.url,
|
|
168
|
+
type: imageType,
|
|
169
|
+
fullPage: context.propsValue.fullPage || false,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
contentType: response.headers?.['content-type'] || `image/${imageType}`,
|
|
172
|
+
fileName: fileName,
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
});
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { createAction, Property } from '@agnocon/pieces-framework';
|
|
2
|
+
import { HttpMethod } from '@agnocon/pieces-common';
|
|
3
|
+
import { browserlessAuth } from '../common/auth';
|
|
4
|
+
import { browserlessCommon, convertBinaryToBase64 } from '../common/client';
|
|
5
|
+
|
|
6
|
+
export const generatePdf = createAction({
|
|
7
|
+
name: 'generate_pdf',
|
|
8
|
+
displayName: 'Generate PDF',
|
|
9
|
+
description: 'Convert a web page to PDF',
|
|
10
|
+
audience: 'both',
|
|
11
|
+
aiMetadata: { description: 'Renders content in a headless browser and returns it as a PDF file. Source the content either from a page URL or from a raw HTML string (provide exactly one, not both). Use to produce a printable PDF of a page or supplied markup, with control over paper format, orientation, margins, and headers/footers. Not idempotent: each call runs a fresh headless-browser render, so repeating it produces a new PDF of the page or markup as it renders at that moment.', idempotent: false },
|
|
12
|
+
auth: browserlessAuth,
|
|
13
|
+
props: {
|
|
14
|
+
url: Property.ShortText({
|
|
15
|
+
displayName: 'URL',
|
|
16
|
+
description: 'The URL of the page to convert to PDF',
|
|
17
|
+
required: false,
|
|
18
|
+
}),
|
|
19
|
+
html: Property.LongText({
|
|
20
|
+
displayName: 'HTML Content',
|
|
21
|
+
description: 'HTML content to render as PDF (alternative to URL)',
|
|
22
|
+
required: false,
|
|
23
|
+
}),
|
|
24
|
+
format: Property.StaticDropdown({
|
|
25
|
+
displayName: 'Paper Format',
|
|
26
|
+
description: 'Paper format for the PDF',
|
|
27
|
+
required: false,
|
|
28
|
+
defaultValue: 'A4',
|
|
29
|
+
options: {
|
|
30
|
+
options: [
|
|
31
|
+
{ label: 'A0', value: 'A0' },
|
|
32
|
+
{ label: 'A1', value: 'A1' },
|
|
33
|
+
{ label: 'A2', value: 'A2' },
|
|
34
|
+
{ label: 'A3', value: 'A3' },
|
|
35
|
+
{ label: 'A4', value: 'A4' },
|
|
36
|
+
{ label: 'A5', value: 'A5' },
|
|
37
|
+
{ label: 'A6', value: 'A6' },
|
|
38
|
+
{ label: 'Letter', value: 'Letter' },
|
|
39
|
+
{ label: 'Legal', value: 'Legal' },
|
|
40
|
+
{ label: 'Ledger', value: 'Ledger' },
|
|
41
|
+
{ label: 'Tabloid', value: 'Tabloid' }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
landscape: Property.Checkbox({
|
|
46
|
+
displayName: 'Landscape',
|
|
47
|
+
description: 'Use landscape orientation',
|
|
48
|
+
required: false,
|
|
49
|
+
defaultValue: false,
|
|
50
|
+
}),
|
|
51
|
+
printBackground: Property.Checkbox({
|
|
52
|
+
displayName: 'Print Background',
|
|
53
|
+
description: 'Include background graphics',
|
|
54
|
+
required: false,
|
|
55
|
+
defaultValue: true,
|
|
56
|
+
}),
|
|
57
|
+
marginTop: Property.ShortText({
|
|
58
|
+
displayName: 'Top Margin',
|
|
59
|
+
description: 'Top margin (e.g., "10mm", "0.4in")',
|
|
60
|
+
required: false,
|
|
61
|
+
}),
|
|
62
|
+
marginRight: Property.ShortText({
|
|
63
|
+
displayName: 'Right Margin',
|
|
64
|
+
description: 'Right margin (e.g., "10mm", "0.4in")',
|
|
65
|
+
required: false,
|
|
66
|
+
}),
|
|
67
|
+
marginBottom: Property.ShortText({
|
|
68
|
+
displayName: 'Bottom Margin',
|
|
69
|
+
description: 'Bottom margin (e.g., "10mm", "0.4in")',
|
|
70
|
+
required: false,
|
|
71
|
+
}),
|
|
72
|
+
marginLeft: Property.ShortText({
|
|
73
|
+
displayName: 'Left Margin',
|
|
74
|
+
description: 'Left margin (e.g., "10mm", "0.4in")',
|
|
75
|
+
required: false,
|
|
76
|
+
}),
|
|
77
|
+
headerTemplate: Property.LongText({
|
|
78
|
+
displayName: 'Header Template',
|
|
79
|
+
description: 'HTML template for the print header',
|
|
80
|
+
required: false,
|
|
81
|
+
}),
|
|
82
|
+
footerTemplate: Property.LongText({
|
|
83
|
+
displayName: 'Footer Template',
|
|
84
|
+
description: 'HTML template for the print footer',
|
|
85
|
+
required: false,
|
|
86
|
+
}),
|
|
87
|
+
displayHeaderFooter: Property.Checkbox({
|
|
88
|
+
displayName: 'Display Header/Footer',
|
|
89
|
+
description: 'Display header and footer',
|
|
90
|
+
required: false,
|
|
91
|
+
defaultValue: false,
|
|
92
|
+
}),
|
|
93
|
+
scale: Property.Number({
|
|
94
|
+
displayName: 'Scale',
|
|
95
|
+
description: 'Scale of the webpage rendering (0.1 - 2.0)',
|
|
96
|
+
required: false,
|
|
97
|
+
}),
|
|
98
|
+
waitForSelector: Property.ShortText({
|
|
99
|
+
displayName: 'Wait for Selector',
|
|
100
|
+
description: 'CSS selector to wait for before generating PDF',
|
|
101
|
+
required: false,
|
|
102
|
+
}),
|
|
103
|
+
waitForSelectorTimeout: Property.Number({
|
|
104
|
+
displayName: 'Wait for Selector Timeout',
|
|
105
|
+
description: 'Timeout in milliseconds for waiting for selector',
|
|
106
|
+
required: false,
|
|
107
|
+
}),
|
|
108
|
+
waitForSelectorVisible: Property.Checkbox({
|
|
109
|
+
displayName: 'Wait for Selector Visible',
|
|
110
|
+
description: 'Wait for selector to be visible',
|
|
111
|
+
required: false,
|
|
112
|
+
defaultValue: true,
|
|
113
|
+
}),
|
|
114
|
+
waitForSelectorHidden: Property.Checkbox({
|
|
115
|
+
displayName: 'Wait for Selector Hidden',
|
|
116
|
+
description: 'Wait for selector to be hidden',
|
|
117
|
+
required: false,
|
|
118
|
+
defaultValue: false,
|
|
119
|
+
}),
|
|
120
|
+
preferCSSPageSize: Property.Checkbox({
|
|
121
|
+
displayName: 'Prefer CSS Page Size',
|
|
122
|
+
description: 'Give any CSS @page size declared in the page priority over format',
|
|
123
|
+
required: false,
|
|
124
|
+
defaultValue: false,
|
|
125
|
+
}),
|
|
126
|
+
pageRanges: Property.ShortText({
|
|
127
|
+
displayName: 'Page Ranges',
|
|
128
|
+
description: 'Paper ranges to print, e.g. "1-5, 8, 11-13"',
|
|
129
|
+
required: false,
|
|
130
|
+
}),
|
|
131
|
+
width: Property.ShortText({
|
|
132
|
+
displayName: 'Custom Width',
|
|
133
|
+
description: 'Custom width of paper (e.g., "8.5in", "210mm")',
|
|
134
|
+
required: false,
|
|
135
|
+
}),
|
|
136
|
+
height: Property.ShortText({
|
|
137
|
+
displayName: 'Custom Height',
|
|
138
|
+
description: 'Custom height of paper (e.g., "11in", "297mm")',
|
|
139
|
+
required: false,
|
|
140
|
+
}),
|
|
141
|
+
omitBackground: Property.Checkbox({
|
|
142
|
+
displayName: 'Omit Background',
|
|
143
|
+
description: 'Hide default white background and allow transparent PDFs',
|
|
144
|
+
required: false,
|
|
145
|
+
defaultValue: false,
|
|
146
|
+
}),
|
|
147
|
+
tagged: Property.Checkbox({
|
|
148
|
+
displayName: 'Tagged PDF',
|
|
149
|
+
description: 'Generate tagged (accessible) PDF',
|
|
150
|
+
required: false,
|
|
151
|
+
defaultValue: false,
|
|
152
|
+
}),
|
|
153
|
+
outline: Property.Checkbox({
|
|
154
|
+
displayName: 'Generate Outline',
|
|
155
|
+
description: 'Generate document outline',
|
|
156
|
+
required: false,
|
|
157
|
+
defaultValue: false,
|
|
158
|
+
}),
|
|
159
|
+
timeout: Property.Number({
|
|
160
|
+
displayName: 'Timeout (ms)',
|
|
161
|
+
description: 'Maximum time to wait for the page to load',
|
|
162
|
+
required: false,
|
|
163
|
+
}),
|
|
164
|
+
waitForFunction: Property.LongText({
|
|
165
|
+
displayName: 'Wait for Function',
|
|
166
|
+
description: 'JavaScript function to wait for before generating PDF',
|
|
167
|
+
required: false,
|
|
168
|
+
}),
|
|
169
|
+
waitForFunctionPolling: Property.ShortText({
|
|
170
|
+
displayName: 'Wait for Function Polling',
|
|
171
|
+
description: 'Polling interval for wait function ("raf", "mutation", or number in ms)',
|
|
172
|
+
required: false,
|
|
173
|
+
}),
|
|
174
|
+
waitForFunctionTimeout: Property.Number({
|
|
175
|
+
displayName: 'Wait for Function Timeout',
|
|
176
|
+
description: 'Timeout in milliseconds for wait function (0 to disable)',
|
|
177
|
+
required: false,
|
|
178
|
+
}),
|
|
179
|
+
userAgent: Property.ShortText({
|
|
180
|
+
displayName: 'User Agent',
|
|
181
|
+
description: 'Custom user agent string to use for the request',
|
|
182
|
+
required: false,
|
|
183
|
+
}),
|
|
184
|
+
waitForTimeout: Property.Number({
|
|
185
|
+
displayName: 'Wait Timeout (ms)',
|
|
186
|
+
description: 'Timeout in milliseconds to wait before generating PDF',
|
|
187
|
+
required: false,
|
|
188
|
+
}),
|
|
189
|
+
bestAttempt: Property.Checkbox({
|
|
190
|
+
displayName: 'Best Attempt',
|
|
191
|
+
description: 'Attempt to proceed when awaited events fail or timeout',
|
|
192
|
+
required: false,
|
|
193
|
+
defaultValue: false,
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
async run(context) {
|
|
197
|
+
if (!context.propsValue.url && !context.propsValue.html) {
|
|
198
|
+
throw new Error('Either URL or HTML content must be provided');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (context.propsValue.url && context.propsValue.html) {
|
|
202
|
+
throw new Error('Cannot provide both URL and HTML content. Choose one.');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const requestBody: any = {
|
|
206
|
+
options: {
|
|
207
|
+
format: context.propsValue.format || 'A4',
|
|
208
|
+
landscape: context.propsValue.landscape || false,
|
|
209
|
+
printBackground: context.propsValue.printBackground !== false,
|
|
210
|
+
displayHeaderFooter: context.propsValue.displayHeaderFooter || false,
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
if (context.propsValue.url) {
|
|
215
|
+
requestBody.url = context.propsValue.url;
|
|
216
|
+
} else if (context.propsValue.html) {
|
|
217
|
+
requestBody.html = context.propsValue.html;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (context.propsValue.userAgent) {
|
|
221
|
+
requestBody.userAgent = context.propsValue.userAgent;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (context.propsValue.waitForTimeout) {
|
|
225
|
+
requestBody.waitForTimeout = context.propsValue.waitForTimeout;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (context.propsValue.bestAttempt) {
|
|
229
|
+
requestBody.bestAttempt = context.propsValue.bestAttempt;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const margin: any = {};
|
|
233
|
+
if (context.propsValue.marginTop) margin.top = context.propsValue.marginTop;
|
|
234
|
+
if (context.propsValue.marginRight) margin.right = context.propsValue.marginRight;
|
|
235
|
+
if (context.propsValue.marginBottom) margin.bottom = context.propsValue.marginBottom;
|
|
236
|
+
if (context.propsValue.marginLeft) margin.left = context.propsValue.marginLeft;
|
|
237
|
+
|
|
238
|
+
if (Object.keys(margin).length > 0) {
|
|
239
|
+
requestBody.options.margin = margin;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (context.propsValue.headerTemplate) {
|
|
243
|
+
requestBody.options.headerTemplate = context.propsValue.headerTemplate;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (context.propsValue.footerTemplate) {
|
|
247
|
+
requestBody.options.footerTemplate = context.propsValue.footerTemplate;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (context.propsValue.scale) {
|
|
251
|
+
requestBody.options.scale = Math.max(0.1, Math.min(2.0, context.propsValue.scale));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (context.propsValue.waitForSelector) {
|
|
255
|
+
const waitForSelectorObj: any = {
|
|
256
|
+
selector: context.propsValue.waitForSelector,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
if (context.propsValue.waitForSelectorTimeout !== undefined) {
|
|
260
|
+
waitForSelectorObj.timeout = context.propsValue.waitForSelectorTimeout;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (context.propsValue.waitForSelectorVisible !== undefined) {
|
|
264
|
+
waitForSelectorObj.visible = context.propsValue.waitForSelectorVisible;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (context.propsValue.waitForSelectorHidden !== undefined) {
|
|
268
|
+
waitForSelectorObj.hidden = context.propsValue.waitForSelectorHidden;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
requestBody.options.waitForSelector = waitForSelectorObj;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (context.propsValue.preferCSSPageSize) {
|
|
275
|
+
requestBody.options.preferCSSPageSize = context.propsValue.preferCSSPageSize;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (context.propsValue.pageRanges) {
|
|
279
|
+
requestBody.options.pageRanges = context.propsValue.pageRanges;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (context.propsValue.width) {
|
|
283
|
+
requestBody.options.width = context.propsValue.width;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (context.propsValue.height) {
|
|
287
|
+
requestBody.options.height = context.propsValue.height;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (context.propsValue.omitBackground) {
|
|
291
|
+
requestBody.options.omitBackground = context.propsValue.omitBackground;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (context.propsValue.tagged) {
|
|
295
|
+
requestBody.options.tagged = context.propsValue.tagged;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (context.propsValue.outline) {
|
|
299
|
+
requestBody.options.outline = context.propsValue.outline;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (context.propsValue.timeout) {
|
|
303
|
+
requestBody.options.timeout = context.propsValue.timeout;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (context.propsValue.waitForFunction) {
|
|
307
|
+
const waitForFunctionObj: any = {
|
|
308
|
+
fn: context.propsValue.waitForFunction,
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
if (context.propsValue.waitForFunctionPolling !== undefined) {
|
|
312
|
+
waitForFunctionObj.polling = context.propsValue.waitForFunctionPolling;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (context.propsValue.waitForFunctionTimeout !== undefined) {
|
|
316
|
+
waitForFunctionObj.timeout = context.propsValue.waitForFunctionTimeout;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
requestBody.options.waitForFunction = waitForFunctionObj;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const response = await browserlessCommon.apiCall({
|
|
323
|
+
auth: context.auth.props,
|
|
324
|
+
method: HttpMethod.POST,
|
|
325
|
+
resourceUri: '/pdf',
|
|
326
|
+
body: requestBody,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const fileName = 'document.pdf';
|
|
330
|
+
|
|
331
|
+
let fileData: Buffer;
|
|
332
|
+
|
|
333
|
+
if (response.body instanceof ArrayBuffer) {
|
|
334
|
+
fileData = Buffer.from(response.body);
|
|
335
|
+
} else if (Buffer.isBuffer(response.body)) {
|
|
336
|
+
fileData = response.body;
|
|
337
|
+
} else if (typeof response.body === 'string') {
|
|
338
|
+
fileData = Buffer.from(response.body, 'latin1');
|
|
339
|
+
} else {
|
|
340
|
+
fileData = Buffer.from(String(response.body), 'latin1');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const file = await context.files.write({
|
|
344
|
+
data: fileData,
|
|
345
|
+
fileName: fileName,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
success: true,
|
|
350
|
+
file: file,
|
|
351
|
+
pdfBase64: convertBinaryToBase64(fileData),
|
|
352
|
+
metadata: {
|
|
353
|
+
source: context.propsValue.url ? 'url' : 'html',
|
|
354
|
+
url: context.propsValue.url || null,
|
|
355
|
+
hasHtml: !!context.propsValue.html,
|
|
356
|
+
format: context.propsValue.format || 'A4',
|
|
357
|
+
landscape: context.propsValue.landscape || false,
|
|
358
|
+
timestamp: new Date().toISOString(),
|
|
359
|
+
fileName: fileName,
|
|
360
|
+
contentType: 'application/pdf',
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
});
|