diff --git a/app/components/TerminalPage.tsx b/app/components/TerminalPage.tsx index 1f1a426a..cbebe3e5 100644 --- a/app/components/TerminalPage.tsx +++ b/app/components/TerminalPage.tsx @@ -4,6 +4,7 @@ import { useEffect, useState, ReactNode } from "react"; import { usePrivy } from "@privy-io/react-auth"; import TerminalComponent from "./Terminal"; import { TerminalData } from "./TerminalData"; +import { useSetupSandbox } from "../hooks/useSetupSandbox"; export default function TerminalPage({ agentEndpoint, @@ -14,6 +15,7 @@ export default function TerminalPage({ }) { const [mounted, setMounted] = useState(false); const { ready, authenticated, login, getAccessToken } = usePrivy(); + useSetupSandbox(); useEffect(() => { setMounted(true); diff --git a/app/hooks/useSetupSandbox.ts b/app/hooks/useSetupSandbox.ts new file mode 100644 index 00000000..af498b72 --- /dev/null +++ b/app/hooks/useSetupSandbox.ts @@ -0,0 +1,29 @@ +import { useEffect, useRef } from "react"; +import { usePrivy } from "@privy-io/react-auth"; +import { getSandboxes } from "@/lib/recoup-api/getSandboxes"; +import { setupSandbox } from "@/lib/recoup-api/setupSandbox"; + +export function useSetupSandbox() { + const { authenticated, getAccessToken } = usePrivy(); + const hasRun = useRef(false); + + useEffect(() => { + if (!authenticated || hasRun.current) return; + hasRun.current = true; + + (async () => { + try { + const token = await getAccessToken(); + if (!token) return; + + const data = await getSandboxes(token); + if (!data) return; + if (data.snapshot_id && data.github_repo) return; + + setupSandbox(token); + } catch { + // Silent — background provisioning only + } + })(); + }, [authenticated, getAccessToken]); +} diff --git a/lib/consts.ts b/lib/consts.ts new file mode 100644 index 00000000..c667cf3f --- /dev/null +++ b/lib/consts.ts @@ -0,0 +1,5 @@ +const IS_PROD = process.env.NEXT_PUBLIC_VERCEL_ENV === "production"; + +export const RECOUP_API_URL = IS_PROD + ? "https://recoup-api.vercel.app" + : "https://test-recoup-api.vercel.app"; diff --git a/lib/recoup-api/createSandbox.ts b/lib/recoup-api/createSandbox.ts index 24e13208..56ec3b35 100644 --- a/lib/recoup-api/createSandbox.ts +++ b/lib/recoup-api/createSandbox.ts @@ -1,7 +1,4 @@ -const IS_PROD = process.env.NEXT_PUBLIC_VERCEL_ENV === "production"; -const RECOUP_API_URL = IS_PROD - ? "https://recoup-api.vercel.app" - : "https://test-recoup-api.vercel.app"; +import { RECOUP_API_URL } from "@/lib/consts"; export async function createSandbox( bearerToken: string, diff --git a/lib/recoup-api/getSandboxes.ts b/lib/recoup-api/getSandboxes.ts new file mode 100644 index 00000000..fe7569c7 --- /dev/null +++ b/lib/recoup-api/getSandboxes.ts @@ -0,0 +1,11 @@ +import { RECOUP_API_URL } from "@/lib/consts"; + +export async function getSandboxes(bearerToken: string) { + const response = await fetch(`${RECOUP_API_URL}/api/sandboxes`, { + headers: { Authorization: `Bearer ${bearerToken}` }, + }); + + if (!response.ok) return null; + + return response.json(); +} diff --git a/lib/recoup-api/setupSandbox.ts b/lib/recoup-api/setupSandbox.ts new file mode 100644 index 00000000..7f193eda --- /dev/null +++ b/lib/recoup-api/setupSandbox.ts @@ -0,0 +1,8 @@ +import { RECOUP_API_URL } from "@/lib/consts"; + +export function setupSandbox(bearerToken: string) { + fetch(`${RECOUP_API_URL}/api/sandboxes/setup`, { + method: "POST", + headers: { Authorization: `Bearer ${bearerToken}` }, + }); +} diff --git a/lib/recoup-api/updateAccountSnapshot.ts b/lib/recoup-api/updateAccountSnapshot.ts index 19712984..b2bb7626 100644 --- a/lib/recoup-api/updateAccountSnapshot.ts +++ b/lib/recoup-api/updateAccountSnapshot.ts @@ -1,7 +1,4 @@ -const IS_PROD = process.env.NEXT_PUBLIC_VERCEL_ENV === "production"; -const RECOUP_API_URL = IS_PROD - ? "https://recoup-api.vercel.app" - : "https://test-recoup-api.vercel.app"; +import { RECOUP_API_URL } from "@/lib/consts"; export async function updateAccountSnapshot( bearerToken: string,