@@ -2,68 +2,294 @@ import { NextResponse } from 'next/server';
22
33declare global {
44 var activeSandbox : any ;
5+ var activeSandboxProvider : any ;
56}
67
78export async function POST ( ) {
89 try {
9- if ( ! global . activeSandbox ) {
10- return NextResponse . json ( {
11- success : false ,
12- error : 'No active sandbox'
10+ // Check both V2 provider (new) and V1 sandbox (legacy) patterns
11+ const provider = global . activeSandboxProvider ;
12+ const sandbox = global . activeSandbox ;
13+
14+ if ( ! provider && ! sandbox ) {
15+ return NextResponse . json ( {
16+ success : false ,
17+ error : 'No active sandbox'
1318 } , { status : 400 } ) ;
1419 }
15-
20+
1621 console . log ( '[create-zip] Creating project zip...' ) ;
17-
18- // Create zip file in sandbox using standard commands
19- const zipResult = await global . activeSandbox . runCommand ( {
20- cmd : 'bash' ,
21- args : [ '-c' , `zip -r /tmp/project.zip . -x "node_modules/*" ".git/*" ".next/*" "dist/*" "build/*" "*.log"` ]
22- } ) ;
23-
24- if ( zipResult . exitCode !== 0 ) {
25- const error = await zipResult . stderr ( ) ;
26- throw new Error ( `Failed to create zip: ${ error } ` ) ;
27- }
28-
29- const sizeResult = await global . activeSandbox . runCommand ( {
30- cmd : 'bash' ,
31- args : [ '-c' , `ls -la /tmp/project.zip | awk '{print $5}'` ]
32- } ) ;
33-
34- const fileSize = await sizeResult . stdout ( ) ;
35- console . log ( `[create-zip] Created project.zip (${ fileSize . trim ( ) } bytes)` ) ;
36-
37- // Read the zip file and convert to base64
38- const readResult = await global . activeSandbox . runCommand ( {
39- cmd : 'base64' ,
40- args : [ '/tmp/project.zip' ]
41- } ) ;
42-
43- if ( readResult . exitCode !== 0 ) {
44- const error = await readResult . stderr ( ) ;
45- throw new Error ( `Failed to read zip file: ${ error } ` ) ;
22+
23+ // Detect provider type
24+ const isE2B = provider && provider . constructor . name === 'E2BProvider' ;
25+ const isVercel = provider && provider . constructor . name === 'VercelProvider' ;
26+ const isV1Sandbox = ! provider && sandbox ;
27+
28+ console . log ( '[create-zip] Provider type:' , { isE2B, isVercel, isV1Sandbox } ) ;
29+
30+ if ( isE2B && provider . sandbox ) {
31+ // E2B Provider - use Python code execution to avoid command parsing issues
32+ try {
33+ console . log ( '[create-zip] Using E2B Python-based zip creation' ) ;
34+
35+ // Create zip using Python's zipfile module
36+ const zipCreationResult = await provider . sandbox . runCode ( `
37+ import zipfile
38+ import os
39+ import base64
40+ from pathlib import Path
41+
42+ # Change to app directory
43+ os.chdir('/home/user/app')
44+
45+ # Create zip file
46+ zip_path = '/tmp/project.zip'
47+ exclude_patterns = ['node_modules', '.git', '.next', 'dist', 'build', '*.log', '__pycache__', '*.pyc']
48+
49+ def should_exclude(path):
50+ path_str = str(path)
51+ for pattern in exclude_patterns:
52+ if pattern in path_str:
53+ return True
54+ if pattern.startswith('*') and path_str.endswith(pattern[1:]):
55+ return True
56+ return False
57+
58+ with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
59+ for root, dirs, files in os.walk('.'):
60+ # Filter out excluded directories
61+ dirs[:] = [d for d in dirs if not should_exclude(d)]
62+
63+ for file in files:
64+ file_path = os.path.join(root, file)
65+ if not should_exclude(file_path):
66+ # Add file to zip with relative path
67+ arcname = os.path.relpath(file_path, '.')
68+ zipf.write(file_path, arcname)
69+
70+ # Get file size
71+ file_size = os.path.getsize(zip_path)
72+ print(f"ZIP_SIZE:{file_size}")
73+
74+ # Read and encode to base64
75+ with open(zip_path, 'rb') as f:
76+ zip_content = f.read()
77+ base64_content = base64.b64encode(zip_content).decode('utf-8')
78+ print(f"BASE64_START:{base64_content}:BASE64_END")
79+ ` ) ;
80+
81+ // Parse the output to extract base64 content
82+ const output = zipCreationResult . logs . stdout . join ( '\n' ) ;
83+
84+ // Extract file size
85+ const sizeMatch = output . match ( / Z I P _ S I Z E : ( \d + ) / ) ;
86+ const fileSize = sizeMatch ? sizeMatch [ 1 ] : 'unknown' ;
87+ console . log ( `[create-zip] Created project.zip (${ fileSize } bytes)` ) ;
88+
89+ // Extract base64 content (using [\s\S] instead of 's' flag for compatibility)
90+ const base64Match = output . match ( / B A S E 6 4 _ S T A R T : ( [ \s \S ] * ?) : B A S E 6 4 _ E N D / ) ;
91+ if ( ! base64Match ) {
92+ throw new Error ( 'Failed to extract base64 content from Python output' ) ;
93+ }
94+
95+ const base64Content = base64Match [ 1 ] . trim ( ) ;
96+
97+ // Create a data URL for download
98+ const dataUrl = `data:application/zip;base64,${ base64Content } ` ;
99+
100+ return NextResponse . json ( {
101+ success : true ,
102+ dataUrl,
103+ fileName : 'e2b-sandbox-project.zip' ,
104+ message : 'Zip file created successfully'
105+ } ) ;
106+
107+ } catch ( error ) {
108+ console . error ( '[create-zip] E2B Provider error:' , error ) ;
109+ throw error ;
110+ }
111+
112+ } else if ( isVercel && provider ) {
113+ // Vercel Provider - use correct working directory
114+ try {
115+ console . log ( '[create-zip] Using Vercel Provider with /vercel/sandbox path' ) ;
116+
117+ // Install zip utility using dnf package manager with sudo
118+ console . log ( '[create-zip] Installing zip utility...' ) ;
119+ const installResult = await provider . sandbox . runCommand ( {
120+ cmd : 'dnf' ,
121+ args : [ 'install' , '-y' , 'zip' ] ,
122+ sudo : true
123+ } ) ;
124+
125+ // Create zip file
126+ const zipResult = await provider . sandbox . runCommand ( {
127+ cmd : 'zip' ,
128+ args : [ '-r' , '/tmp/project.zip' , '.' , '-x' , 'node_modules/*' , '.git/*' , '.next/*' , 'dist/*' , 'build/*' , '*.log' ] ,
129+ cwd : '/vercel/sandbox'
130+ } ) ;
131+
132+ // Handle stdout and stderr - they might be functions in Vercel SDK
133+ let stderr = '' ;
134+ try {
135+ if ( typeof zipResult . stderr === 'function' ) {
136+ stderr = await zipResult . stderr ( ) ;
137+ } else {
138+ stderr = zipResult . stderr || '' ;
139+ }
140+ } catch ( e ) {
141+ stderr = '' ;
142+ }
143+
144+ if ( zipResult . exitCode !== 0 ) {
145+ throw new Error ( `Failed to create zip: ${ stderr } ` ) ;
146+ }
147+
148+ const sizeResult = await provider . sandbox . runCommand ( {
149+ cmd : 'sh' ,
150+ args : [ '-c' , 'ls -la /tmp/project.zip | awk \'{print $5}\'' ]
151+ } ) ;
152+
153+ let fileSize = '' ;
154+ try {
155+ if ( typeof sizeResult . stdout === 'function' ) {
156+ fileSize = ( await sizeResult . stdout ( ) ) . trim ( ) ;
157+ } else {
158+ fileSize = ( sizeResult . stdout || '' ) . trim ( ) ;
159+ }
160+ } catch ( e ) {
161+ fileSize = 'unknown' ;
162+ }
163+ console . log ( `[create-zip] Created project.zip (${ fileSize } bytes)` ) ;
164+
165+ // Read the zip file and convert to base64
166+ const readResult = await provider . sandbox . runCommand ( {
167+ cmd : 'base64' ,
168+ args : [ '/tmp/project.zip' ]
169+ } ) ;
170+
171+ let readStderr = '' ;
172+ try {
173+ if ( typeof readResult . stderr === 'function' ) {
174+ readStderr = await readResult . stderr ( ) ;
175+ } else {
176+ readStderr = readResult . stderr || '' ;
177+ }
178+ } catch ( e ) {
179+ readStderr = '' ;
180+ }
181+
182+ if ( readResult . exitCode !== 0 ) {
183+ throw new Error ( `Failed to read zip file: ${ readStderr } ` ) ;
184+ }
185+
186+ let base64Content = '' ;
187+ try {
188+ if ( typeof readResult . stdout === 'function' ) {
189+ base64Content = ( await readResult . stdout ( ) ) . trim ( ) ;
190+ } else {
191+ base64Content = ( readResult . stdout || '' ) . trim ( ) ;
192+ }
193+ } catch ( e ) {
194+ throw new Error ( 'Failed to get base64 content from command result' ) ;
195+ }
196+
197+ // Create a data URL for download
198+ const dataUrl = `data:application/zip;base64,${ base64Content } ` ;
199+
200+ return NextResponse . json ( {
201+ success : true ,
202+ dataUrl,
203+ fileName : 'vercel-sandbox-project.zip' ,
204+ message : 'Zip file created successfully'
205+ } ) ;
206+
207+ } catch ( error ) {
208+ console . error ( '[create-zip] Vercel Provider error:' , error ) ;
209+ throw error ;
210+ }
211+
212+ } else if ( isV1Sandbox ) {
213+ // V1 Sandbox pattern - uses object with cmd/args (legacy)
214+ try {
215+ const zipResult = await sandbox . runCommand ( {
216+ cmd : 'bash' ,
217+ args : [ '-c' , `zip -r /tmp/project.zip . -x "node_modules/*" ".git/*" ".next/*" "dist/*" "build/*" "*.log"` ]
218+ } ) ;
219+
220+ // Handle potential function-based stdout/stderr (Vercel SDK pattern)
221+ const exitCode = zipResult . exitCode ;
222+ let stderr = '' ;
223+
224+ if ( typeof zipResult . stderr === 'function' ) {
225+ stderr = await zipResult . stderr ( ) ;
226+ } else {
227+ stderr = zipResult . stderr || '' ;
228+ }
229+
230+ if ( exitCode !== 0 ) {
231+ throw new Error ( `Failed to create zip: ${ stderr } ` ) ;
232+ }
233+
234+ const sizeResult = await sandbox . runCommand ( {
235+ cmd : 'bash' ,
236+ args : [ '-c' , `ls -la /tmp/project.zip | awk '{print $5}'` ]
237+ } ) ;
238+
239+ let fileSize = '' ;
240+ if ( typeof sizeResult . stdout === 'function' ) {
241+ fileSize = await sizeResult . stdout ( ) ;
242+ } else {
243+ fileSize = sizeResult . stdout || '' ;
244+ }
245+ console . log ( `[create-zip] Created project.zip (${ fileSize . trim ( ) } bytes)` ) ;
246+
247+ // Read the zip file and convert to base64
248+ const readResult = await sandbox . runCommand ( {
249+ cmd : 'base64' ,
250+ args : [ '/tmp/project.zip' ]
251+ } ) ;
252+
253+ if ( readResult . exitCode !== 0 ) {
254+ let error = '' ;
255+ if ( typeof readResult . stderr === 'function' ) {
256+ error = await readResult . stderr ( ) ;
257+ } else {
258+ error = readResult . stderr || 'Unknown error' ;
259+ }
260+ throw new Error ( `Failed to read zip file: ${ error } ` ) ;
261+ }
262+
263+ let base64Content = '' ;
264+ if ( typeof readResult . stdout === 'function' ) {
265+ base64Content = ( await readResult . stdout ( ) ) . trim ( ) ;
266+ } else {
267+ base64Content = ( readResult . stdout || '' ) . trim ( ) ;
268+ }
269+
270+ // Create a data URL for download
271+ const dataUrl = `data:application/zip;base64,${ base64Content } ` ;
272+
273+ return NextResponse . json ( {
274+ success : true ,
275+ dataUrl,
276+ fileName : 'vercel-sandbox-project.zip' ,
277+ message : 'Zip file created successfully'
278+ } ) ;
279+
280+ } catch ( error ) {
281+ console . error ( '[create-zip] V1 Sandbox error:' , error ) ;
282+ throw error ;
283+ }
46284 }
47-
48- const base64Content = ( await readResult . stdout ( ) ) . trim ( ) ;
49-
50- // Create a data URL for download
51- const dataUrl = `data:application/zip;base64,${ base64Content } ` ;
52-
53- return NextResponse . json ( {
54- success : true ,
55- dataUrl,
56- fileName : 'vercel-sandbox-project.zip' ,
57- message : 'Zip file created successfully'
58- } ) ;
59-
285+
60286 } catch ( error ) {
61287 console . error ( '[create-zip] Error:' , error ) ;
62288 return NextResponse . json (
63- {
64- success : false ,
65- error : ( error as Error ) . message
66- } ,
289+ {
290+ success : false ,
291+ error : ( error as Error ) . message
292+ } ,
67293 { status : 500 }
68294 ) ;
69295 }
0 commit comments