feat: initial codebase v0.4.1
Some checks failed
Deploy to Staging / build-and-deploy (push) Failing after 9m44s

- Extract complete codebase from running staging pod
- Add Dockerfile with multi-stage build for Node.js + Puppeteer
- Configure CI/CD workflows for staging and production deployment
- Include all source files, configs, and public assets
This commit is contained in:
OpenClaw DevOps 2026-02-19 17:05:16 +00:00
commit b58f634318
28 changed files with 5669 additions and 0 deletions

View file

@ -0,0 +1,74 @@
import { Page } from "puppeteer";
import { acquirePage, releasePage } from "./browser.js";
import { validateUrl } from "./ssrf.js";
import logger from "./logger.js";
export interface ScreenshotOptions {
url: string;
format?: "png" | "jpeg" | "webp";
width?: number;
height?: number;
fullPage?: boolean;
quality?: number;
waitForSelector?: string;
deviceScale?: number;
delay?: number;
}
export interface ScreenshotResult {
buffer: Buffer;
contentType: string;
}
const MAX_WIDTH = 3840;
const MAX_HEIGHT = 2160;
const TIMEOUT_MS = 30_000;
export async function takeScreenshot(opts: ScreenshotOptions): Promise<ScreenshotResult> {
// Validate URL for SSRF
await validateUrl(opts.url);
const format = opts.format || "png";
const width = Math.min(opts.width || 1280, MAX_WIDTH);
const height = Math.min(opts.height || 800, MAX_HEIGHT);
const fullPage = opts.fullPage ?? false;
const quality = format === "png" ? undefined : Math.min(Math.max(opts.quality || 80, 1), 100);
const deviceScale = Math.min(opts.deviceScale || 1, 3);
const { page, instance } = await acquirePage();
try {
await page.setViewport({ width, height, deviceScaleFactor: deviceScale });
await Promise.race([
(async () => {
await page.goto(opts.url, { waitUntil: "networkidle2", timeout: 20_000 });
if (opts.waitForSelector) {
await page.waitForSelector(opts.waitForSelector, { timeout: 10_000 });
}
if (opts.delay && opts.delay > 0) {
await new Promise(r => setTimeout(r, Math.min(opts.delay!, 5000)));
}
})(),
new Promise<never>((_, reject) => setTimeout(() => reject(new Error("SCREENSHOT_TIMEOUT")), TIMEOUT_MS)),
]);
const screenshotOpts: any = {
type: format === "webp" ? "webp" : format,
fullPage,
encoding: "binary",
};
if (quality !== undefined) screenshotOpts.quality = quality;
const result = await page.screenshot(screenshotOpts);
const buffer = Buffer.from(result as unknown as ArrayBuffer);
const contentType = format === "png" ? "image/png" : format === "jpeg" ? "image/jpeg" : "image/webp";
return { buffer, contentType };
} finally {
releasePage(page, instance);
}
}