update vercel sandbox support
This commit is contained in:
@@ -5,7 +5,7 @@ import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
||||
import { generateObject } from 'ai';
|
||||
import { z } from 'zod';
|
||||
import type { FileManifest } from '@/types/file-manifest';
|
||||
// import type { FileManifest } from '@/types/file-manifest'; // Type is used implicitly through manifest parameter
|
||||
|
||||
// Check if we're using Vercel AI Gateway
|
||||
const isUsingAIGateway = !!process.env.AI_GATEWAY_API_KEY;
|
||||
@@ -76,7 +76,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Create a summary of available files for the AI
|
||||
const validFiles = Object.entries(manifest.files as Record<string, any>)
|
||||
.filter(([path, info]) => {
|
||||
.filter(([path, _info]) => {
|
||||
// Filter out invalid paths
|
||||
return path.includes('.') && !path.match(/\/\d+$/);
|
||||
});
|
||||
@@ -84,7 +84,7 @@ export async function POST(request: NextRequest) {
|
||||
const fileSummary = validFiles
|
||||
.map(([path, info]: [string, any]) => {
|
||||
const componentName = info.componentInfo?.name || path.split('/').pop();
|
||||
const hasImports = info.imports?.length > 0;
|
||||
// const hasImports = info.imports?.length > 0; // Kept for future use
|
||||
const childComponents = info.componentInfo?.childComponents?.join(', ') || 'none';
|
||||
return `- ${path} (${componentName}, renders: ${childComponents})`;
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { Sandbox } from '@e2b/code-interpreter';
|
||||
// Sandbox import not needed - using global sandbox from sandbox-manager
|
||||
import type { SandboxState } from '@/types/sandbox';
|
||||
import type { ConversationState } from '@/types/conversation';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
declare global {
|
||||
var conversationState: ConversationState | null;
|
||||
@@ -294,45 +295,48 @@ export async function POST(request: NextRequest) {
|
||||
global.existingFiles = new Set<string>();
|
||||
}
|
||||
|
||||
// First, always check the global state for active provider
|
||||
let provider = global.activeSandboxProvider;
|
||||
// Try to get provider from sandbox manager first
|
||||
let provider = sandboxId ? sandboxManager.getProvider(sandboxId) : sandboxManager.getActiveProvider();
|
||||
|
||||
// Fall back to global state if not found in manager
|
||||
if (!provider) {
|
||||
provider = global.activeSandboxProvider;
|
||||
}
|
||||
|
||||
// If we don't have a provider in this instance but we have a sandboxId,
|
||||
// try to use the existing sandbox data or create a new one
|
||||
// If we have a sandboxId but no provider, try to get or create one
|
||||
if (!provider && sandboxId) {
|
||||
console.log(`[apply-ai-code-stream] Provider not in this instance for sandbox ${sandboxId}, checking existing data...`);
|
||||
|
||||
// If we have sandbox data but no provider, we'll create a new provider
|
||||
// E2B doesn't support reconnection like Vercel does
|
||||
if (global.sandboxData && global.sandboxData.sandboxId === sandboxId) {
|
||||
console.log(`[apply-ai-code-stream] Creating new provider for existing sandbox ${sandboxId}`);
|
||||
|
||||
// Create a new provider instance (this will create a new sandbox since E2B doesn't support reconnection)
|
||||
try {
|
||||
const { SandboxFactory } = await import('@/lib/sandbox/factory');
|
||||
provider = SandboxFactory.create();
|
||||
console.log(`[apply-ai-code-stream] No provider found for sandbox ${sandboxId}, attempting to get or create...`);
|
||||
|
||||
try {
|
||||
provider = await sandboxManager.getOrCreateProvider(sandboxId);
|
||||
|
||||
// If we got a new provider (not reconnected), we need to create a new sandbox
|
||||
if (!provider.getSandboxInfo()) {
|
||||
console.log(`[apply-ai-code-stream] Creating new sandbox since reconnection failed for ${sandboxId}`);
|
||||
await provider.createSandbox();
|
||||
|
||||
// Update the global state
|
||||
global.activeSandboxProvider = provider;
|
||||
console.log(`[apply-ai-code-stream] Created new provider for sandbox ${sandboxId}`);
|
||||
} catch (providerError) {
|
||||
console.error(`[apply-ai-code-stream] Failed to create provider for sandbox ${sandboxId}:`, providerError);
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to create sandbox provider for ${sandboxId}. The sandbox may have expired.`,
|
||||
results: {
|
||||
filesCreated: [],
|
||||
packagesInstalled: [],
|
||||
commandsExecuted: [],
|
||||
errors: [`Sandbox provider creation failed: ${(providerError as Error).message}`]
|
||||
},
|
||||
explanation: parsed.explanation,
|
||||
structure: parsed.structure,
|
||||
parsedFiles: parsed.files,
|
||||
message: `Parsed ${parsed.files.length} files but couldn't apply them - sandbox reconnection failed.`
|
||||
}, { status: 500 });
|
||||
await provider.setupViteApp();
|
||||
sandboxManager.registerSandbox(sandboxId, provider);
|
||||
}
|
||||
|
||||
// Update legacy global state
|
||||
global.activeSandboxProvider = provider;
|
||||
console.log(`[apply-ai-code-stream] Successfully got provider for sandbox ${sandboxId}`);
|
||||
} catch (providerError) {
|
||||
console.error(`[apply-ai-code-stream] Failed to get or create provider for sandbox ${sandboxId}:`, providerError);
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: `Failed to create sandbox provider for ${sandboxId}. The sandbox may have expired.`,
|
||||
results: {
|
||||
filesCreated: [],
|
||||
packagesInstalled: [],
|
||||
commandsExecuted: [],
|
||||
errors: [`Sandbox provider creation failed: ${(providerError as Error).message}`]
|
||||
},
|
||||
explanation: parsed.explanation,
|
||||
structure: parsed.structure,
|
||||
parsedFiles: parsed.files,
|
||||
message: `Parsed ${parsed.files.length} files but couldn't apply them - sandbox reconnection failed.`
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,19 +346,18 @@ export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { SandboxFactory } = await import('@/lib/sandbox/factory');
|
||||
provider = SandboxFactory.create();
|
||||
await provider.createSandbox();
|
||||
const sandboxInfo = await provider.createSandbox();
|
||||
await provider.setupViteApp();
|
||||
|
||||
// Store the provider globally
|
||||
// Register with sandbox manager
|
||||
sandboxManager.registerSandbox(sandboxInfo.sandboxId, provider);
|
||||
|
||||
// Store in legacy global state
|
||||
global.activeSandboxProvider = provider;
|
||||
|
||||
// Update sandbox data
|
||||
const sandboxInfo = provider.getSandboxInfo();
|
||||
if (sandboxInfo) {
|
||||
global.sandboxData = {
|
||||
sandboxId: sandboxInfo.sandboxId,
|
||||
url: sandboxInfo.url
|
||||
};
|
||||
}
|
||||
global.sandboxData = {
|
||||
sandboxId: sandboxInfo.sandboxId,
|
||||
url: sandboxInfo.url
|
||||
};
|
||||
|
||||
console.log(`[apply-ai-code-stream] Created new sandbox successfully`);
|
||||
} catch (createError) {
|
||||
@@ -476,7 +479,8 @@ export async function POST(request: NextRequest) {
|
||||
if (data.type === 'success' && data.installedPackages) {
|
||||
results.packagesInstalled = data.installedPackages;
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (parseError) {
|
||||
console.debug('Error parsing terminal output:', parseError);
|
||||
// Ignore parse errors
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +488,7 @@ body {
|
||||
console.log('Auto-generated: src/index.css');
|
||||
results.filesCreated.push('src/index.css (with Tailwind)');
|
||||
} catch (error) {
|
||||
console.error('Failed to create index.css:', error);
|
||||
results.errors.push('Failed to create index.css with Tailwind');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { SandboxFactory } from '@/lib/sandbox/factory';
|
||||
import { SandboxProvider } from '@/lib/sandbox/types';
|
||||
// SandboxProvider type is used through SandboxFactory
|
||||
import type { SandboxState } from '@/types/sandbox';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
// Store active sandbox globally
|
||||
declare global {
|
||||
@@ -15,13 +16,16 @@ export async function POST() {
|
||||
try {
|
||||
console.log('[create-ai-sandbox-v2] Creating sandbox...');
|
||||
|
||||
// Clean up existing sandbox if any
|
||||
// Clean up all existing sandboxes
|
||||
console.log('[create-ai-sandbox-v2] Cleaning up existing sandboxes...');
|
||||
await sandboxManager.terminateAll();
|
||||
|
||||
// Also clean up legacy global state
|
||||
if (global.activeSandboxProvider) {
|
||||
console.log('[create-ai-sandbox-v2] Terminating existing sandbox...');
|
||||
try {
|
||||
await global.activeSandboxProvider.terminate();
|
||||
} catch (e) {
|
||||
console.error('Failed to terminate existing sandbox:', e);
|
||||
console.error('Failed to terminate legacy global sandbox:', e);
|
||||
}
|
||||
global.activeSandboxProvider = null;
|
||||
}
|
||||
@@ -40,7 +44,10 @@ export async function POST() {
|
||||
console.log('[create-ai-sandbox-v2] Setting up Vite React app...');
|
||||
await provider.setupViteApp();
|
||||
|
||||
// Store provider globally
|
||||
// Register with sandbox manager
|
||||
sandboxManager.registerSandbox(sandboxInfo.sandboxId, provider);
|
||||
|
||||
// Also store in legacy global state for backward compatibility
|
||||
global.activeSandboxProvider = provider;
|
||||
global.sandboxData = {
|
||||
sandboxId: sandboxInfo.sandboxId,
|
||||
@@ -75,6 +82,7 @@ export async function POST() {
|
||||
console.error('[create-ai-sandbox-v2] Error:', error);
|
||||
|
||||
// Clean up on error
|
||||
await sandboxManager.terminateAll();
|
||||
if (global.activeSandboxProvider) {
|
||||
try {
|
||||
await global.activeSandboxProvider.terminate();
|
||||
|
||||
@@ -118,7 +118,7 @@ async function createSandboxInternal() {
|
||||
|
||||
// First, change to the working directory
|
||||
await sandbox.runCommand('pwd');
|
||||
const workDir = appConfig.vercelSandbox.workingDirectory;
|
||||
// workDir is defined in appConfig - not needed here
|
||||
|
||||
// Get the sandbox URL using the correct Vercel Sandbox API
|
||||
const sandboxUrl = sandbox.domain(appConfig.vercelSandbox.devPort);
|
||||
|
||||
@@ -4,7 +4,7 @@ declare global {
|
||||
var activeSandbox: any;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
export async function POST(_request: NextRequest) {
|
||||
try {
|
||||
if (!global.activeSandbox) {
|
||||
return NextResponse.json({
|
||||
|
||||
@@ -108,8 +108,9 @@ export async function POST(request: NextRequest) {
|
||||
} else {
|
||||
missing.push(packageName);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (checkError) {
|
||||
// If test command fails, assume package is missing
|
||||
console.debug(`Package check failed for ${packageName}:`, checkError);
|
||||
missing.push(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,8 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
// Create surgical edit context with exact location
|
||||
const normalizedPath = target.filePath.replace('/home/user/app/', '');
|
||||
const fileContent = fileContents[normalizedPath]?.content || '';
|
||||
// fileContent available but not used in current implementation
|
||||
// const fileContent = fileContents[normalizedPath]?.content || '';
|
||||
|
||||
// Build enhanced context with search results
|
||||
enhancedSystemPrompt = `
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { parseJavaScriptFile, buildComponentTree } from '@/lib/file-parser';
|
||||
import { FileManifest, FileInfo, RouteInfo } from '@/types/file-manifest';
|
||||
import type { SandboxState } from '@/types/sandbox';
|
||||
// SandboxState type used implicitly through global.activeSandbox
|
||||
|
||||
declare global {
|
||||
var activeSandbox: any;
|
||||
@@ -76,7 +76,8 @@ export async function GET() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (parseError) {
|
||||
console.debug('Error parsing component info:', parseError);
|
||||
// Skip files that can't be read
|
||||
continue;
|
||||
}
|
||||
@@ -180,7 +181,8 @@ function extractRoutes(files: Record<string, FileInfo>): RouteInfo[] {
|
||||
const routeMatches = fileInfo.content.matchAll(/path=["']([^"']+)["'].*(?:element|component)={([^}]+)}/g);
|
||||
|
||||
for (const match of routeMatches) {
|
||||
const [, routePath, componentRef] = match;
|
||||
const [, routePath] = match;
|
||||
// componentRef available in match but not used currently
|
||||
routes.push({
|
||||
path: routePath,
|
||||
component: path,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { SandboxProvider } from '@/lib/sandbox/types';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
declare global {
|
||||
var activeSandboxProvider: SandboxProvider | null;
|
||||
@@ -16,7 +17,10 @@ export async function POST(request: NextRequest) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
if (!global.activeSandboxProvider) {
|
||||
// Get provider from sandbox manager or global state
|
||||
const provider = sandboxManager.getActiveProvider() || global.activeSandboxProvider;
|
||||
|
||||
if (!provider) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: 'No active sandbox'
|
||||
@@ -25,7 +29,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
console.log(`[install-packages-v2] Installing: ${packages.join(', ')}`);
|
||||
|
||||
const result = await global.activeSandboxProvider.installPackages(packages);
|
||||
const result = await provider.installPackages(packages);
|
||||
|
||||
return NextResponse.json({
|
||||
success: result.success,
|
||||
|
||||
@@ -8,7 +8,8 @@ declare global {
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { packages, sandboxId } = await request.json();
|
||||
const { packages } = await request.json();
|
||||
// sandboxId not used - using global sandbox
|
||||
|
||||
if (!packages || !Array.isArray(packages) || packages.length === 0) {
|
||||
return NextResponse.json({
|
||||
@@ -75,9 +76,9 @@ export async function POST(request: NextRequest) {
|
||||
// Try to kill any running dev server processes
|
||||
await providerInstance.runCommand('pkill -f vite');
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait a bit
|
||||
} catch (error) {
|
||||
} catch (killError) {
|
||||
// It's OK if no process is found
|
||||
console.log('[install-packages] No existing dev server found');
|
||||
console.debug('[install-packages] No existing dev server found:', killError);
|
||||
}
|
||||
|
||||
// Check which packages are already installed
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function GET() {
|
||||
const data = JSON.parse(errorFileContent);
|
||||
errors.push(...(data.errors || []));
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// No error file exists, that's OK
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ export async function GET() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Skip if grep fails
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// No log files found, that's OK
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export async function POST() {
|
||||
|
||||
// Wait a moment for processes to terminate
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
} catch (error) {
|
||||
} catch {
|
||||
console.log('[restart-vite] No existing Vite processes found');
|
||||
}
|
||||
|
||||
@@ -62,12 +62,13 @@ export async function POST() {
|
||||
cmd: 'bash',
|
||||
args: ['-c', 'echo \'{"errors": [], "lastChecked": '+ Date.now() +'}\' > /tmp/vite-errors.json']
|
||||
});
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Ignore if this fails
|
||||
}
|
||||
|
||||
// Start Vite dev server in detached mode
|
||||
const viteProcess = await global.activeSandbox.runCommand({
|
||||
// Start Vite dev server in detached mode
|
||||
await global.activeSandbox.runCommand({
|
||||
cmd: 'npm',
|
||||
args: ['run', 'dev'],
|
||||
detached: true
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { SandboxProvider } from '@/lib/sandbox/types';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
// Get active sandbox provider from global state
|
||||
declare global {
|
||||
@@ -17,7 +18,10 @@ export async function POST(request: NextRequest) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
if (!global.activeSandboxProvider) {
|
||||
// Get provider from sandbox manager or global state
|
||||
const provider = sandboxManager.getActiveProvider() || global.activeSandboxProvider;
|
||||
|
||||
if (!provider) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: 'No active sandbox'
|
||||
@@ -26,7 +30,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
console.log(`[run-command-v2] Executing: ${command}`);
|
||||
|
||||
const result = await global.activeSandboxProvider.runCommand(command);
|
||||
const result = await provider.runCommand(command);
|
||||
|
||||
return NextResponse.json({
|
||||
success: result.success,
|
||||
|
||||
@@ -4,7 +4,7 @@ declare global {
|
||||
var activeSandbox: any;
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
export async function GET(_request: NextRequest) {
|
||||
try {
|
||||
if (!global.activeSandbox) {
|
||||
return NextResponse.json({
|
||||
@@ -22,7 +22,7 @@ export async function GET(request: NextRequest) {
|
||||
});
|
||||
|
||||
let viteRunning = false;
|
||||
let logContent: string[] = [];
|
||||
const logContent: string[] = [];
|
||||
|
||||
if (psResult.exitCode === 0) {
|
||||
const psOutput = await psResult.stdout();
|
||||
@@ -63,12 +63,12 @@ export async function GET(request: NextRequest) {
|
||||
logContent.push(`--- ${logFile} ---`);
|
||||
logContent.push(logFileContent);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Skip if can't read log file
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// No log files found, that's OK
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { sandboxManager } from '@/lib/sandbox/sandbox-manager';
|
||||
|
||||
declare global {
|
||||
var activeSandboxProvider: any;
|
||||
@@ -8,19 +9,22 @@ declare global {
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
// Check if sandbox exists
|
||||
const sandboxExists = !!global.activeSandboxProvider;
|
||||
// Check sandbox manager first, then fall back to global state
|
||||
const provider = sandboxManager.getActiveProvider() || global.activeSandboxProvider;
|
||||
const sandboxExists = !!provider;
|
||||
|
||||
let sandboxHealthy = false;
|
||||
let sandboxInfo = null;
|
||||
|
||||
if (sandboxExists && global.activeSandboxProvider) {
|
||||
if (sandboxExists && provider) {
|
||||
try {
|
||||
// Check if sandbox is healthy by calling a method that should work
|
||||
sandboxHealthy = true;
|
||||
// Check if sandbox is healthy by getting its info
|
||||
const providerInfo = provider.getSandboxInfo();
|
||||
sandboxHealthy = !!providerInfo;
|
||||
|
||||
sandboxInfo = {
|
||||
sandboxId: global.sandboxData?.sandboxId,
|
||||
url: global.sandboxData?.url,
|
||||
sandboxId: providerInfo?.sandboxId || global.sandboxData?.sandboxId,
|
||||
url: providerInfo?.url || global.sandboxData?.url,
|
||||
filesTracked: global.existingFiles ? Array.from(global.existingFiles) : [],
|
||||
lastHealthCheck: new Date().toISOString()
|
||||
};
|
||||
|
||||
@@ -38,24 +38,35 @@ export async function POST(req: NextRequest) {
|
||||
]
|
||||
});
|
||||
|
||||
console.log('[scrape-screenshot] Scrape result success:', scrapeResult.success);
|
||||
console.log('[scrape-screenshot] Scrape result data:', scrapeResult.data ? Object.keys(scrapeResult.data) : 'No data');
|
||||
console.log('[scrape-screenshot] Full scrape result:', JSON.stringify(scrapeResult, null, 2));
|
||||
console.log('[scrape-screenshot] Scrape result type:', typeof scrapeResult);
|
||||
console.log('[scrape-screenshot] Scrape result keys:', Object.keys(scrapeResult));
|
||||
|
||||
if (!scrapeResult.success) {
|
||||
// The Firecrawl v4 API might return data directly without a success flag
|
||||
// Check if we have data with screenshot
|
||||
if (scrapeResult && scrapeResult.screenshot) {
|
||||
// Direct screenshot response
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
screenshot: scrapeResult.screenshot,
|
||||
metadata: scrapeResult.metadata || {}
|
||||
});
|
||||
} else if (scrapeResult?.data?.screenshot) {
|
||||
// Nested data structure
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
screenshot: scrapeResult.data.screenshot,
|
||||
metadata: scrapeResult.data.metadata || {}
|
||||
});
|
||||
} else if (scrapeResult?.success === false) {
|
||||
// Explicit failure
|
||||
console.error('[scrape-screenshot] Firecrawl API error:', scrapeResult.error);
|
||||
console.error('[scrape-screenshot] Full scrapeResult:', JSON.stringify(scrapeResult, null, 2));
|
||||
throw new Error(scrapeResult.error || 'Failed to capture screenshot');
|
||||
} else {
|
||||
// No screenshot in response
|
||||
console.error('[scrape-screenshot] No screenshot in response. Full response:', JSON.stringify(scrapeResult, null, 2));
|
||||
throw new Error('Screenshot not available in response - check console for full response structure');
|
||||
}
|
||||
|
||||
if (!scrapeResult.data?.screenshot) {
|
||||
throw new Error('Screenshot not available in response');
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
screenshot: scrapeResult.data.screenshot,
|
||||
metadata: scrapeResult.data.metadata || {}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[scrape-screenshot] Screenshot capture error:', error);
|
||||
|
||||
@@ -72,7 +72,8 @@ export async function POST(request: NextRequest) {
|
||||
throw new Error('Failed to scrape content');
|
||||
}
|
||||
|
||||
const { markdown, html, metadata, screenshot, actions } = data.data;
|
||||
const { markdown, metadata, screenshot, actions } = data.data;
|
||||
// html available but not used in current implementation
|
||||
|
||||
// Get screenshot from either direct field or actions result
|
||||
const screenshotUrl = screenshot || actions?.screenshots?.[0] || null;
|
||||
|
||||
@@ -94,7 +94,7 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Optional: Add OPTIONS handler for CORS if needed
|
||||
export async function OPTIONS(request: NextRequest) {
|
||||
export async function OPTIONS(_request: NextRequest) {
|
||||
return new NextResponse(null, {
|
||||
status: 200,
|
||||
headers: {
|
||||
|
||||
Reference in New Issue
Block a user