Add js parameter for custom JavaScript injection
- Add js parameter to ScreenshotOptions interface (max 5000 chars) - Execute JavaScript via page.evaluate() after delay, before CSS/hideSelectors - 5-second timeout with JS_TIMEOUT error handling - JS_EXECUTION_ERROR for script failures with sanitized error messages - Support in both GET and POST endpoints with validation - Updated OpenAPI spec for both GET and POST routes - Added comprehensive test coverage (service + route layers) - Updated SDK documentation (Node.js and Python) with examples Test results: 414 tests passing (includes new JS injection tests)
This commit is contained in:
parent
ba888bb580
commit
91a08bab70
6 changed files with 572 additions and 3 deletions
|
|
@ -80,6 +80,16 @@ export const screenshotRouter = Router();
|
|||
* maxLength: 5000
|
||||
* description: Custom CSS to inject into the page before capture (max 5000 chars)
|
||||
* example: "body { background: #1a1a2e !important; color: #eee !important }"
|
||||
* js:
|
||||
* type: string
|
||||
* maxLength: 5000
|
||||
* description: Custom JavaScript code to execute on the page before capture (max 5000 chars, 5-second timeout)
|
||||
* example: "document.querySelector('.modal').remove(); window.scrollTo(0, 500);"
|
||||
* selector:
|
||||
* type: string
|
||||
* maxLength: 200
|
||||
* description: CSS selector for element to capture instead of full page/viewport (max 200 chars)
|
||||
* example: "#main-content"
|
||||
* hideSelectors:
|
||||
* oneOf:
|
||||
* - type: string
|
||||
|
|
@ -246,6 +256,13 @@ export const screenshotRouter = Router();
|
|||
* maxLength: 5000
|
||||
* description: Custom CSS to inject into the page before capture (max 5000 chars)
|
||||
* example: "body { background: #1a1a2e !important }"
|
||||
* - name: js
|
||||
* in: query
|
||||
* schema:
|
||||
* type: string
|
||||
* maxLength: 5000
|
||||
* description: Custom JavaScript code to execute on the page before capture (max 5000 chars, 5-second timeout)
|
||||
* example: "document.querySelector('.modal').remove();"
|
||||
* - name: darkMode
|
||||
* in: query
|
||||
* schema:
|
||||
|
|
@ -331,6 +348,8 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
darkMode,
|
||||
hideSelectors,
|
||||
css,
|
||||
js,
|
||||
selector,
|
||||
} = source;
|
||||
|
||||
if (!url || typeof url !== "string") {
|
||||
|
|
@ -344,6 +363,12 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Validate js parameter
|
||||
if (js && typeof js === 'string' && js.length > 5000) {
|
||||
res.status(400).json({ error: "js: maximum 5000 characters allowed" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize hideSelectors: string | string[] → string[]
|
||||
let normalizedHideSelectors: string[] | undefined;
|
||||
if (hideSelectors) {
|
||||
|
|
@ -366,6 +391,12 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check mutual exclusivity of selector and fullPage
|
||||
if (selector && (fullPage === true || fullPage === "true")) {
|
||||
res.status(400).json({ error: "selector and fullPage are mutually exclusive" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalize parameters
|
||||
const params = {
|
||||
url,
|
||||
|
|
@ -382,6 +413,8 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
darkMode: darkMode === true || darkMode === "true",
|
||||
hideSelectors: normalizedHideSelectors,
|
||||
css: css || undefined,
|
||||
js: js || undefined,
|
||||
selector: selector || undefined,
|
||||
};
|
||||
|
||||
try {
|
||||
|
|
@ -423,7 +456,11 @@ async function handleScreenshotRequest(req: any, res: any) {
|
|||
res.status(504).json({ error: "Screenshot timed out. The page may be too slow to load." });
|
||||
return;
|
||||
}
|
||||
if (err.message.includes("blocked") || err.message.includes("not allowed") || err.message.includes("Invalid URL") || err.message.includes("Could not resolve")) {
|
||||
if (err.message === "SELECTOR_NOT_FOUND") {
|
||||
res.status(400).json({ error: `Element not found: ${selector}` });
|
||||
return;
|
||||
}
|
||||
if (err.message.includes("blocked") || err.message.includes("not allowed") || err.message.includes("Invalid URL") || err.message.includes("Could not resolve") || err.message.includes("JS_EXECUTION_ERROR")) {
|
||||
res.status(400).json({ error: err.message });
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue