Initial commit
This commit is contained in:
107
templates/screenshot-with-kv-cache.ts
Normal file
107
templates/screenshot-with-kv-cache.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
// Screenshot with KV Caching
|
||||
// Production-ready screenshot service with KV caching to reduce browser usage
|
||||
|
||||
import puppeteer from "@cloudflare/puppeteer";
|
||||
|
||||
interface Env {
|
||||
MYBROWSER: Fetcher;
|
||||
SCREENSHOT_CACHE: KVNamespace;
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request: Request, env: Env): Promise<Response> {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const url = searchParams.get("url");
|
||||
const refresh = searchParams.get("refresh") === "true";
|
||||
|
||||
if (!url) {
|
||||
return new Response("Missing ?url parameter", { status: 400 });
|
||||
}
|
||||
|
||||
const normalizedUrl = new URL(url).toString();
|
||||
|
||||
// Check cache (unless refresh requested)
|
||||
if (!refresh) {
|
||||
const cached = await env.SCREENSHOT_CACHE.get(normalizedUrl, {
|
||||
type: "arrayBuffer",
|
||||
});
|
||||
|
||||
if (cached) {
|
||||
return new Response(cached, {
|
||||
headers: {
|
||||
"content-type": "image/png",
|
||||
"x-cache": "HIT",
|
||||
"cache-control": "public, max-age=3600",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Generate screenshot
|
||||
const browser = await puppeteer.launch(env.MYBROWSER);
|
||||
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto(normalizedUrl, {
|
||||
waitUntil: "networkidle0",
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
const screenshot = await page.screenshot({
|
||||
fullPage: true,
|
||||
type: "png",
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
|
||||
// Cache for 24 hours
|
||||
await env.SCREENSHOT_CACHE.put(normalizedUrl, screenshot, {
|
||||
expirationTtl: 60 * 60 * 24, // 24 hours
|
||||
});
|
||||
|
||||
return new Response(screenshot, {
|
||||
headers: {
|
||||
"content-type": "image/png",
|
||||
"x-cache": "MISS",
|
||||
"cache-control": "public, max-age=3600",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
await browser.close();
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
error: error instanceof Error ? error.message : "Screenshot failed",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup:
|
||||
* 1. Create KV namespace:
|
||||
* npx wrangler kv namespace create SCREENSHOT_CACHE
|
||||
* npx wrangler kv namespace create SCREENSHOT_CACHE --preview
|
||||
*
|
||||
* 2. Add to wrangler.jsonc:
|
||||
* {
|
||||
* "browser": { "binding": "MYBROWSER" },
|
||||
* "compatibility_flags": ["nodejs_compat"],
|
||||
* "kv_namespaces": [
|
||||
* {
|
||||
* "binding": "SCREENSHOT_CACHE",
|
||||
* "id": "YOUR_KV_ID",
|
||||
* "preview_id": "YOUR_PREVIEW_ID"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* Usage:
|
||||
* New screenshot: ?url=https://example.com
|
||||
* Force refresh: ?url=https://example.com&refresh=true
|
||||
*/
|
||||
Reference in New Issue
Block a user