1
- // lib/e2b.ts
2
- import { Sandbox } from '@e2b/sdk' ;
3
- import { GeneratedFile , DeployResult } from '@/lib/types' ;
4
-
1
+ import { Sandbox } from '@e2b/code-interpreter' ;
2
+ import { benchifyFileSchema } from './schemas' ;
3
+ import { z } from 'zod' ;
5
4
6
5
const E2B_API_KEY = process . env . E2B_API_KEY ;
7
6
8
7
if ( ! E2B_API_KEY ) {
9
8
throw new Error ( 'E2B_API_KEY is not set' ) ;
10
9
}
11
10
12
- // Ensure path has a leading slash
13
- function normalizePath ( path : string ) : string {
14
- return path . startsWith ( '/' ) ? path : `/${ path } ` ;
15
- }
16
-
17
- // Initialize E2B SDK
18
- export async function createSandbox ( ) {
19
- try {
20
- const sandbox = await Sandbox . create ( {
21
- apiKey : E2B_API_KEY ,
22
- } ) ;
23
-
24
- return sandbox ;
25
- } catch ( error : any ) {
26
- console . error ( 'E2B Error Details:' , {
27
- message : error . message ,
28
- status : error . status ,
29
- statusText : error . statusText ,
30
- data : error . data ,
31
- headers : error . headers ,
32
- url : error . url
33
- } ) ;
34
- throw error ;
35
- }
36
- }
37
-
38
- // Set up a Vue environment with required dependencies
39
- export async function prepareVueEnvironment ( sandbox : Sandbox ) {
40
- try {
41
- // Create necessary directories
42
- await sandbox . filesystem . makeDir ( '/src' ) ;
43
- await sandbox . filesystem . makeDir ( '/src/components' ) ;
44
-
45
- // Define base configuration files
46
- const packageJson = {
47
- name : "vue-app" ,
48
- version : "1.0.0" ,
49
- type : "module" ,
50
- scripts : {
51
- "dev" : "vite" ,
52
- "build" : "vue-tsc && vite build" ,
53
- "preview" : "vite preview"
54
- } ,
55
- dependencies : {
56
- "vue" : "^3.3.0" ,
57
- "vue-router" : "^4.2.0" ,
58
- "pinia" : "^2.1.0" ,
59
- "@vueuse/core" : "^10.5.0"
60
- } ,
61
- devDependencies : {
62
- "@vitejs/plugin-vue" : "^4.4.0" ,
63
- "typescript" : "^5.2.0" ,
64
- "vite" : "^4.5.0" ,
65
- "vue-tsc" : "^1.8.0" ,
66
- "tailwindcss" : "^3.3.0" ,
67
- "postcss" : "^8.4.0" ,
68
- "autoprefixer" : "^10.4.0"
11
+ export async function createSandbox ( { files } : { files : z . infer < typeof benchifyFileSchema > } ) {
12
+ const sandbox = await Sandbox . create ( 'vue-dynamic-sandbox' , { apiKey : E2B_API_KEY } ) ;
13
+
14
+ // Write all files to the sandbox at once
15
+ await sandbox . files . write (
16
+ files . map ( file => ( {
17
+ path : `/home/user/app/${ file . path } ` ,
18
+ data : file . contents
19
+ } ) )
20
+ ) ;
21
+
22
+ console . log ( "sandbox created" , sandbox . sandboxId ) ;
23
+
24
+ // Find package.json to check for new dependencies
25
+ const packageJsonFile = files . find ( file => file . path === 'package.json' ) ;
26
+ if ( packageJsonFile ) {
27
+ try {
28
+ const packageJson = JSON . parse ( packageJsonFile . contents ) ;
29
+ const dependencies = packageJson . dependencies || { } ;
30
+ const devDependencies = packageJson . devDependencies || { } ;
31
+
32
+ // Filter out pre-installed dependencies (vue, tailwindcss, etc.)
33
+ const preInstalled = [ 'vue' , 'tailwindcss' , 'autoprefixer' , 'postcss' , 'vite' , '@vitejs/plugin-vue' , '@vue/compiler-sfc' ] ;
34
+
35
+ // Get new deps that need to be installed
36
+ const newDeps = Object . keys ( dependencies ) . filter ( dep => ! preInstalled . includes ( dep ) ) ;
37
+ const newDevDeps = Object . keys ( devDependencies ) . filter ( dep => ! preInstalled . includes ( dep ) ) ;
38
+
39
+ // Install only new dependencies if any exist
40
+ if ( newDeps . length > 0 ) {
41
+ console . log ( "Installing new dependencies:" , newDeps . join ( ", " ) ) ;
42
+ await sandbox . commands . run ( `cd /home/user/app && npm install --legacy-peer-deps ${ newDeps . join ( ' ' ) } ` ) ;
69
43
}
70
- } ;
71
-
72
- // Write initial configuration
73
- await sandbox . filesystem . write ( '/package.json' , JSON . stringify ( packageJson , null , 2 ) ) ;
74
-
75
- await sandbox . filesystem . write ( '/vite.config.ts' , `import { defineConfig } from 'vite'
76
- import vue from '@vitejs/plugin-vue'
77
-
78
- export default defineConfig({
79
- plugins: [vue()],
80
- server: {
81
- host: true,
82
- port: 3000
83
- }
84
- })` ) ;
85
-
86
- // Install dependencies with legacy peer deps to avoid conflicts
87
- await sandbox . process . start ( {
88
- cmd : 'npm install --legacy-peer-deps' ,
89
- } ) ;
90
-
91
- // Write Vue app files
92
- await sandbox . filesystem . write ( '/src/App.vue' , `<template>
93
- <div class="min-h-screen">
94
- <router-view />
95
- </div>
96
- </template>
97
-
98
- <script setup lang="ts">
99
- // App level setup
100
- </script>` ) ;
101
44
102
- await sandbox . filesystem . write ( '/tailwind.config.js' , `/** @type {import('tailwindcss').Config} */
103
- export default {
104
- content: [
105
- "./index.html",
106
- "./src/**/*.{vue,js,ts,jsx,tsx}",
107
- ],
108
- theme: {
109
- extend: {},
110
- },
111
- plugins: [],
112
- }` ) ;
113
-
114
- await sandbox . filesystem . write ( '/postcss.config.js' , `export default {
115
- plugins: {
116
- tailwindcss: {},
117
- autoprefixer: {},
118
- },
119
- }` ) ;
120
-
121
- // Create index files
122
- await sandbox . filesystem . write ( '/index.html' , `<!DOCTYPE html>
123
- <html lang="en">
124
- <head>
125
- <meta charset="UTF-8" />
126
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
127
- <title>Vue App</title>
128
- </head>
129
- <body>
130
- <div id="app"></div>
131
- <script type="module" src="/src/main.ts"></script>
132
- </body>
133
- </html>` ) ;
134
-
135
- await sandbox . filesystem . write ( '/src/main.ts' , `import { createApp } from 'vue'
136
- import App from './App.vue'
137
- import './style.css'
138
-
139
- createApp(App).mount('#app')` ) ;
140
-
141
- await sandbox . filesystem . write ( '/src/style.css' , `@tailwind base;
142
- @tailwind components;
143
- @tailwind utilities;` ) ;
144
-
145
- return sandbox ;
146
- } catch ( error : any ) {
147
- console . error ( 'E2B Environment Setup Error:' , {
148
- message : error . message ,
149
- details : error . details ,
150
- command : error . command ,
151
- exitCode : error . exitCode ,
152
- stdout : error . stdout ,
153
- stderr : error . stderr
154
- } ) ;
155
- throw error ;
156
- }
157
- }
158
-
159
- // Deploy the app for preview
160
- export async function deployApp ( sandbox : Sandbox , files : GeneratedFile [ ] ) : Promise < DeployResult > {
161
- try {
162
- // Write all the generated files
163
- for ( const file of files ) {
164
- const normalizedPath = normalizePath ( file . path ) ;
165
- const dirPath = normalizedPath . split ( '/' ) . slice ( 0 , - 1 ) . join ( '/' ) ;
166
-
167
- if ( dirPath && dirPath !== '/' ) {
168
- await sandbox . filesystem . makeDir ( dirPath ) ;
45
+ if ( newDevDeps . length > 0 ) {
46
+ console . log ( "Installing new dev dependencies:" , newDevDeps . join ( ", " ) ) ;
47
+ await sandbox . commands . run ( `cd /home/user/app && npm install --legacy-peer-deps --save-dev ${ newDevDeps . join ( ' ' ) } ` ) ;
169
48
}
170
-
171
- await sandbox . filesystem . write ( normalizedPath , file . contents ) ;
49
+ } catch ( error ) {
50
+ console . error ( "Error parsing package.json:" , error ) ;
172
51
}
52
+ }
173
53
174
- console . log ( 'Starting development server...' ) ;
175
- // Start the development server
176
- const process = await sandbox . process . start ( {
177
- cmd : 'npm run dev' ,
178
- } ) ;
54
+ // Run the Vite app
55
+ await sandbox . commands . run ( 'cd /home/user/app && npx vite' ) ;
179
56
180
- const previewUrl = `https://${ sandbox . id } -3000.code.e2b.dev` ;
181
- console . log ( 'Preview URL generated:' , previewUrl ) ;
57
+ return {
58
+ sbxId : sandbox . sandboxId ,
59
+ template : 'vue-dynamic-sandbox' ,
60
+ url : `https://${ sandbox . getHost ( 5173 ) } `
61
+ } ;
62
+ }
182
63
183
- // Return the URL for preview
184
- return {
185
- previewUrl,
186
- process,
187
- } ;
188
- } catch ( error : any ) {
189
- console . error ( 'E2B Deployment Error:' , {
190
- message : error . message ,
191
- sandboxId : sandbox ?. id ,
192
- status : error . status ,
193
- statusText : error . statusText ,
194
- data : error . data ,
195
- url : error . url
196
- } ) ;
197
- throw error ;
198
- }
199
- }
0 commit comments