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": {
|
"dependencies": {
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||||
|
"@opencode/cloud-core": "workspace:*",
|
||||||
"@solidjs/meta": "^0.29.4",
|
"@solidjs/meta": "^0.29.4",
|
||||||
"@solidjs/router": "^0.15.0",
|
"@solidjs/router": "^0.15.0",
|
||||||
"@solidjs/start": "^1.1.0",
|
"@solidjs/start": "^1.1.0",
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"@solidjs/router": "^0.15.0",
|
"@solidjs/router": "^0.15.0",
|
||||||
"@solidjs/start": "^1.1.0",
|
"@solidjs/start": "^1.1.0",
|
||||||
"solid-js": "^1.9.5",
|
"solid-js": "^1.9.5",
|
||||||
"vinxi": "^0.5.7"
|
"vinxi": "^0.5.7",
|
||||||
|
"@opencode/cloud-core": "workspace:*"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MetaProvider, Title } from "@solidjs/meta";
|
import { MetaProvider, Title } from "@solidjs/meta";
|
||||||
import { Router } from "@solidjs/router";
|
import { Router } from "@solidjs/router";
|
||||||
import { FileRoutes } from "@solidjs/start/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 "@ibm/plex/css/ibm-plex.css";
|
||||||
import "./app.css";
|
import "./app.css";
|
||||||
|
|
||||||
@@ -11,7 +11,9 @@ export default function App() {
|
|||||||
root={props => (
|
root={props => (
|
||||||
<MetaProvider>
|
<MetaProvider>
|
||||||
<Title>SolidStart - Basic</Title>
|
<Title>SolidStart - Basic</Title>
|
||||||
|
<ErrorBoundary fallback={<div>Something went wrong</div>}>
|
||||||
<Suspense>{props.children}</Suspense>
|
<Suspense>{props.children}</Suspense>
|
||||||
|
</ErrorBoundary>
|
||||||
</MetaProvider>
|
</MetaProvider>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,9 +1,90 @@
|
|||||||
|
|
||||||
|
|
||||||
import { useSession } from "vinxi/http"
|
import { useSession } from "vinxi/http"
|
||||||
import { createClient } from "@openauthjs/openauth/client"
|
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({
|
export const AuthClient = createClient({
|
||||||
clientID: "app",
|
clientID: "app",
|
||||||
issuer: "https://auth.dev.opencode.ai",
|
issuer: import.meta.env.VITE_AUTH_URL,
|
||||||
})
|
})
|
||||||
|
|
||||||
export interface AuthSession {
|
export interface AuthSession {
|
||||||
@@ -15,7 +96,6 @@ export interface AuthSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useAuthSession() {
|
export function useAuthSession() {
|
||||||
"use server"
|
|
||||||
|
|
||||||
return useSession<AuthSession>({
|
return useSession<AuthSession>({
|
||||||
password: "0".repeat(32),
|
password: "0".repeat(32),
|
||||||
@@ -26,3 +106,4 @@ export function useAuthSession() {
|
|||||||
|
|
||||||
export function AuthProvider() {
|
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 url = new URL(input.request.url)
|
||||||
const code = url.searchParams.get("code")
|
const code = url.searchParams.get("code")
|
||||||
if (!code) throw new Error("No code found")
|
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}`)
|
const result = await AuthClient.exchange(code, `${url.origin}${url.pathname}`)
|
||||||
if (result.err) {
|
if (result.err) {
|
||||||
throw new Error(result.err.message)
|
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_VSCODE from "../asset/screenshot-vscode.webp"
|
||||||
import IMG_GITHUB from "../asset/screenshot-github.webp"
|
import IMG_GITHUB from "../asset/screenshot-github.webp"
|
||||||
import { IconCopy, IconCheck } from "../component/icon"
|
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() {
|
function CopyStatus() {
|
||||||
return (
|
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() {
|
export default function Home() {
|
||||||
|
createAsync(() => isLoggedIn(), {
|
||||||
|
deferStream: true,
|
||||||
|
})
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const commands = document.querySelectorAll("[data-copy]")
|
const commands = document.querySelectorAll("[data-copy]")
|
||||||
for (const button of commands) {
|
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: {
|
properties: {
|
||||||
userID: string
|
userID: string
|
||||||
workspaceID: string
|
workspaceID: string
|
||||||
email: string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Resource } from "sst"
|
|||||||
export * from "drizzle-orm"
|
export * from "drizzle-orm"
|
||||||
import postgres from "postgres"
|
import postgres from "postgres"
|
||||||
|
|
||||||
function createClient() {
|
const createClient = memo(() => {
|
||||||
const client = postgres({
|
const client = postgres({
|
||||||
idle_timeout: 30000,
|
idle_timeout: 30000,
|
||||||
connect_timeout: 30000,
|
connect_timeout: 30000,
|
||||||
@@ -19,12 +19,13 @@ function createClient() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return drizzle(client, {})
|
return drizzle(client, {})
|
||||||
}
|
})
|
||||||
|
|
||||||
import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
|
import { PgTransaction, type PgTransactionConfig } from "drizzle-orm/pg-core"
|
||||||
import type { ExtractTablesWithRelations } from "drizzle-orm"
|
import type { ExtractTablesWithRelations } from "drizzle-orm"
|
||||||
import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js"
|
import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js"
|
||||||
import { Context } from "../context"
|
import { Context } from "../context"
|
||||||
|
import { memo } from "../util/memo"
|
||||||
|
|
||||||
export namespace Database {
|
export namespace Database {
|
||||||
export type Transaction = PgTransaction<
|
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 { z } from "zod"
|
||||||
import { issuer } from "@openauthjs/openauth"
|
import { issuer } from "@openauthjs/openauth"
|
||||||
import { createSubjects } from "@openauthjs/openauth/subject"
|
import { createSubjects } from "@openauthjs/openauth/subject"
|
||||||
import { CodeProvider } from "@openauthjs/openauth/provider/code"
|
|
||||||
import { GithubProvider } from "@openauthjs/openauth/provider/github"
|
import { GithubProvider } from "@openauthjs/openauth/provider/github"
|
||||||
import { GoogleOidcProvider } from "@openauthjs/openauth/provider/google"
|
import { GoogleOidcProvider } from "@openauthjs/openauth/provider/google"
|
||||||
import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare"
|
import { CloudflareStorage } from "@openauthjs/openauth/storage/cloudflare"
|
||||||
import { Account } from "@opencode/cloud-core/account.js"
|
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 = {
|
type Env = {
|
||||||
AuthStorage: KVNamespace
|
AuthStorage: KVNamespace
|
||||||
@@ -117,6 +118,12 @@ export default {
|
|||||||
email: email!,
|
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 })
|
return ctx.subject("account", accountID, { accountID, email })
|
||||||
},
|
},
|
||||||
}).fetch(request, env, ctx)
|
}).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"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Console": {
|
|
||||||
"type": "sst.cloudflare.StaticSite"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"DATABASE_PASSWORD": {
|
"DATABASE_PASSWORD": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"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 = {
|
args.migrations = {
|
||||||
// Note: when releasing the next tag, make sure all stages use tag v2
|
// Note: when releasing the next tag, make sure all stages use tag v2
|
||||||
oldTag: $app.stage === "production" ? "" : "v1",
|
// oldTag: $app.stage === "production" ? "" : "v1",
|
||||||
newTag: $app.stage === "production" ? "" : "v1",
|
// newTag: $app.stage === "production" ? "" : "v1",
|
||||||
//newSqliteClasses: ["SyncServer"],
|
newSqliteClasses: ["SyncServer"],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const DATABASE_USERNAME = new sst.Secret("DATABASE_USERNAME")
|
|||||||
const DATABASE_PASSWORD = new sst.Secret("DATABASE_PASSWORD")
|
const DATABASE_PASSWORD = new sst.Secret("DATABASE_PASSWORD")
|
||||||
export const database = new sst.Linkable("Database", {
|
export const database = new sst.Linkable("Database", {
|
||||||
properties: {
|
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",
|
database: "postgres",
|
||||||
username: DATABASE_USERNAME.value,
|
username: DATABASE_USERNAME.value,
|
||||||
password: DATABASE_PASSWORD.value,
|
password: DATABASE_PASSWORD.value,
|
||||||
@@ -106,6 +106,7 @@ export const gateway = new sst.cloudflare.Worker("GatewayApi", {
|
|||||||
// CONSOLE
|
// CONSOLE
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
/*
|
||||||
export const console = new sst.cloudflare.x.StaticSite("Console", {
|
export const console = new sst.cloudflare.x.StaticSite("Console", {
|
||||||
domain: `console.${domain}`,
|
domain: `console.${domain}`,
|
||||||
path: "cloud/web",
|
path: "cloud/web",
|
||||||
@@ -119,3 +120,15 @@ export const console = new sst.cloudflare.x.StaticSite("Console", {
|
|||||||
VITE_AUTH_URL: auth.url.apply((url) => url!),
|
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"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Console": {
|
|
||||||
"type": "sst.cloudflare.StaticSite"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"DATABASE_PASSWORD": {
|
"DATABASE_PASSWORD": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|||||||
4
sst-env.d.ts
vendored
4
sst-env.d.ts
vendored
@@ -27,10 +27,6 @@ declare module "sst" {
|
|||||||
"Bucket": {
|
"Bucket": {
|
||||||
"type": "sst.cloudflare.Bucket"
|
"type": "sst.cloudflare.Bucket"
|
||||||
}
|
}
|
||||||
"Console": {
|
|
||||||
"type": "sst.cloudflare.StaticSite"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"DATABASE_PASSWORD": {
|
"DATABASE_PASSWORD": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|||||||
Reference in New Issue
Block a user