diff --git a/.env.example b/.env.example index 975c3f5..34fe23c 100644 --- a/.env.example +++ b/.env.example @@ -4,8 +4,8 @@ SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # Docker sandbox SANDBOX_IMAGE=simples-runner:latest -EXEC_TIMEOUT_S=10 -COMPILE_TIMEOUT_S=15 +EXEC_TIMEOUT_S=30 +COMPILE_TIMEOUT_S=30 MAX_CODE_KB=64 RUNS_PER_MINUTE=30 diff --git a/docker-compose.yml b/docker-compose.yml index 6d93bce..6ab977d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,8 +38,8 @@ services: - SUPABASE_URL=${SUPABASE_URL:-} - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY:-} - SUPABASE_JWT_SECRET=${SUPABASE_JWT_SECRET:-} - - EXEC_TIMEOUT_S=${EXEC_TIMEOUT_S:-10} - - COMPILE_TIMEOUT_S=${COMPILE_TIMEOUT_S:-15} + - EXEC_TIMEOUT_S=${EXEC_TIMEOUT_S:-30} + - COMPILE_TIMEOUT_S=${COMPILE_TIMEOUT_S:-30} - MAX_CODE_KB=${MAX_CODE_KB:-64} - RUNS_PER_MINUTE=${RUNS_PER_MINUTE:-30} - SANDBOX_IMAGE=${SANDBOX_IMAGE:-simples-runner:latest} diff --git a/frontend/app.config.ts b/frontend/app.config.ts deleted file mode 100644 index c82573a..0000000 --- a/frontend/app.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import { tanstackStart } from '@tanstack/react-start/plugin/vite' -import tailwindcss from '@tailwindcss/vite' -import tsconfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - plugins: [ - tsconfigPaths({ projects: ['./tsconfig.json'] }), - tailwindcss(), - react(), - tanstackStart(), - ], -}) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index df2c125..47bcc80 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -327,6 +327,7 @@ function App() { case "asm_generated": setAsmOutput((msg.asm as string) || ""); + setIsCompiling(false); termRef.current?.writeln("\x1b[1;32m✓ Compilação concluída (NASM gerado)\x1b[0m"); break; @@ -344,6 +345,7 @@ function App() { break; case "compile_error": { + setIsCompiling(false); const rawErrors = msg.errors as CompileError[] | undefined; const errors: CompileError[] = rawErrors?.length ? rawErrors : [{ line: (msg.line as number) || 0, @@ -384,37 +386,39 @@ function App() { setCompileErrors([]); clearEditorMarkers(); - // First, compile via REST - fetch("/api/compile", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ code: currentCode }), - }) - .then((res) => res.json()) - .then((data: { success: boolean; asm?: string; errors?: CompileError[] }) => { - if (data.success) { - setAsmOutput(data.asm || ""); - // Now execute via WebSocket - const ws = wsRef.current; - if (ws?.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ type: "compile_and_run", code: currentCode })); - } - } else { - const errors = data.errors?.length ? data.errors : [{ - line: 0, column: 0, message: "Erro de compilação", phase: "compiler", - }]; - setCompileErrors(errors); - setEditorMarkers(errors); - } - }) - .catch((e) => { - setCompileErrors([{ - line: 0, column: 0, - message: `Erro de rede: ${e instanceof Error ? e.message : String(e)}`, - phase: "network", - }]); + // Send via WebSocket — o handler WS compila, retorna NASM (asm_generated) + // e executa em uma única requisição. Evita compilar DUAS vezes. + const ws = wsRef.current; + if (ws?.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ type: "compile_and_run", code: currentCode })); + } else { + // Fallback: WebSocket não conectado — compila via REST (somente NASM) + fetch("/api/compile", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ code: currentCode }), }) - .finally(() => setIsCompiling(false)); + .then((res) => res.json()) + .then((data: { success: boolean; asm?: string; errors?: CompileError[] }) => { + if (data.success) { + setAsmOutput(data.asm || ""); + } else { + const errors = data.errors?.length ? data.errors : [{ + line: 0, column: 0, message: "Erro de compilação", phase: "compiler", + }]; + setCompileErrors(errors); + setEditorMarkers(errors); + } + }) + .catch((e) => { + setCompileErrors([{ + line: 0, column: 0, + message: `Erro de rede: ${e instanceof Error ? e.message : String(e)}`, + phase: "network", + }]); + }) + .finally(() => setIsCompiling(false)); + } }, [code, clearEditorMarkers, setEditorMarkers]); const handleStop = useCallback(() => { diff --git a/frontend/src/client.tsx b/frontend/src/client.tsx deleted file mode 100644 index 35518b4..0000000 --- a/frontend/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from "react-dom/client"; -import { StartClient } from "@tanstack/react-start"; -import { createRouter } from "./router"; - -const router = createRouter(); - -hydrateRoot(document, ); diff --git a/frontend/src/components/LoginPage.tsx b/frontend/src/components/LoginPage.tsx index 1ab86b6..e93fc92 100644 --- a/frontend/src/components/LoginPage.tsx +++ b/frontend/src/components/LoginPage.tsx @@ -1,6 +1,6 @@ import { Auth } from "@supabase/auth-ui-react"; import { ThemeSupa } from "@supabase/auth-ui-shared"; -import { supabase } from "src/lib/supabase"; +import { supabase } from "../lib/supabase"; const siteUrl = import.meta.env.VITE_SITE_URL || (typeof window !== "undefined" ? window.location.origin : ""); diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts deleted file mode 100644 index 8f793fe..0000000 --- a/frontend/src/routeTree.gen.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Route tree generated manually for TanStack React Router. -// Based on the file-based routes in src/routes/* - -import { rootRoute } from "./routes/__root"; -import { loginRoute } from "./routes/login"; -import { indexRoute } from "./routes/index"; - -export const routeTree = rootRoute.addChildren([ - indexRoute, - loginRoute, -]); diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx deleted file mode 100644 index b10be8a..0000000 --- a/frontend/src/router.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { createRouter as createTanStackRouter } from "@tanstack/react-router"; -import { routeTree } from "./routeTree.gen"; - -export function createRouter() { - const router = createTanStackRouter({ - routeTree, - defaultPreload: "intent", - scrollRestoration: true, - }); - - return router; -} - -declare module "@tanstack/react-router" { - interface Register { - router: ReturnType; - } -} diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx deleted file mode 100644 index 030f386..0000000 --- a/frontend/src/routes/__root.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { createRootRoute, Outlet, HeadContent, Scripts } from "@tanstack/react-router"; - -export const rootRoute = createRootRoute({ - component: RootLayout, -}); - -function RootLayout() { - return ( - - - - - - Simples Editor - - - - - - - ); -} diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx deleted file mode 100644 index 61a9546..0000000 --- a/frontend/src/routes/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { createRoute, redirect } from "@tanstack/react-router"; -import { supabase } from "@/lib/supabase"; -import { rootRoute } from "./__root"; -import App from "@/App"; - -// ── Route ─────────────────────────────────────────────────────────────────── - -export const indexRoute = createRoute({ - getParentRoute: () => rootRoute, - path: "/", - component: App, - beforeLoad: async () => { - // Modo demonstração: pula autenticação Supabase - if (import.meta.env.VITE_DEMO_MODE === "true") { - return; - } - try { - const { data } = await supabase.auth.getSession(); - if (!data.session) { - throw redirect({ to: "/login" }); - } - } catch (error) { - if (error instanceof Response || (error as any)?.redirect) throw error; - throw redirect({ to: "/login" }); - } - }, -}); diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx deleted file mode 100644 index b988907..0000000 --- a/frontend/src/routes/login.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { createRoute, redirect } from "@tanstack/react-router"; -import { supabase } from "@/lib/supabase"; -import { rootRoute } from "./__root"; -import { LoginPage } from "@/components/LoginPage"; - -export const loginRoute = createRoute({ - getParentRoute: () => rootRoute, - path: "/login", - component: LoginRoute, - beforeLoad: async () => { - try { - const { data } = await supabase.auth.getSession(); - if (data.session) { - throw redirect({ to: "/" }); - } - } catch (error) { - if (error instanceof Response || (error as any)?.redirect) throw error; - // Se o Supabase está offline, permite continuar para mostrar a UI de login - } - }, -}); - -function LoginRoute() { - return ( -
-
-
-

Simples Editor

-

- IDE web para a linguagem SIMPLES -

-
- -
-
- ); -} diff --git a/frontend/src/ssr.tsx b/frontend/src/ssr.tsx deleted file mode 100644 index f1a09f2..0000000 --- a/frontend/src/ssr.tsx +++ /dev/null @@ -1,7 +0,0 @@ -/// -import { createStartHandler, defaultStreamHandler } from "@tanstack/react-start/server"; -import { createRouter } from "./router"; - -export default createStartHandler({ - createRouter, -})(defaultStreamHandler); diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 81e0db5..f1e4266 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -12,6 +12,7 @@ export default defineConfig({ resolve: { alias: { "@": "/src", + src: "/src", }, }, server: {