diff options
Diffstat (limited to 'cloud/app/src')
| -rw-r--r-- | cloud/app/src/app.tsx | 6 | ||||
| -rw-r--r-- | cloud/app/src/context/auth.tsx | 85 | ||||
| -rw-r--r-- | cloud/app/src/routes/[workspaceID].tsx | 15 | ||||
| -rw-r--r-- | cloud/app/src/routes/auth/callback.ts | 5 | ||||
| -rw-r--r-- | cloud/app/src/routes/index.tsx | 18 |
5 files changed, 120 insertions, 9 deletions
diff --git a/cloud/app/src/app.tsx b/cloud/app/src/app.tsx index 04c569b91..504318995 100644 --- a/cloud/app/src/app.tsx +++ b/cloud/app/src/app.tsx @@ -1,7 +1,7 @@ import { MetaProvider, Title } from "@solidjs/meta"; import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; -import { Suspense } from "solid-js"; +import { ErrorBoundary, Suspense } from "solid-js"; import "@ibm/plex/css/ibm-plex.css"; import "./app.css"; @@ -11,7 +11,9 @@ export default function App() { root={props => ( <MetaProvider> <Title>SolidStart - Basic</Title> - <Suspense>{props.children}</Suspense> + <ErrorBoundary fallback={<div>Something went wrong</div>}> + <Suspense>{props.children}</Suspense> + </ErrorBoundary> </MetaProvider> )} > diff --git a/cloud/app/src/context/auth.tsx b/cloud/app/src/context/auth.tsx index bec949568..88d3214c1 100644 --- a/cloud/app/src/context/auth.tsx +++ b/cloud/app/src/context/auth.tsx @@ -1,9 +1,90 @@ + + import { useSession } from "vinxi/http" import { createClient } from "@openauthjs/openauth/client" +import { getRequestEvent } from "solid-js/web" +import { and, Database, eq, inArray } from "@opencode/cloud-core/drizzle/index.js" +import { WorkspaceTable } from "@opencode/cloud-core/schema/workspace.sql.js" +import { UserTable } from "@opencode/cloud-core/schema/user.sql.js" +import { query, redirect } from "@solidjs/router" +import { AccountTable } from "@opencode/cloud-core/schema/account.sql.js" +import { Actor } from "@opencode/cloud-core/actor.js" + +export async function withActor<T>(fn: () => T) { + const actor = await getActor() + return Actor.provide(actor.type, actor.properties, fn) +} + +export const getActor = query(async (): Promise<Actor.Info> => { + "use server" + const evt = getRequestEvent() + const url = new URL(evt!.request.headers.get("referer") ?? evt!.request.url) + const auth = await useAuthSession() + const [workspaceHint] = url.pathname.split("/").filter((x) => x.length > 0) + if (!workspaceHint) { + if (auth.data.current) { + const current = auth.data.account[auth.data.current] + return { + type: "account", + properties: { + email: current.email, + accountID: current.id, + }, + } + } + if (Object.keys(auth.data.account).length > 0) { + const current = Object.values(auth.data.account)[0] + await auth.update(val => ({ + ...val, + current: current.id, + })) + return { + type: "account", + properties: { + email: current.email, + accountID: current.id, + }, + } + } + return { + type: "public", + properties: {}, + } + } + const accounts = Object.keys(auth.data.account) + const result = await Database.transaction(async (tx) => { + return await tx.select({ + user: UserTable + }) + .from(AccountTable) + .innerJoin(UserTable, and(eq(UserTable.email, AccountTable.email))) + .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID)) + .where( + and( + inArray(AccountTable.id, accounts), + eq(WorkspaceTable.id, workspaceHint), + ) + ) + .limit(1) + .execute() + .then((x) => x[0]) + }) + if (result) { + return { + type: "user", + properties: { + userID: result.user.id, + workspaceID: result.user.workspaceID, + }, + } + } + throw redirect("/auth/authorize") +}, "actor") + export const AuthClient = createClient({ clientID: "app", - issuer: "https://auth.dev.opencode.ai", + issuer: import.meta.env.VITE_AUTH_URL, }) export interface AuthSession { @@ -15,7 +96,6 @@ export interface AuthSession { } export function useAuthSession() { - "use server" return useSession<AuthSession>({ password: "0".repeat(32), @@ -26,3 +106,4 @@ export function useAuthSession() { export function AuthProvider() { } + diff --git a/cloud/app/src/routes/[workspaceID].tsx b/cloud/app/src/routes/[workspaceID].tsx new file mode 100644 index 000000000..706a64323 --- /dev/null +++ b/cloud/app/src/routes/[workspaceID].tsx @@ -0,0 +1,15 @@ +import { createAsync, query } from "@solidjs/router" +import { getActor, withActor } from "~/context/auth" + +const getPosts = query(async () => { + "use server" + return withActor(() => { + return "ok" + }) +}, "posts") + + +export default function () { + const actor = createAsync(async () => getActor()) + return <div>{JSON.stringify(actor())}</div> +} diff --git a/cloud/app/src/routes/auth/callback.ts b/cloud/app/src/routes/auth/callback.ts index a561c70d0..22dcb2b6d 100644 --- a/cloud/app/src/routes/auth/callback.ts +++ b/cloud/app/src/routes/auth/callback.ts @@ -5,11 +5,6 @@ export async function GET(input: APIEvent) { const url = new URL(input.request.url) const code = url.searchParams.get("code") if (!code) throw new Error("No code found") - const redirectURI = `${url.origin}${url.pathname}` - console.log({ - redirectURI, - code, - }) const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`) if (result.err) { throw new Error(result.err.message) diff --git a/cloud/app/src/routes/index.tsx b/cloud/app/src/routes/index.tsx index da4e23364..057ddb49e 100644 --- a/cloud/app/src/routes/index.tsx +++ b/cloud/app/src/routes/index.tsx @@ -6,6 +6,9 @@ import IMG_SPLASH from "../asset/screenshot-splash.webp" import IMG_VSCODE from "../asset/screenshot-vscode.webp" import IMG_GITHUB from "../asset/screenshot-github.webp" import { IconCopy, IconCheck } from "../component/icon" +import { createAsync, query, redirect, RouteDefinition } from "@solidjs/router" +import { getActor, withActor } from "~/context/auth" +import { Account } from "@opencode/cloud-core/account.js" function CopyStatus() { return ( @@ -16,7 +19,22 @@ function CopyStatus() { ) } +const isLoggedIn = query(async () => { + "use server" + const actor = await getActor() + if (actor.type === "account") { + const workspaces = await withActor(() => Account.workspaces()) + throw redirect("/" + workspaces[0].id) + } + return +}, "isLoggedIn") + + + export default function Home() { + createAsync(() => isLoggedIn(), { + deferStream: true, + }) onMount(() => { const commands = document.querySelectorAll("[data-copy]") for (const button of commands) { |
