2024-04-18 16:40:08 -04:00
"use strict" ;
var _ _awaiter = ( this && this . _ _awaiter ) || function ( thisArg , _arguments , P , generator ) {
function adopt ( value ) { return value instanceof P ? value : new P ( function ( resolve ) { resolve ( value ) ; } ) ; }
return new ( P || ( P = Promise ) ) ( function ( resolve , reject ) {
function fulfilled ( value ) { try { step ( generator . next ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function rejected ( value ) { try { step ( generator [ "throw" ] ( value ) ) ; } catch ( e ) { reject ( e ) ; } }
function step ( result ) { result . done ? resolve ( result . value ) : adopt ( result . value ) . then ( fulfilled , rejected ) ; }
step ( ( generator = generator . apply ( thisArg , _arguments || [ ] ) ) . next ( ) ) ;
} ) ;
} ;
var _ _importDefault = ( this && this . _ _importDefault ) || function ( mod ) {
return ( mod && mod . _ _esModule ) ? mod : { "default" : mod } ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
2024-04-29 00:50:25 -04:00
const fs _1 = _ _importDefault ( require ( "fs" ) ) ;
2024-04-29 02:19:27 -04:00
const os _1 = _ _importDefault ( require ( "os" ) ) ;
2024-04-29 00:50:25 -04:00
const path _1 = _ _importDefault ( require ( "path" ) ) ;
2024-04-18 16:40:08 -04:00
const express _1 = _ _importDefault ( require ( "express" ) ) ;
const dotenv _1 = _ _importDefault ( require ( "dotenv" ) ) ;
const http _1 = require ( "http" ) ;
const socket _io _1 = require ( "socket.io" ) ;
2024-04-21 22:55:49 -04:00
const zod _1 = require ( "zod" ) ;
2024-04-27 14:23:09 -04:00
const utils _1 = require ( "./utils" ) ;
2024-04-29 02:19:27 -04:00
const node _pty _1 = require ( "node-pty" ) ;
2024-04-18 16:40:08 -04:00
dotenv _1 . default . config ( ) ;
const app = ( 0 , express _1 . default ) ( ) ;
const port = process . env . PORT || 4000 ;
// app.use(cors())
const httpServer = ( 0 , http _1 . createServer ) ( app ) ;
const io = new socket _io _1 . Server ( httpServer , {
cors : {
origin : "*" ,
} ,
} ) ;
2024-04-28 20:06:47 -04:00
const terminals = { } ;
2024-04-29 00:50:25 -04:00
const dirName = path _1 . default . join ( _ _dirname , ".." ) ;
2024-04-21 22:55:49 -04:00
const handshakeSchema = zod _1 . z . object ( {
userId : zod _1 . z . string ( ) ,
sandboxId : zod _1 . z . string ( ) ,
EIO : zod _1 . z . string ( ) ,
transport : zod _1 . z . string ( ) ,
} ) ;
2024-04-18 16:40:08 -04:00
io . use ( ( socket , next ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
const q = socket . handshake . query ;
2024-04-21 22:55:49 -04:00
const parseQuery = handshakeSchema . safeParse ( q ) ;
if ( ! parseQuery . success ) {
console . log ( "Invalid request." ) ;
2024-04-18 16:40:08 -04:00
next ( new Error ( "Invalid request." ) ) ;
2024-04-21 22:55:49 -04:00
return ;
}
2024-04-26 21:57:30 -04:00
const { sandboxId , userId } = parseQuery . data ;
2024-04-26 02:10:37 -04:00
const dbUser = yield fetch ( ` http://localhost:8787/api/user?id= ${ userId } ` ) ;
2024-04-21 22:55:49 -04:00
const dbUserJSON = ( yield dbUser . json ( ) ) ;
if ( ! dbUserJSON ) {
console . log ( "DB error." ) ;
next ( new Error ( "DB error." ) ) ;
return ;
2024-04-18 16:40:08 -04:00
}
2024-04-26 02:10:37 -04:00
const sandbox = dbUserJSON . sandbox . find ( ( s ) => s . id === sandboxId ) ;
2024-04-21 22:55:49 -04:00
if ( ! sandbox ) {
console . log ( "Invalid credentials." ) ;
2024-04-18 16:40:08 -04:00
next ( new Error ( "Invalid credentials." ) ) ;
2024-04-21 22:55:49 -04:00
return ;
2024-04-18 16:40:08 -04:00
}
2024-04-26 02:10:37 -04:00
socket . data = {
id : sandboxId ,
userId ,
2024-04-21 22:55:49 -04:00
} ;
2024-04-18 16:40:08 -04:00
next ( ) ;
} ) ) ;
io . on ( "connection" , ( socket ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
2024-04-21 22:55:49 -04:00
const data = socket . data ;
2024-04-27 14:23:09 -04:00
const sandboxFiles = yield ( 0 , utils _1 . getSandboxFiles ) ( data . id ) ;
2024-04-29 00:50:25 -04:00
sandboxFiles . fileData . forEach ( ( file ) => {
const filePath = path _1 . default . join ( dirName , file . id ) ;
fs _1 . default . mkdirSync ( path _1 . default . dirname ( filePath ) , { recursive : true } ) ;
fs _1 . default . writeFile ( filePath , file . data , function ( err ) {
if ( err )
throw err ;
} ) ;
} ) ;
2024-04-26 21:57:30 -04:00
socket . emit ( "loaded" , sandboxFiles . files ) ;
2024-04-27 00:20:17 -04:00
socket . on ( "getFile" , ( fileId , callback ) => {
const file = sandboxFiles . fileData . find ( ( f ) => f . id === fileId ) ;
if ( ! file )
return ;
callback ( file . data ) ;
} ) ;
2024-04-27 19:12:25 -04:00
// todo: send diffs + debounce for efficiency
socket . on ( "saveFile" , ( fileId , body ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
const file = sandboxFiles . fileData . find ( ( f ) => f . id === fileId ) ;
if ( ! file )
return ;
file . data = body ;
2024-04-29 00:50:25 -04:00
fs _1 . default . writeFile ( path _1 . default . join ( dirName , file . id ) , body , function ( err ) {
if ( err )
throw err ;
} ) ;
2024-04-27 19:12:25 -04:00
yield ( 0 , utils _1 . saveFile ) ( fileId , body ) ;
} ) ) ;
2024-04-29 00:50:25 -04:00
socket . on ( "createFile" , ( name ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
const id = ` projects/ ${ data . id } / ${ name } ` ;
fs _1 . default . writeFile ( path _1 . default . join ( dirName , id ) , "" , function ( err ) {
if ( err )
throw err ;
} ) ;
sandboxFiles . files . push ( {
id ,
name ,
type : "file" ,
} ) ;
sandboxFiles . fileData . push ( {
id ,
data : "" ,
} ) ;
yield ( 0 , utils _1 . createFile ) ( id ) ;
} ) ) ;
2024-04-27 14:23:09 -04:00
socket . on ( "renameFile" , ( fileId , newName ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
const file = sandboxFiles . fileData . find ( ( f ) => f . id === fileId ) ;
if ( ! file )
return ;
file . id = newName ;
2024-04-29 00:50:25 -04:00
const parts = fileId . split ( "/" ) ;
const newFileId = parts . slice ( 0 , parts . length - 1 ) . join ( "/" ) + "/" + newName ;
fs _1 . default . rename ( path _1 . default . join ( dirName , fileId ) , path _1 . default . join ( dirName , newFileId ) , function ( err ) {
if ( err )
throw err ;
} ) ;
yield ( 0 , utils _1 . renameFile ) ( fileId , newFileId , file . data ) ;
2024-04-27 14:23:09 -04:00
} ) ) ;
2024-04-30 01:56:43 -04:00
socket . on ( "deleteFile" , ( fileId , callback ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
const file = sandboxFiles . fileData . find ( ( f ) => f . id === fileId ) ;
if ( ! file )
return ;
fs _1 . default . unlink ( path _1 . default . join ( dirName , fileId ) , function ( err ) {
if ( err )
throw err ;
} ) ;
sandboxFiles . fileData = sandboxFiles . fileData . filter ( ( f ) => f . id !== fileId ) ;
yield ( 0 , utils _1 . deleteFile ) ( fileId ) ;
const newFiles = yield ( 0 , utils _1 . getSandboxFiles ) ( data . id ) ;
callback ( newFiles . files ) ;
} ) ) ;
2024-04-28 20:06:47 -04:00
socket . on ( "createTerminal" , ( { id } ) => {
2024-04-29 02:19:27 -04:00
const pty = ( 0 , node _pty _1 . spawn ) ( os _1 . default . platform ( ) === "win32" ? "cmd.exe" : "bash" , [ ] , {
name : "xterm" ,
cols : 100 ,
cwd : path _1 . default . join ( dirName , "projects" , data . id ) ,
} ) ;
2024-04-29 21:36:33 -04:00
const onData = pty . onData ( ( data ) => {
2024-04-29 02:19:27 -04:00
socket . emit ( "terminalResponse" , {
// data: Buffer.from(data, "utf-8").toString("base64"),
data ,
} ) ;
} ) ;
2024-04-29 21:36:33 -04:00
const onExit = pty . onExit ( ( code ) => console . log ( "exit :(" , code ) ) ;
2024-04-30 22:48:36 -04:00
pty . write ( "clear\r" ) ;
2024-04-29 21:36:33 -04:00
terminals [ id ] = {
terminal : pty ,
onData ,
onExit ,
} ;
2024-04-28 20:06:47 -04:00
} ) ;
2024-04-29 02:19:27 -04:00
socket . on ( "terminalData" , ( id , data ) => {
2024-04-28 20:06:47 -04:00
if ( ! terminals [ id ] ) {
console . log ( "terminals" , terminals ) ;
return ;
}
2024-04-29 02:19:27 -04:00
try {
2024-04-29 21:36:33 -04:00
terminals [ id ] . terminal . write ( data ) ;
2024-04-29 02:19:27 -04:00
}
catch ( e ) {
console . log ( "Error writing to terminal" , e ) ;
}
2024-04-28 20:06:47 -04:00
} ) ;
2024-05-03 00:52:01 -07:00
socket . on ( "generateCode" , ( fileName , code , line , instructions , callback ) => _ _awaiter ( void 0 , void 0 , void 0 , function * ( ) {
console . log ( "Generating code..." ) ;
const res = yield fetch ( ` https://api.cloudflare.com/client/v4/accounts/ ${ process . env . CF _USER _ID } /ai/run/@cf/meta/llama-3-8b-instruct ` , {
method : "POST" ,
headers : {
"Content-Type" : "application/json" ,
Authorization : ` Bearer ${ process . env . CF _API _TOKEN } ` ,
} ,
body : JSON . stringify ( {
messages : [
{
role : "system" ,
content : "You are an expert coding assistant. You read code from a file, and you suggest new code to add to the file. You may be given instructions on what to generate, which you should follow. You should generate code that is correct, efficient, and follows best practices. You should also generate code that is clear and easy to read." ,
} ,
{
role : "user" ,
content : ` The file is called ${ fileName } . Here are my instructions on what to generate: ${ instructions } . Suggest me code to insert at line ${ line } in my file.
My code file content : $ { code }
Return only the code , and nothing else . Do not include backticks . ` ,
} ,
] ,
} ) ,
} ) ;
const json = yield res . json ( ) ;
callback ( json ) ;
} ) ) ;
2024-04-29 21:36:33 -04:00
socket . on ( "disconnect" , ( ) => {
Object . entries ( terminals ) . forEach ( ( t ) => {
const { terminal , onData , onExit } = t [ 1 ] ;
if ( os _1 . default . platform ( ) !== "win32" )
terminal . kill ( ) ;
onData . dispose ( ) ;
onExit . dispose ( ) ;
delete terminals [ t [ 0 ] ] ;
} ) ;
} ) ;
2024-04-18 16:40:08 -04:00
} ) ) ;
httpServer . listen ( port , ( ) => {
console . log ( ` Server running on port ${ port } ` ) ;
} ) ;