mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-23 02:34:21 +01:00
ignore: cloud stuff
This commit is contained in:
1
bun.lock
1
bun.lock
@@ -16,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"@ibm/plex": "6.4.1",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@opencode/cloud-core": "workspace:*",
|
||||
"@solidjs/meta": "^0.29.4",
|
||||
"@solidjs/router": "^0.15.0",
|
||||
"@solidjs/start": "^1.1.0",
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"@solidjs/router": "^0.15.0",
|
||||
"@solidjs/start": "^1.1.0",
|
||||
"solid-js": "^1.9.5",
|
||||
"vinxi": "^0.5.7"
|
||||
"vinxi": "^0.5.7",
|
||||
"@opencode/cloud-core": "workspace:*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
|
||||
@@ -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>
|
||||
<ErrorBoundary fallback={<div>Something went wrong</div>}>
|
||||
<Suspense>{props.children}</Suspense>
|
||||
</ErrorBoundary>
|
||||
</MetaProvider>
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
|
||||
15
cloud/app/src/routes/[workspaceID].tsx
Normal file
15
cloud/app/src/routes/[workspaceID].tsx
Normal file
@@ -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>
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
9
cloud/app/sst-env.d.ts
vendored
Normal file
9
cloud/app/sst-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/* This file is auto-generated by SST. Do not edit. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* deno-fmt-ignore-file */
|
||||
|
||||
/// <reference path="../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
@@ -20,7 +20,6 @@ export namespace Actor {
|
||||
properties: {
|
||||
userID: string
|
||||
workspaceID: string
|
||||
email: string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Resource } from "sst"
|
||||
export * from "drizzle-orm"
|
||||
import postgres from "postgres"
|
||||
|
||||
function createClient() {
|
||||
const createClient = memo(() => {
|
||||
const client = postgres({
|
||||
idle_timeout: 30000,
|
||||
connect_timeout: 30000,
|
||||
@@ -19,12 +19,13 @@ function createClient() {
|
||||
})
|
||||
|
||||
return drizzle(client, {})
|
||||
}
|
||||
})
|
||||
|
||||
import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
|
||||
import type { ExtractTablesWithRelations } from "drizzle-orm"
|
||||
import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js"
|
||||
import { Context } from "../context"
|
||||
import { memo } from "../util/memo"
|
||||
|
||||
export namespace Database {
|
||||
export type Transaction = PgTransaction<
|
||||
|
||||
11
cloud/core/src/util/memo.ts
Normal file
11
cloud/core/src/util/memo.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export function memo<T>(fn: () => T) {
|
||||
let value: T | undefined
|
||||
let loaded = false
|
||||
|
||||
return (): T => {
|
||||
if (loaded) return value as T
|
||||
loaded = true
|
||||
value = fn()
|
||||
return value as T
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@ import { Resource } from "sst"
|
||||
import { z } from "zod"
|
||||
import { issuer } from "@openauthjs/openauth"
|
||||
import { createSubjects } from "@openauthjs/openauth/subject"
|
||||
import { CodeProvider } from "@openauthjs/openauth/provider/code"
|
||||
import { GithubProvider } from "@openauthjs/openauth/provider/github"
|
||||
import { GoogleOidcProvider } from "@openauthjs/openauth/provider/google"
|
||||
import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare"
|
||||
import { Account } from "@opencode/cloud-core/account.js"
|
||||
import { Workspace } from "@opencode/cloud-core/workspace.js"
|
||||
import { Actor } from "@opencode/cloud-core/actor.js"
|
||||
|
||||
type Env = {
|
||||
AuthStorage: KVNamespace
|
||||
@@ -117,6 +118,12 @@ export default {
|
||||
email: email!,
|
||||
})
|
||||
}
|
||||
await Actor.provide("account", { accountID, email }, async () => {
|
||||
const workspaces = await Account.workspaces()
|
||||
if (workspaces.length === 0) {
|
||||
await Workspace.create()
|
||||
}
|
||||
})
|
||||
return ctx.subject("account", accountID, { accountID, email })
|
||||
},
|
||||
}).fetch(request, env, ctx)
|
||||
|
||||
4
cloud/function/sst-env.d.ts
vendored
4
cloud/function/sst-env.d.ts
vendored
@@ -14,10 +14,6 @@ declare module "sst" {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
}
|
||||
"DATABASE_PASSWORD": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
|
||||
9
github/sst-env.d.ts
vendored
Normal file
9
github/sst-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/* This file is auto-generated by SST. Do not edit. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* deno-fmt-ignore-file */
|
||||
|
||||
/// <reference path="../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
@@ -25,9 +25,9 @@ export const api = new sst.cloudflare.Worker("Api", {
|
||||
])
|
||||
args.migrations = {
|
||||
// Note: when releasing the next tag, make sure all stages use tag v2
|
||||
oldTag: $app.stage === "production" ? "" : "v1",
|
||||
newTag: $app.stage === "production" ? "" : "v1",
|
||||
//newSqliteClasses: ["SyncServer"],
|
||||
// oldTag: $app.stage === "production" ? "" : "v1",
|
||||
// newTag: $app.stage === "production" ? "" : "v1",
|
||||
newSqliteClasses: ["SyncServer"],
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ const DATABASE_USERNAME = new sst.Secret("DATABASE_USERNAME")
|
||||
const DATABASE_PASSWORD = new sst.Secret("DATABASE_PASSWORD")
|
||||
export const database = new sst.Linkable("Database", {
|
||||
properties: {
|
||||
host: "aws-us-east-2-1.pg.psdb.cloud",
|
||||
host: `aws-us-east-2-${$app.stage === "thdxr" ? "2" : "1"}.pg.psdb.cloud`,
|
||||
database: "postgres",
|
||||
username: DATABASE_USERNAME.value,
|
||||
password: DATABASE_PASSWORD.value,
|
||||
@@ -106,6 +106,7 @@ export const gateway = new sst.cloudflare.Worker("GatewayApi", {
|
||||
// CONSOLE
|
||||
////////////////
|
||||
|
||||
/*
|
||||
export const console = new sst.cloudflare.x.StaticSite("Console", {
|
||||
domain: `console.${domain}`,
|
||||
path: "cloud/web",
|
||||
@@ -119,3 +120,15 @@ export const console = new sst.cloudflare.x.StaticSite("Console", {
|
||||
VITE_AUTH_URL: auth.url.apply((url) => url!),
|
||||
},
|
||||
})
|
||||
*/
|
||||
|
||||
new sst.x.DevCommand("Solid", {
|
||||
link: [database],
|
||||
dev: {
|
||||
directory: "cloud/app",
|
||||
command: "bun dev",
|
||||
},
|
||||
environment: {
|
||||
VITE_AUTH_URL: auth.url.apply((url) => url!),
|
||||
},
|
||||
})
|
||||
|
||||
4
packages/function/sst-env.d.ts
vendored
4
packages/function/sst-env.d.ts
vendored
@@ -14,10 +14,6 @@ declare module "sst" {
|
||||
"type": "sst.sst.Linkable"
|
||||
"value": string
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
}
|
||||
"DATABASE_PASSWORD": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
|
||||
4
sst-env.d.ts
vendored
4
sst-env.d.ts
vendored
@@ -27,10 +27,6 @@ declare module "sst" {
|
||||
"Bucket": {
|
||||
"type": "sst.cloudflare.Bucket"
|
||||
}
|
||||
"Console": {
|
||||
"type": "sst.cloudflare.StaticSite"
|
||||
"url": string
|
||||
}
|
||||
"DATABASE_PASSWORD": {
|
||||
"type": "sst.sst.Secret"
|
||||
"value": string
|
||||
|
||||
Reference in New Issue
Block a user