├── .gitignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── backend └── server │ ├── .dockerignore │ ├── .env.example │ ├── dockerfile │ ├── drizzle.config.ts │ ├── drizzle │ ├── 0000_safe_stark_industries.sql │ ├── 0000_superb_nomad.sql │ ├── 0001_unusual_archangel.sql │ └── meta │ │ ├── 0000_snapshot.json │ │ ├── 0001_snapshot.json │ │ └── _journal.json │ ├── nodemon.json │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── db │ │ ├── migrate.ts │ │ └── schema.ts │ ├── index.ts │ ├── middleware │ │ ├── GitHubAuthUsers.ts │ │ ├── attachAuthToken.ts │ │ ├── clerkAuth.ts │ │ └── socketAuth.ts │ ├── routes │ │ ├── GitHubApiRoutes.ts │ │ ├── sandbox.ts │ │ └── user.ts │ ├── services │ │ ├── ConnectionManager.ts │ │ ├── DokkuClient.ts │ │ ├── FileManager.ts │ │ ├── GitHubApiService.ts │ │ ├── GitHubManager.ts │ │ ├── Project.ts │ │ ├── SSHSocketClient.ts │ │ ├── SecureGitClient.ts │ │ ├── Terminal.ts │ │ └── TerminalManager.ts │ └── utils │ │ ├── clerk.ts │ │ ├── constants.ts │ │ ├── lock.ts │ │ ├── ratelimit.ts │ │ └── types.ts │ └── tsconfig.json ├── frontend ├── .env.example ├── app │ ├── (app) │ │ ├── code │ │ │ ├── [id] │ │ │ │ └── page.tsx │ │ │ └── page.tsx │ │ ├── dashboard │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── (auth) │ │ ├── layout.tsx │ │ ├── sign-in │ │ │ └── [[...sign-in]] │ │ │ │ └── page.tsx │ │ └── sign-up │ │ │ └── [[...sign-up]] │ │ │ └── page.tsx │ ├── [username] │ │ └── page.tsx │ ├── api │ │ ├── ai │ │ │ └── route.ts │ │ ├── lb-auth │ │ │ └── route.ts │ │ ├── merge │ │ │ └── route.ts │ │ └── user │ │ │ └── upgrade-tier │ │ │ └── route.ts │ ├── globals.css │ ├── icon.svg │ ├── layout.tsx │ ├── loading │ │ └── page.tsx │ ├── opengraph-image.alt.txt │ ├── opengraph-image.png │ ├── page.tsx │ └── providers.tsx ├── assets │ ├── logo-dark.svg │ ├── logo-light.svg │ └── x.svg ├── components.json ├── components │ ├── dashboard │ │ ├── about.tsx │ │ ├── index.tsx │ │ ├── navbar │ │ │ ├── index.tsx │ │ │ └── search.tsx │ │ ├── newProject.tsx │ │ ├── projectCard │ │ │ ├── dropdown.tsx │ │ │ ├── index.tsx │ │ │ └── revealEffect.tsx │ │ ├── projects.tsx │ │ └── shared.tsx │ ├── editor │ │ ├── AIChat │ │ │ ├── ApplyButton.tsx │ │ │ ├── ChatInput.tsx │ │ │ ├── ChatMessage.tsx │ │ │ ├── ContextTabs.tsx │ │ │ ├── index.tsx │ │ │ ├── lib │ │ │ │ ├── chatUtils.ts │ │ │ │ ├── ignored-paths.ts │ │ │ │ └── markdownComponents.tsx │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── CodeEditorWrapper.tsx │ │ ├── changes-alert.tsx │ │ ├── generate.tsx │ │ ├── index.tsx │ │ ├── live │ │ │ ├── avatars.tsx │ │ │ ├── cursors.tsx │ │ │ ├── disableModal.tsx │ │ │ └── room.tsx │ │ ├── loading │ │ │ └── index.tsx │ │ ├── navbar │ │ │ ├── deploy.tsx │ │ │ ├── downloadButton.tsx │ │ │ ├── edit.tsx │ │ │ ├── index.tsx │ │ │ ├── run.tsx │ │ │ ├── share.tsx │ │ │ └── sharedUser.tsx │ │ ├── preview │ │ │ └── index.tsx │ │ ├── sidebar │ │ │ ├── file-explorer.tsx │ │ │ ├── file.tsx │ │ │ ├── folder.tsx │ │ │ ├── github-sync.tsx │ │ │ ├── index.tsx │ │ │ └── new.tsx │ │ ├── terminals │ │ │ ├── index.tsx │ │ │ ├── terminal.tsx │ │ │ └── xterm.css │ │ └── theme.json │ ├── landing │ │ └── index.tsx │ ├── logo.tsx │ ├── profile │ │ ├── index.tsx │ │ └── navbar.tsx │ ├── query-client.tsx │ └── ui │ │ ├── LoadingDots.tsx │ │ ├── alert-dialog.tsx │ │ ├── alert.tsx │ │ ├── avatar.tsx │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── context-menu.tsx │ │ ├── customButton.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── form.tsx │ │ ├── hover-card.tsx │ │ ├── icons.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── popover.tsx │ │ ├── progress.tsx │ │ ├── resizable.tsx │ │ ├── scroll-area.tsx │ │ ├── select.tsx │ │ ├── sidebar.tsx │ │ ├── skeleton.tsx │ │ ├── sonner.tsx │ │ ├── switch.tsx │ │ ├── tab.tsx │ │ ├── table.tsx │ │ ├── tabs.tsx │ │ ├── textarea.tsx │ │ ├── theme-provider.tsx │ │ ├── theme-switcher.tsx │ │ ├── tooltip.tsx │ │ └── userButton.tsx ├── context │ ├── PreviewContext.tsx │ ├── SocketContext.tsx │ └── TerminalContext.tsx ├── hooks │ └── github.ts ├── lib │ ├── actions.ts │ ├── colors.ts │ ├── constants │ │ └── index.ts │ ├── data │ │ └── index.ts │ ├── file-extension-to-language.json │ ├── get-query-client.ts │ ├── schema │ │ └── index.ts │ ├── server-utils.ts │ ├── templates │ │ └── index.ts │ ├── terminal.ts │ ├── tiers.ts │ ├── tsconfig.ts │ ├── types.ts │ ├── username-generator.ts │ └── utils.ts ├── liveblocks.config.ts ├── middleware.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ ├── icons │ │ ├── default_file.svg │ │ ├── default_folder.svg │ │ ├── default_folder_opened.svg │ │ ├── default_root_folder.svg │ │ ├── default_root_folder_opened.svg │ │ ├── file_type_access.svg │ │ ├── file_type_actionscript.svg │ │ ├── file_type_ai.svg │ │ ├── file_type_ai2.svg │ │ ├── file_type_al.svg │ │ ├── file_type_angular.svg │ │ ├── file_type_ansible.svg │ │ ├── file_type_antlr.svg │ │ ├── file_type_anyscript.svg │ │ ├── file_type_apache.svg │ │ ├── file_type_apex.svg │ │ ├── file_type_apib.svg │ │ ├── file_type_apib2.svg │ │ ├── file_type_applescript.svg │ │ ├── file_type_appveyor.svg │ │ ├── file_type_arduino.svg │ │ ├── file_type_asp.svg │ │ ├── file_type_aspx.svg │ │ ├── file_type_assembly.svg │ │ ├── file_type_audio.svg │ │ ├── file_type_aurelia.svg │ │ ├── file_type_autohotkey.svg │ │ ├── file_type_autoit.svg │ │ ├── file_type_avro.svg │ │ ├── file_type_aws.svg │ │ ├── file_type_babel.svg │ │ ├── file_type_babel2.svg │ │ ├── file_type_bat.svg │ │ ├── file_type_bazaar.svg │ │ ├── file_type_bazel.svg │ │ ├── file_type_binary.svg │ │ ├── file_type_bithound.svg │ │ ├── file_type_blade.svg │ │ ├── file_type_bolt.svg │ │ ├── file_type_bower.svg │ │ ├── file_type_bower2.svg │ │ ├── file_type_browserslist.svg │ │ ├── file_type_buckbuild.svg │ │ ├── file_type_bundler.svg │ │ ├── file_type_c.svg │ │ ├── file_type_c2.svg │ │ ├── file_type_c_al.svg │ │ ├── file_type_cabal.svg │ │ ├── file_type_cake.svg │ │ ├── file_type_cakephp.svg │ │ ├── file_type_cargo.svg │ │ ├── file_type_cert.svg │ │ ├── file_type_cf.svg │ │ ├── file_type_cf2.svg │ │ ├── file_type_cfc.svg │ │ ├── file_type_cfc2.svg │ │ ├── file_type_cfm.svg │ │ ├── file_type_cfm2.svg │ │ ├── file_type_cheader.svg │ │ ├── file_type_chef.svg │ │ ├── file_type_circleci.svg │ │ ├── file_type_class.svg │ │ ├── file_type_clojure.svg │ │ ├── file_type_cloudfoundry.svg │ │ ├── file_type_cmake.svg │ │ ├── file_type_cobol.svg │ │ ├── file_type_codacy.svg │ │ ├── file_type_codeclimate.svg │ │ ├── file_type_codecov.svg │ │ ├── file_type_codekit.svg │ │ ├── file_type_coffeelint.svg │ │ ├── file_type_coffeescript.svg │ │ ├── file_type_compass.svg │ │ ├── file_type_composer.svg │ │ ├── file_type_conan.svg │ │ ├── file_type_config.svg │ │ ├── file_type_coveralls.svg │ │ ├── file_type_cpp.svg │ │ ├── file_type_cpp2.svg │ │ ├── file_type_cppheader.svg │ │ ├── file_type_crowdin.svg │ │ ├── file_type_crystal.svg │ │ ├── file_type_csharp.svg │ │ ├── file_type_csproj.svg │ │ ├── file_type_css.svg │ │ ├── file_type_csslint.svg │ │ ├── file_type_cssmap.svg │ │ ├── file_type_cucumber.svg │ │ ├── file_type_cvs.svg │ │ ├── file_type_cypress.svg │ │ ├── file_type_cython.svg │ │ ├── file_type_dal.svg │ │ ├── file_type_darcs.svg │ │ ├── file_type_dartlang.svg │ │ ├── file_type_db.svg │ │ ├── file_type_delphi.svg │ │ ├── file_type_dependencies.svg │ │ ├── file_type_diff.svg │ │ ├── file_type_django.svg │ │ ├── file_type_dlang.svg │ │ ├── file_type_docker.svg │ │ ├── file_type_docker2.svg │ │ ├── file_type_dockertest.svg │ │ ├── file_type_dockertest2.svg │ │ ├── file_type_docpad.svg │ │ ├── file_type_doxygen.svg │ │ ├── file_type_drone.svg │ │ ├── file_type_drools.svg │ │ ├── file_type_dustjs.svg │ │ ├── file_type_dylan.svg │ │ ├── file_type_edge.svg │ │ ├── file_type_edge2.svg │ │ ├── file_type_editorconfig.svg │ │ ├── file_type_eex.svg │ │ ├── file_type_ejs.svg │ │ ├── file_type_elastic.svg │ │ ├── file_type_elasticbeanstalk.svg │ │ ├── file_type_elixir.svg │ │ ├── file_type_elm.svg │ │ ├── file_type_elm2.svg │ │ ├── file_type_emacs.svg │ │ ├── file_type_ember.svg │ │ ├── file_type_ensime.svg │ │ ├── file_type_eps.svg │ │ ├── file_type_erb.svg │ │ ├── file_type_erlang.svg │ │ ├── file_type_erlang2.svg │ │ ├── file_type_eslint.svg │ │ ├── file_type_eslint2.svg │ │ ├── file_type_excel.svg │ │ ├── file_type_favicon.svg │ │ ├── file_type_fbx.svg │ │ ├── file_type_firebase.svg │ │ ├── file_type_firestore.svg │ │ ├── file_type_flash.svg │ │ ├── file_type_floobits.svg │ │ ├── file_type_flow.svg │ │ ├── file_type_font.svg │ │ ├── file_type_fortran.svg │ │ ├── file_type_fossa.svg │ │ ├── file_type_fossil.svg │ │ ├── file_type_freemarker.svg │ │ ├── file_type_fsharp.svg │ │ ├── file_type_fsharp2.svg │ │ ├── file_type_fsproj.svg │ │ ├── file_type_fusebox.svg │ │ ├── file_type_galen.svg │ │ ├── file_type_galen2.svg │ │ ├── file_type_gamemaker.svg │ │ ├── file_type_gamemaker2.svg │ │ ├── file_type_gamemaker81.svg │ │ ├── file_type_git.svg │ │ ├── file_type_git2.svg │ │ ├── file_type_gitlab.svg │ │ ├── file_type_glide.svg │ │ ├── file_type_glsl.svg │ │ ├── file_type_go.svg │ │ ├── file_type_godot.svg │ │ ├── file_type_gradle.svg │ │ ├── file_type_graphql.svg │ │ ├── file_type_graphviz.svg │ │ ├── file_type_groovy.svg │ │ ├── file_type_groovy2.svg │ │ ├── file_type_grunt.svg │ │ ├── file_type_gulp.svg │ │ ├── file_type_haml.svg │ │ ├── file_type_handlebars.svg │ │ ├── file_type_handlebars2.svg │ │ ├── file_type_harbour.svg │ │ ├── file_type_haskell.svg │ │ ├── file_type_haskell2.svg │ │ ├── file_type_haxe.svg │ │ ├── file_type_haxecheckstyle.svg │ │ ├── file_type_haxedevelop.svg │ │ ├── file_type_helix.svg │ │ ├── file_type_helm.svg │ │ ├── file_type_hlsl.svg │ │ ├── file_type_host.svg │ │ ├── file_type_html.svg │ │ ├── file_type_htmlhint.svg │ │ ├── file_type_http.svg │ │ ├── file_type_idris.svg │ │ ├── file_type_idrisbin.svg │ │ ├── file_type_idrispkg.svg │ │ ├── file_type_image.svg │ │ ├── file_type_infopath.svg │ │ ├── file_type_ini.svg │ │ ├── file_type_io.svg │ │ ├── file_type_iodine.svg │ │ ├── file_type_ionic.svg │ │ ├── file_type_jake.svg │ │ ├── file_type_jar.svg │ │ ├── file_type_java.svg │ │ ├── file_type_jbuilder.svg │ │ ├── file_type_jekyll.svg │ │ ├── file_type_jenkins.svg │ │ ├── file_type_jest.svg │ │ ├── file_type_jinja.svg │ │ ├── file_type_jpm.svg │ │ ├── file_type_js.svg │ │ ├── file_type_js_official.svg │ │ ├── file_type_jsbeautify.svg │ │ ├── file_type_jsconfig.svg │ │ ├── file_type_jshint.svg │ │ ├── file_type_jsmap.svg │ │ ├── file_type_json.svg │ │ ├── file_type_json2.svg │ │ ├── file_type_json5.svg │ │ ├── file_type_json_official.svg │ │ ├── file_type_jsonld.svg │ │ ├── file_type_jsp.svg │ │ ├── file_type_julia.svg │ │ ├── file_type_julia2.svg │ │ ├── file_type_jupyter.svg │ │ ├── file_type_karma.svg │ │ ├── file_type_key.svg │ │ ├── file_type_kitchenci.svg │ │ ├── file_type_kite.svg │ │ ├── file_type_kivy.svg │ │ ├── file_type_kos.svg │ │ ├── file_type_kotlin.svg │ │ ├── file_type_layout.svg │ │ ├── file_type_lerna.svg │ │ ├── file_type_less.svg │ │ ├── file_type_license.svg │ │ ├── file_type_light_babel.svg │ │ ├── file_type_light_babel2.svg │ │ ├── file_type_light_cabal.svg │ │ ├── file_type_light_circleci.svg │ │ ├── file_type_light_cloudfoundry.svg │ │ ├── file_type_light_codacy.svg │ │ ├── file_type_light_codeclimate.svg │ │ ├── file_type_light_config.svg │ │ ├── file_type_light_crystal.svg │ │ ├── file_type_light_db.svg │ │ ├── file_type_light_docpad.svg │ │ ├── file_type_light_drone.svg │ │ ├── file_type_light_font.svg │ │ ├── file_type_light_gamemaker2.svg │ │ ├── file_type_light_ini.svg │ │ ├── file_type_light_io.svg │ │ ├── file_type_light_js.svg │ │ ├── file_type_light_jsconfig.svg │ │ ├── file_type_light_jsmap.svg │ │ ├── file_type_light_json.svg │ │ ├── file_type_light_json5.svg │ │ ├── file_type_light_jsonld.svg │ │ ├── file_type_light_kite.svg │ │ ├── file_type_light_lerna.svg │ │ ├── file_type_light_mlang.svg │ │ ├── file_type_light_mustache.svg │ │ ├── file_type_light_openHAB.svg │ │ ├── file_type_light_pcl.svg │ │ ├── file_type_light_prettier.svg │ │ ├── file_type_light_purescript.svg │ │ ├── file_type_light_rubocop.svg │ │ ├── file_type_light_shaderlab.svg │ │ ├── file_type_light_solidity.svg │ │ ├── file_type_light_stylelint.svg │ │ ├── file_type_light_stylus.svg │ │ ├── file_type_light_symfony.svg │ │ ├── file_type_light_systemverilog.svg │ │ ├── file_type_light_testjs.svg │ │ ├── file_type_light_tex.svg │ │ ├── file_type_light_todo.svg │ │ ├── file_type_light_vash.svg │ │ ├── file_type_light_vsix.svg │ │ ├── file_type_light_yaml.svg │ │ ├── file_type_lime.svg │ │ ├── file_type_liquid.svg │ │ ├── file_type_lisp.svg │ │ ├── file_type_livescript.svg │ │ ├── file_type_locale.svg │ │ ├── file_type_log.svg │ │ ├── file_type_lolcode.svg │ │ ├── file_type_lsl.svg │ │ ├── file_type_lua.svg │ │ ├── file_type_lync.svg │ │ ├── file_type_makefile.svg │ │ ├── file_type_manifest.svg │ │ ├── file_type_manifest_bak.svg │ │ ├── file_type_manifest_skip.svg │ │ ├── file_type_map.svg │ │ ├── file_type_markdown.svg │ │ ├── file_type_markdownlint.svg │ │ ├── file_type_marko.svg │ │ ├── file_type_markojs.svg │ │ ├── file_type_matlab.png │ │ ├── file_type_maven.svg │ │ ├── file_type_maxscript.svg │ │ ├── file_type_maya.svg │ │ ├── file_type_mediawiki.svg │ │ ├── file_type_mercurial.svg │ │ ├── file_type_meson.svg │ │ ├── file_type_meteor.svg │ │ ├── file_type_mjml.svg │ │ ├── file_type_mlang.svg │ │ ├── file_type_mocha.svg │ │ ├── file_type_mojolicious.svg │ │ ├── file_type_monotone.svg │ │ ├── file_type_mson.svg │ │ ├── file_type_mustache.svg │ │ ├── file_type_ng_component_css.svg │ │ ├── file_type_ng_component_html.svg │ │ ├── file_type_ng_component_js.svg │ │ ├── file_type_ng_component_js2.svg │ │ ├── file_type_ng_component_less.svg │ │ ├── file_type_ng_component_sass.svg │ │ ├── file_type_ng_component_scss.svg │ │ ├── file_type_ng_component_ts.svg │ │ ├── file_type_ng_component_ts2.svg │ │ ├── file_type_ng_controller_js.svg │ │ ├── file_type_ng_controller_ts.svg │ │ ├── file_type_ng_directive_js.svg │ │ ├── file_type_ng_directive_js2.svg │ │ ├── file_type_ng_directive_ts.svg │ │ ├── file_type_ng_directive_ts2.svg │ │ ├── file_type_ng_guard_js.svg │ │ ├── file_type_ng_guard_ts.svg │ │ ├── file_type_ng_interceptor_js.svg │ │ ├── file_type_ng_interceptor_ts.svg │ │ ├── file_type_ng_module_js.svg │ │ ├── file_type_ng_module_js2.svg │ │ ├── file_type_ng_module_ts.svg │ │ ├── file_type_ng_module_ts2.svg │ │ ├── file_type_ng_pipe_js.svg │ │ ├── file_type_ng_pipe_js2.svg │ │ ├── file_type_ng_pipe_ts.svg │ │ ├── file_type_ng_pipe_ts2.svg │ │ ├── file_type_ng_routing_js.svg │ │ ├── file_type_ng_routing_js2.svg │ │ ├── file_type_ng_routing_ts.svg │ │ ├── file_type_ng_routing_ts2.svg │ │ ├── file_type_ng_service_js.svg │ │ ├── file_type_ng_service_js2.svg │ │ ├── file_type_ng_service_ts.svg │ │ ├── file_type_ng_service_ts2.svg │ │ ├── file_type_ng_smart_component_js.svg │ │ ├── file_type_ng_smart_component_js2.svg │ │ ├── file_type_ng_smart_component_ts.svg │ │ ├── file_type_ng_smart_component_ts2.svg │ │ ├── file_type_nginx.svg │ │ ├── file_type_nim.svg │ │ ├── file_type_njsproj.svg │ │ ├── file_type_node.svg │ │ ├── file_type_node2.svg │ │ ├── file_type_nodemon.svg │ │ ├── file_type_npm.svg │ │ ├── file_type_nsi.svg │ │ ├── file_type_nuget.svg │ │ ├── file_type_nunjucks.svg │ │ ├── file_type_nuxt.svg │ │ ├── file_type_nyc.svg │ │ ├── file_type_objectivec.svg │ │ ├── file_type_objectivecpp.svg │ │ ├── file_type_ocaml.svg │ │ ├── file_type_onenote.svg │ │ ├── file_type_openHAB.svg │ │ ├── file_type_opencl.svg │ │ ├── file_type_org.svg │ │ ├── file_type_outlook.svg │ │ ├── file_type_package.svg │ │ ├── file_type_paket.svg │ │ ├── file_type_patch.svg │ │ ├── file_type_pcl.svg │ │ ├── file_type_pdf.svg │ │ ├── file_type_pdf2.svg │ │ ├── file_type_perl.svg │ │ ├── file_type_perl2.svg │ │ ├── file_type_perl6.svg │ │ ├── file_type_pgsql.svg │ │ ├── file_type_photoshop.svg │ │ ├── file_type_photoshop2.svg │ │ ├── file_type_php.svg │ │ ├── file_type_php2.svg │ │ ├── file_type_php3.svg │ │ ├── file_type_phpcsfixer.svg │ │ ├── file_type_phpunit.svg │ │ ├── file_type_phraseapp.svg │ │ ├── file_type_pip.svg │ │ ├── file_type_plantuml.svg │ │ ├── file_type_plsql.svg │ │ ├── file_type_plsql_package.svg │ │ ├── file_type_plsql_package_body.svg │ │ ├── file_type_plsql_package_header.svg │ │ ├── file_type_plsql_package_spec.svg │ │ ├── file_type_poedit.svg │ │ ├── file_type_polymer.svg │ │ ├── file_type_postcss.svg │ │ ├── file_type_postcssconfig.svg │ │ ├── file_type_powerpoint.svg │ │ ├── file_type_powershell.svg │ │ ├── file_type_prettier.svg │ │ ├── file_type_processinglang.svg │ │ ├── file_type_procfile.svg │ │ ├── file_type_progress.svg │ │ ├── file_type_prolog.svg │ │ ├── file_type_prometheus.svg │ │ ├── file_type_protobuf.svg │ │ ├── file_type_protractor.svg │ │ ├── file_type_publisher.svg │ │ ├── file_type_pug.svg │ │ ├── file_type_puppet.svg │ │ ├── file_type_purescript.svg │ │ ├── file_type_pyret.svg │ │ ├── file_type_python.svg │ │ ├── file_type_q.svg │ │ ├── file_type_qlikview.svg │ │ ├── file_type_qsharp.svg │ │ ├── file_type_quasar.svg │ │ ├── file_type_r.svg │ │ ├── file_type_racket.svg │ │ ├── file_type_rails.svg │ │ ├── file_type_rake.svg │ │ ├── file_type_raml.svg │ │ ├── file_type_razor.svg │ │ ├── file_type_reactjs.svg │ │ ├── file_type_reacttemplate.svg │ │ ├── file_type_reactts.svg │ │ ├── file_type_reason.svg │ │ ├── file_type_registry.svg │ │ ├── file_type_rest.svg │ │ ├── file_type_riot.svg │ │ ├── file_type_robotframework.svg │ │ ├── file_type_robots.svg │ │ ├── file_type_rollup.svg │ │ ├── file_type_rproj.svg │ │ ├── file_type_rspec.svg │ │ ├── file_type_rubocop.svg │ │ ├── file_type_ruby.svg │ │ ├── file_type_rust.svg │ │ ├── file_type_saltstack.svg │ │ ├── file_type_sass.svg │ │ ├── file_type_sbt.svg │ │ ├── file_type_scala.svg │ │ ├── file_type_scilab.svg │ │ ├── file_type_script.svg │ │ ├── file_type_scss.svg │ │ ├── file_type_scss2.svg │ │ ├── file_type_sdlang.svg │ │ ├── file_type_sequelize.svg │ │ ├── file_type_shaderlab.svg │ │ ├── file_type_shell.svg │ │ ├── file_type_silverstripe.svg │ │ ├── file_type_sketch.svg │ │ ├── file_type_skipper.svg │ │ ├── file_type_slang.svg │ │ ├── file_type_slice.svg │ │ ├── file_type_slim.svg │ │ ├── file_type_sln.svg │ │ ├── file_type_smarty.svg │ │ ├── file_type_snort.svg │ │ ├── file_type_snyk.svg │ │ ├── file_type_solidarity.svg │ │ ├── file_type_solidity.svg │ │ ├── file_type_source.svg │ │ ├── file_type_sqf.svg │ │ ├── file_type_sql.svg │ │ ├── file_type_sqlite.svg │ │ ├── file_type_squirrel.svg │ │ ├── file_type_sss.svg │ │ ├── file_type_stata.svg │ │ ├── file_type_storyboard.svg │ │ ├── file_type_storybook.svg │ │ ├── file_type_stylable.svg │ │ ├── file_type_style.svg │ │ ├── file_type_stylelint.svg │ │ ├── file_type_stylus.svg │ │ ├── file_type_subversion.svg │ │ ├── file_type_svg.svg │ │ ├── file_type_swagger.svg │ │ ├── file_type_swift.svg │ │ ├── file_type_swig.svg │ │ ├── file_type_symfony.svg │ │ ├── file_type_systemverilog.svg │ │ ├── file_type_t4tt.svg │ │ ├── file_type_tcl.svg │ │ ├── file_type_terraform.svg │ │ ├── file_type_test.svg │ │ ├── file_type_testjs.svg │ │ ├── file_type_testts.svg │ │ ├── file_type_tex.svg │ │ ├── file_type_text.svg │ │ ├── file_type_textile.svg │ │ ├── file_type_tfs.svg │ │ ├── file_type_todo.svg │ │ ├── file_type_toml.svg │ │ ├── file_type_travis.svg │ │ ├── file_type_tsconfig.svg │ │ ├── file_type_tslint.svg │ │ ├── file_type_twig.svg │ │ ├── file_type_typescript.svg │ │ ├── file_type_typescript_official.svg │ │ ├── file_type_typescriptdef.svg │ │ ├── file_type_typescriptdef_official.svg │ │ ├── file_type_typo3.svg │ │ ├── file_type_vagrant.svg │ │ ├── file_type_vala.svg │ │ ├── file_type_vapi.svg │ │ ├── file_type_vash.svg │ │ ├── file_type_vb.svg │ │ ├── file_type_vba.svg │ │ ├── file_type_vbhtml.svg │ │ ├── file_type_vbproj.svg │ │ ├── file_type_vcxproj.svg │ │ ├── file_type_velocity.svg │ │ ├── file_type_verilog.svg │ │ ├── file_type_vhdl.svg │ │ ├── file_type_video.svg │ │ ├── file_type_view.svg │ │ ├── file_type_vim.svg │ │ ├── file_type_volt.svg │ │ ├── file_type_vscode.svg │ │ ├── file_type_vscode2.svg │ │ ├── file_type_vsix.svg │ │ ├── file_type_vue.svg │ │ ├── file_type_wallaby.svg │ │ ├── file_type_wasm.svg │ │ ├── file_type_watchmanconfig.svg │ │ ├── file_type_webpack.svg │ │ ├── file_type_wercker.svg │ │ ├── file_type_wolfram.svg │ │ ├── file_type_word.svg │ │ ├── file_type_wurst.svg │ │ ├── file_type_wxml.svg │ │ ├── file_type_wxss.svg │ │ ├── file_type_xcode.svg │ │ ├── file_type_xib.svg │ │ ├── file_type_xliff.svg │ │ ├── file_type_xml.svg │ │ ├── file_type_xsl.svg │ │ ├── file_type_yaml.svg │ │ ├── file_type_yamllint.svg │ │ ├── file_type_yang.svg │ │ ├── file_type_yarn.svg │ │ ├── file_type_yeoman.svg │ │ ├── file_type_zip.svg │ │ ├── file_type_zip2.svg │ │ ├── folder_type_api.svg │ │ ├── folder_type_api_opened.svg │ │ ├── folder_type_app.svg │ │ ├── folder_type_app_opened.svg │ │ ├── folder_type_asset.svg │ │ ├── folder_type_asset_opened.svg │ │ ├── folder_type_audio.svg │ │ ├── folder_type_audio_opened.svg │ │ ├── folder_type_aurelia.svg │ │ ├── folder_type_aurelia_opened.svg │ │ ├── folder_type_aws.svg │ │ ├── folder_type_aws_opened.svg │ │ ├── folder_type_binary.svg │ │ ├── folder_type_binary_opened.svg │ │ ├── folder_type_bower.svg │ │ ├── folder_type_bower_opened.svg │ │ ├── folder_type_cake.svg │ │ ├── folder_type_cake_opened.svg │ │ ├── folder_type_chef.svg │ │ ├── folder_type_chef_opened.svg │ │ ├── folder_type_circleci.svg │ │ ├── folder_type_circleci_opened.svg │ │ ├── folder_type_client.svg │ │ ├── folder_type_client_opened.svg │ │ ├── folder_type_component.svg │ │ ├── folder_type_component_opened.svg │ │ ├── folder_type_composer.svg │ │ ├── folder_type_composer_opened.svg │ │ ├── folder_type_config.svg │ │ ├── folder_type_config_opened.svg │ │ ├── folder_type_css.svg │ │ ├── folder_type_css_opened.svg │ │ ├── folder_type_cypress.svg │ │ ├── folder_type_cypress_opened.svg │ │ ├── folder_type_db.svg │ │ ├── folder_type_db_opened.svg │ │ ├── folder_type_debian.svg │ │ ├── folder_type_debian_opened.svg │ │ ├── folder_type_dist.svg │ │ ├── folder_type_dist_opened.svg │ │ ├── folder_type_docker.svg │ │ ├── folder_type_docker_opened.svg │ │ ├── folder_type_docs.svg │ │ ├── folder_type_docs_opened.svg │ │ ├── folder_type_elasticbeanstalk.svg │ │ ├── folder_type_elasticbeanstalk_opened.svg │ │ ├── folder_type_flow.svg │ │ ├── folder_type_flow_opened.svg │ │ ├── folder_type_fonts.svg │ │ ├── folder_type_fonts_opened.svg │ │ ├── folder_type_gcp.svg │ │ ├── folder_type_gcp_opened.svg │ │ ├── folder_type_git.svg │ │ ├── folder_type_git_opened.svg │ │ ├── folder_type_github.svg │ │ ├── folder_type_github_opened.svg │ │ ├── folder_type_gitlab.svg │ │ ├── folder_type_gitlab_opened.svg │ │ ├── folder_type_haxelib.svg │ │ ├── folder_type_haxelib_opened.svg │ │ ├── folder_type_helper.svg │ │ ├── folder_type_helper_opened.svg │ │ ├── folder_type_idea.svg │ │ ├── folder_type_idea_opened.svg │ │ ├── folder_type_images.svg │ │ ├── folder_type_images_opened.svg │ │ ├── folder_type_include.svg │ │ ├── folder_type_include_opened.svg │ │ ├── folder_type_js.svg │ │ ├── folder_type_js_opened.svg │ │ ├── folder_type_kubernetes.svg │ │ ├── folder_type_kubernetes_opened.svg │ │ ├── folder_type_less.svg │ │ ├── folder_type_less_opened.svg │ │ ├── folder_type_library.svg │ │ ├── folder_type_library_opened.svg │ │ ├── folder_type_light_fonts.svg │ │ ├── folder_type_light_fonts_opened.svg │ │ ├── folder_type_light_meteor.svg │ │ ├── folder_type_light_meteor_opened.svg │ │ ├── folder_type_light_node.svg │ │ ├── folder_type_light_node_opened.svg │ │ ├── folder_type_light_sass.svg │ │ ├── folder_type_light_sass_opened.svg │ │ ├── folder_type_locale.svg │ │ ├── folder_type_locale_opened.svg │ │ ├── folder_type_log.svg │ │ ├── folder_type_log_opened.svg │ │ ├── folder_type_maven.svg │ │ ├── folder_type_maven_opened.svg │ │ ├── folder_type_meteor.svg │ │ ├── folder_type_meteor_opened.svg │ │ ├── folder_type_mjml.svg │ │ ├── folder_type_mjml_opened.svg │ │ ├── folder_type_model.svg │ │ ├── folder_type_model_opened.svg │ │ ├── folder_type_mongodb.svg │ │ ├── folder_type_mongodb_opened.svg │ │ ├── folder_type_nginx.svg │ │ ├── folder_type_nginx_opened.svg │ │ ├── folder_type_node.svg │ │ ├── folder_type_node_opened.svg │ │ ├── folder_type_nuget.svg │ │ ├── folder_type_nuget_opened.svg │ │ ├── folder_type_package.svg │ │ ├── folder_type_package_opened.svg │ │ ├── folder_type_paket.svg │ │ ├── folder_type_paket_opened.svg │ │ ├── folder_type_php.svg │ │ ├── folder_type_php_opened.svg │ │ ├── folder_type_plugin.svg │ │ ├── folder_type_plugin_opened.svg │ │ ├── folder_type_private.svg │ │ ├── folder_type_private_opened.svg │ │ ├── folder_type_public.svg │ │ ├── folder_type_public_opened.svg │ │ ├── folder_type_ravendb.svg │ │ ├── folder_type_ravendb_opened.svg │ │ ├── folder_type_redis.svg │ │ ├── folder_type_redis_opened.svg │ │ ├── folder_type_route.svg │ │ ├── folder_type_route_opened.svg │ │ ├── folder_type_sass.svg │ │ ├── folder_type_sass_opened.svg │ │ ├── folder_type_script.svg │ │ ├── folder_type_script_opened.svg │ │ ├── folder_type_server.svg │ │ ├── folder_type_server_opened.svg │ │ ├── folder_type_src.svg │ │ ├── folder_type_src_opened.svg │ │ ├── folder_type_style.svg │ │ ├── folder_type_style_opened.svg │ │ ├── folder_type_temp.svg │ │ ├── folder_type_temp_opened.svg │ │ ├── folder_type_template.svg │ │ ├── folder_type_template_opened.svg │ │ ├── folder_type_test.svg │ │ ├── folder_type_test_opened.svg │ │ ├── folder_type_tools.svg │ │ ├── folder_type_tools_opened.svg │ │ ├── folder_type_travis.svg │ │ ├── folder_type_travis_opened.svg │ │ ├── folder_type_typescript.svg │ │ ├── folder_type_typescript_opened.svg │ │ ├── folder_type_typings.svg │ │ ├── folder_type_typings2.svg │ │ ├── folder_type_typings2_opened.svg │ │ ├── folder_type_typings_opened.svg │ │ ├── folder_type_vagrant.svg │ │ ├── folder_type_vagrant_opened.svg │ │ ├── folder_type_video.svg │ │ ├── folder_type_video_opened.svg │ │ ├── folder_type_view.svg │ │ ├── folder_type_view_opened.svg │ │ ├── folder_type_vs.svg │ │ ├── folder_type_vs_opened.svg │ │ ├── folder_type_vscode.svg │ │ ├── folder_type_vscode2.svg │ │ ├── folder_type_vscode2_opened.svg │ │ ├── folder_type_vscode_opened.svg │ │ ├── folder_type_vscode_test.svg │ │ ├── folder_type_vscode_test2.svg │ │ ├── folder_type_vscode_test2_opened.svg │ │ ├── folder_type_vscode_test_opened.svg │ │ ├── folder_type_webpack.svg │ │ ├── folder_type_webpack_opened.svg │ │ ├── folder_type_www.svg │ │ └── folder_type_www_opened.svg │ ├── next.svg │ ├── project-icons │ │ ├── more.svg │ │ ├── next-js.svg │ │ ├── node.svg │ │ ├── php.svg │ │ ├── python.svg │ │ └── react.svg │ └── vercel.svg ├── tailwind.config.ts └── tsconfig.json └── tests ├── .env.example ├── github.test.ts ├── package-lock.json ├── package.json ├── sandbox.test.ts ├── sockets.ts ├── tsconfig.json ├── user.test.ts └── utils ├── api.ts ├── auth.ts └── env.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | coverage 11 | 12 | # next.js 13 | .next/ 14 | out/ 15 | 16 | # production 17 | build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | wrangler.toml 40 | 41 | dist 42 | backend/server/projects 43 | 44 | app.yaml 45 | ingressController.yaml -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "semi": false, 4 | "singleQuote": false, 5 | "insertFinalNewline": true, 6 | "useTabs": false 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.formatOnSaveMode": "file", 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll": "explicit", 6 | "source.organizeImports": "explicit" 7 | }, 8 | "tailwindCSS.experimental.classRegex": [ 9 | ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], 10 | ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] 11 | ], 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | } 14 | -------------------------------------------------------------------------------- /backend/server/.dockerignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | projects -------------------------------------------------------------------------------- /backend/server/.env.example: -------------------------------------------------------------------------------- 1 | # The variables below are required. 2 | 3 | # PORT is the port used by NodeJS 4 | # SERVER_URL points to this server 5 | # E2B_API_KEY can be obtained at https://e2b.dev/ 6 | 7 | PORT=4000 8 | SERVER_URL=http://localhost:4000 9 | E2B_API_KEY= 10 | 11 | # The variables below are required to use deployments. 12 | 13 | # DOKKU_HOST and DOKKU_USERNAME are used to authenticate via SSH with the Dokku server 14 | # DOKKU_KEY is the path to an SSH (.pem) key on the local machine 15 | 16 | DOKKU_HOST= 17 | DOKKU_USERNAME= 18 | DOKKU_KEY= 19 | 20 | # DATABASE_URL is the connection string for the database 21 | 22 | DATABASE_URL= 23 | 24 | # CLERK_SECRET_KEY needed for making authenticated requests 25 | CLERK_SECRET_KEY= -------------------------------------------------------------------------------- /backend/server/dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20 2 | 3 | # Security: Drop all capabilities 4 | USER root 5 | RUN apt-get update && apt-get install -y libcap2-bin 6 | RUN setcap cap_net_bind_service=+ep /usr/local/bin/node 7 | 8 | WORKDIR /code 9 | 10 | COPY package*.json ./ 11 | 12 | RUN npm install 13 | 14 | COPY . . 15 | 16 | RUN npm run build 17 | 18 | # Security: Create non-root user and assign ownership 19 | RUN useradd -m appuser 20 | RUN mkdir projects && chown -R appuser:appuser projects 21 | USER appuser 22 | 23 | # todo user namespace mapping 24 | 25 | EXPOSE 5173 26 | EXPOSE 4000 27 | 28 | CMD [ "node", "dist/index.js" ] -------------------------------------------------------------------------------- /backend/server/drizzle.config.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config" 2 | import type { Config } from "drizzle-kit" 3 | import { defineConfig } from "drizzle-kit" 4 | 5 | export default defineConfig({ 6 | out: "./drizzle", 7 | schema: "./src/db/schema.ts", 8 | dialect: "postgresql", 9 | dbCredentials: { 10 | url: process.env.DATABASE_URL!, 11 | }, 12 | }) satisfies Config 13 | -------------------------------------------------------------------------------- /backend/server/drizzle/0001_unusual_archangel.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE "sandbox" ADD COLUMN "repositoryId" text; -------------------------------------------------------------------------------- /backend/server/drizzle/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7", 3 | "dialect": "postgresql", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "7", 8 | "when": 1739612282205, 9 | "tag": "0000_superb_nomad", 10 | "breakpoints": true 11 | }, 12 | { 13 | "idx": 1, 14 | "version": "7", 15 | "when": 1739612320600, 16 | "tag": "0001_unusual_archangel", 17 | "breakpoints": true 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /backend/server/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "src" 4 | ], 5 | "ext": "ts", 6 | "exec": "concurrently \"npx tsc --watch\" \"ts-node src/index.ts\"" 7 | } -------------------------------------------------------------------------------- /backend/server/src/db/migrate.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config" 2 | import { drizzle } from "drizzle-orm/node-postgres" 3 | import { migrate } from "drizzle-orm/node-postgres/migrator" 4 | import { Pool } from "pg" 5 | 6 | const pool = new Pool({ 7 | connectionString: process.env.DATABASE_URL, 8 | }) 9 | 10 | const db = drizzle(pool) 11 | 12 | async function main() { 13 | try { 14 | console.log("Starting migrations...") 15 | const start = Date.now() 16 | 17 | await migrate(db, { migrationsFolder: "./drizzle" }) 18 | 19 | const end = Date.now() 20 | console.log(`✅ Migrations completed successfully (${end - start}ms)`) 21 | 22 | } catch (error) { 23 | console.error("❌ Migration failed:", error) 24 | throw error 25 | } finally { 26 | await pool.end() 27 | } 28 | } 29 | 30 | main().catch((err) => { 31 | console.error("Migration process failed:", err) 32 | process.exit(1) 33 | }) 34 | -------------------------------------------------------------------------------- /backend/server/src/services/ConnectionManager.ts: -------------------------------------------------------------------------------- 1 | import { Socket } from "socket.io" 2 | 3 | // Owner Connection Management 4 | export class ConnectionManager { 5 | // Stores all sockets connected to a given sandbox 6 | private sockets: Record> = {} 7 | 8 | // Adds a connection for a sandbox 9 | addConnectionForProject(socket: Socket, projectId: string) { 10 | this.sockets[projectId] ??= new Set() 11 | this.sockets[projectId].add(socket) 12 | } 13 | 14 | // Removes a connection for a sandbox 15 | removeConnectionForProject(socket: Socket, projectId: string) { 16 | this.sockets[projectId]?.delete(socket) 17 | } 18 | 19 | // Returns the set of sockets connected to a given sandbox 20 | connectionsForProject(projectId: string): Set { 21 | return this.sockets[projectId] ?? new Set() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /backend/server/src/utils/clerk.ts: -------------------------------------------------------------------------------- 1 | import { Clerk } from "@clerk/clerk-sdk-node" 2 | import "dotenv/config" 3 | 4 | const clerkSecretKey = process.env.CLERK_SECRET_KEY 5 | if (!clerkSecretKey) { 6 | console.warn( 7 | "Missing CLERK_SECRET_KEY in environment variables. Authentication will not work." 8 | ) 9 | } 10 | 11 | export const clerkClient = clerkSecretKey 12 | ? Clerk({ secretKey: clerkSecretKey }) 13 | : null 14 | 15 | // Helper to check if Clerk is configured 16 | export const isClerkConfigured = (): boolean => !!clerkClient 17 | 18 | // Helper function to verify token and get user 19 | export const verifyClerkToken = async (token: string) => { 20 | if (!isClerkConfigured() || !clerkClient || !token) { 21 | throw new Error("Clerk is not configured or token is missing") 22 | } 23 | 24 | const decoded = await clerkClient.verifyToken(token) 25 | const user = await clerkClient.users.getUser(decoded.sub) 26 | return { decoded, user } 27 | } 28 | -------------------------------------------------------------------------------- /backend/server/src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | // The amount of time in ms that a container will stay alive without a hearbeat. 2 | export const CONTAINER_TIMEOUT = 3 * 60_000 3 | -------------------------------------------------------------------------------- /backend/server/src/utils/lock.ts: -------------------------------------------------------------------------------- 1 | export class LockManager { 2 | private locks: { [key: string]: Promise } 3 | 4 | constructor() { 5 | this.locks = {} 6 | } 7 | 8 | async acquireLock(key: string, task: () => Promise): Promise { 9 | if (!this.locks[key]) { 10 | this.locks[key] = new Promise(async (resolve, reject) => { 11 | try { 12 | const result = await task() 13 | resolve(result) 14 | } catch (error) { 15 | reject(error) 16 | } finally { 17 | delete this.locks[key] 18 | } 19 | }) 20 | } 21 | return await this.locks[key] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /backend/server/src/utils/ratelimit.ts: -------------------------------------------------------------------------------- 1 | import { RateLimiterMemory } from "rate-limiter-flexible" 2 | 3 | export const saveFileRL = new RateLimiterMemory({ 4 | points: 2, 5 | duration: 1, 6 | }) 7 | 8 | export const MAX_BODY_SIZE = 5 * 1024 * 1024 9 | 10 | export const createFileRL = new RateLimiterMemory({ 11 | points: 1, 12 | duration: 2, 13 | }) 14 | 15 | export const createFolderRL = new RateLimiterMemory({ 16 | points: 1, 17 | duration: 2, 18 | }) 19 | 20 | export const renameFileRL = new RateLimiterMemory({ 21 | points: 1, 22 | duration: 2, 23 | }) 24 | 25 | export const deleteFileRL = new RateLimiterMemory({ 26 | points: 1, 27 | duration: 2, 28 | }) 29 | 30 | export const deleteFolderRL = new RateLimiterMemory({ 31 | points: 1, 32 | duration: 2, 33 | }) 34 | -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | # The variables below are required. 2 | 3 | NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY= 4 | CLERK_SECRET_KEY= 5 | 6 | NEXT_PUBLIC_SERVER_PORT=4000 7 | NEXT_PUBLIC_APP_URL=http://localhost:3000 8 | NEXT_PUBLIC_SERVER_URL=http://localhost:4000 9 | 10 | NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in 11 | NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up 12 | NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard 13 | NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard 14 | 15 | # The variables below are required to use the AI assistant. 16 | # You need: 17 | # 1. OPENAI_API_KEY (required for applying AI-generated code diffs) 18 | # 2. EITHER Anthropic direct API OR AWS Bedrock configuration (for code generation) 19 | 20 | # Option 1: Direct Anthropic API 21 | ANTHROPIC_API_KEY= 22 | 23 | # Option 2: AWS Bedrock Configuration (all four required if using this option) 24 | AWS_ACCESS_KEY_ID= 25 | AWS_SECRET_ACCESS_KEY= 26 | AWS_REGION= 27 | AWS_ARN= 28 | 29 | # Required for code diffs 30 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /frontend/app/(app)/code/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation" 2 | 3 | export default function Page() { 4 | redirect("/") 5 | } 6 | -------------------------------------------------------------------------------- /frontend/app/(auth)/layout.tsx: -------------------------------------------------------------------------------- 1 | export default function AuthLayout({ 2 | children, 3 | }: { 4 | children: React.ReactNode 5 | }) { 6 | return ( 7 |
8 | {children} 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/loading/page.tsx: -------------------------------------------------------------------------------- 1 | import { Loader2 } from "lucide-react" 2 | 3 | export default function LoadingPage() { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /frontend/app/opengraph-image.alt.txt: -------------------------------------------------------------------------------- 1 | About Sandbox by Gitwit -------------------------------------------------------------------------------- /frontend/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesmurdza/sandbox/ddbf848699dc4cf00c44fce03602d498641d3f74/frontend/app/opengraph-image.png -------------------------------------------------------------------------------- /frontend/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Landing from "@/components/landing" 2 | import { currentUser } from "@clerk/nextjs/server" 3 | import { redirect } from "next/navigation" 4 | 5 | export default async function Home() { 6 | const user = await currentUser() 7 | 8 | if (user) { 9 | redirect("/dashboard") 10 | } 11 | 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /frontend/assets/x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/editor/CodeEditorWrapper.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import dynamic from "next/dynamic" 4 | import Loading from "./loading" 5 | 6 | // Dynamically import the CodeEditor with no SSR 7 | const CodeEditor = dynamic(() => import("./index"), { 8 | ssr: false, 9 | loading: () => , 10 | }) 11 | 12 | export default CodeEditor 13 | -------------------------------------------------------------------------------- /frontend/components/editor/live/room.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { RoomProvider } from "@/liveblocks.config" 4 | 5 | export function Room({ 6 | id, 7 | children, 8 | }: { 9 | id: string 10 | children: React.ReactNode 11 | }) { 12 | return ( 13 | 19 | {/* }> */} 20 | {children} 21 | {/* */} 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/components/logo.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import DarkLogo from "@/assets/logo-dark.svg" 4 | import LightLogo from "@/assets/logo-light.svg" 5 | import { useTheme } from "next-themes" 6 | import Image from "next/image" 7 | 8 | interface LogoProps extends React.HTMLAttributes { 9 | size?: number 10 | } 11 | export function Logo({ size = 36, ...props }: LogoProps) { 12 | const { resolvedTheme: theme } = useTheme() 13 | return ( 14 | Logo 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/components/query-client.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { getQueryClient } from "@/lib/get-query-client" 4 | import { QueryClientProvider as TanstackQueryClientProvider } from "@tanstack/react-query" 5 | import * as React from "react" 6 | 7 | export function QueryClientProvider({ 8 | children, 9 | }: { 10 | children: React.ReactNode 11 | }) { 12 | const queryClient = getQueryClient() 13 | // const token = await (await auth()).getToken() 14 | return ( 15 | 16 | {children} 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /frontend/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /frontend/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as LabelPrimitive from "@radix-ui/react-label" 4 | import { cva, type VariantProps } from "class-variance-authority" 5 | import * as React from "react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /frontend/components/ui/progress.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as ProgressPrimitive from "@radix-ui/react-progress" 4 | import * as React from "react" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Progress = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, value, ...props }, ref) => ( 12 | 20 | 24 | 25 | )) 26 | Progress.displayName = ProgressPrimitive.Root.displayName 27 | 28 | export { Progress } 29 | -------------------------------------------------------------------------------- /frontend/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /frontend/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { Toaster as Sonner } from "sonner" 5 | 6 | type ToasterProps = React.ComponentProps 7 | 8 | const Toaster = ({ ...props }: ToasterProps) => { 9 | const { theme = "system" } = useTheme() 10 | 11 | return ( 12 | 28 | ) 29 | } 30 | 31 | export { Toaster } 32 | -------------------------------------------------------------------------------- /frontend/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |