cloudflare-browser-rendering-mcp
by amotivv
Verified
- src
import axios from 'axios';
/**
* Client for interacting with Cloudflare Browser Rendering
*/
export class BrowserClient {
private apiEndpoint: string;
constructor() {
// Use the Cloudflare Worker endpoint from environment variable
if (!process.env.BROWSER_RENDERING_API) {
console.error('[Setup] BROWSER_RENDERING_API environment variable is not set. Please set it to your Cloudflare Worker URL.');
}
this.apiEndpoint = process.env.BROWSER_RENDERING_API || 'https://your-browser-rendering-api.workers.dev';
console.error(`[Setup] Initialized BrowserClient with endpoint: ${this.apiEndpoint}`);
}
/**
* Fetches rendered HTML content from a URL
* @param url The URL to fetch content from
* @returns The rendered HTML content
*/
async fetchContent(url: string): Promise<string> {
try {
console.error(`[API] Fetching content from: ${url}`);
// Make the API call to the Cloudflare Worker
const response = await axios.post(`${this.apiEndpoint}/content`, {
url,
rejectResourceTypes: ['image', 'font', 'media'],
waitUntil: 'networkidle0',
});
// Check if the response has the expected structure
if (response.data && response.data.content) {
return response.data.content;
}
// If we can't find the content, log the response and throw an error
console.error('[Error] Unexpected response structure:', JSON.stringify(response.data, null, 2));
throw new Error('Unexpected response structure from Cloudflare Worker');
} catch (error: any) {
console.error('[Error] Error fetching content:', error);
// Log more detailed error information if available
if (error.response) {
console.error('[Error] Response status:', error.response.status);
console.error('[Error] Response data:', JSON.stringify(error.response.data, null, 2));
}
throw new Error(`Failed to fetch content: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Takes a screenshot of a URL
* @param url The URL to take a screenshot of
* @param options Optional screenshot parameters
* @returns The URL to the screenshot
*/
async takeScreenshot(url: string, options: {
width?: number;
height?: number;
fullPage?: boolean;
waitUntil?: string;
timeout?: number;
} = {}): Promise<string> {
try {
console.error(`[API] Taking screenshot of: ${url}`);
// Validate URL before sending
try {
new URL(url); // Will throw if URL is invalid
} catch (e) {
throw new Error(`Invalid URL provided: ${url}`);
}
// Add timeout for the request
const requestTimeout = options.timeout || 30000;
// Make the API call to the Cloudflare Worker with timeout
const response = await axios.post(`${this.apiEndpoint}/screenshot`, {
url,
width: options.width || 1280,
height: options.height || 800,
fullPage: options.fullPage || false,
waitUntil: options.waitUntil || 'networkidle0',
timeout: requestTimeout,
}, {
timeout: requestTimeout + 5000, // Add 5 seconds to the request timeout
});
// Check if the response has the expected structure with a URL
if (response.data && response.data.url) {
// Validate the returned URL
try {
new URL(response.data.url);
return response.data.url;
} catch (e) {
throw new Error(`Invalid screenshot URL returned: ${response.data.url}`);
}
}
// If we can't find the URL, log the response and throw an error
console.error('[Error] Unexpected response structure:', JSON.stringify(response.data, null, 2));
throw new Error('Screenshot URL not found in Cloudflare Worker response');
} catch (error: any) {
console.error('[Error] Error taking screenshot:', error);
// If API is unavailable, throw an error
if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND' || !process.env.BROWSER_RENDERING_API) {
console.error('[Error] Cloudflare worker API is unavailable or not configured');
throw new Error('Cloudflare worker API is unavailable or not configured. Please check your BROWSER_RENDERING_API environment variable.');
}
// Handle timeout errors specifically
if (error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT' || error.message?.includes('timeout')) {
throw new Error(`Screenshot request timed out for URL: ${url}. Try increasing the timeout value.`);
}
// Log more detailed error information if available
if (error.response) {
console.error('[Error] Response status:', error.response.status);
console.error('[Error] Response data:', JSON.stringify(error.response.data, null, 2));
}
throw new Error(`Failed to take screenshot: ${error instanceof Error ? error.message : String(error)}`);
}
}
}