Compare commits

...

1 Commits

Author SHA1 Message Date
MrMushrooooom 40663a92e2 feat(console): add support workspace deletion 2026-09-08 08:28:46 +00:00
2 changed files with 63 additions and 0 deletions
@@ -0,0 +1,19 @@
import type { APIEvent } from "@solidjs/start/server"
import { Workspace } from "@opencode/console-core/workspace.js"
import { safeEqual } from "@opencode/console-core/util/crypto.js"
import { Resource } from "@opencode/console-resource"
export async function DELETE(event: APIEvent) {
if (!safeEqual(event.request.headers.get("authorization") ?? "", `Bearer ${Resource.SUPPORT_API_KEY.value}`)) {
return Response.json({ error: "Unauthorized" }, { status: 401 })
}
const body = Workspace.removeExact.schema.safeParse(await event.request.json().catch(() => undefined))
if (!body.success) {
return Response.json({ error: "Invalid request", issues: body.error.issues }, { status: 400 })
}
return Workspace.removeExact
.force(body.data)
.then(() => Response.json({ success: true, message: "Workspace deleted" }))
.catch((error) => Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 400 }))
}
+44
View File
@@ -7,6 +7,8 @@ import { UserTable } from "./schema/user.sql"
import { BillingTable } from "./schema/billing.sql"
import { WorkspaceTable } from "./schema/workspace.sql"
import { AccountTable } from "./schema/account.sql"
import { AuthTable } from "./schema/auth.sql"
import { KeyTable } from "./schema/key.sql"
import { Key } from "./key"
import { and, eq, isNull, sql } from "drizzle-orm"
@@ -104,6 +106,48 @@ export namespace Workspace {
)
})
export const removeExact = fn(
z.object({
workspaceID: Identifier.schema("workspace"),
requesterEmail: z.email(),
}),
async (input) => {
await Database.transaction(async (tx) => {
const requester = await tx
.select({ id: UserTable.id })
.from(AuthTable)
.innerJoin(
UserTable,
and(
eq(UserTable.accountID, AuthTable.accountID),
eq(UserTable.workspaceID, input.workspaceID),
eq(UserTable.role, "admin"),
isNull(UserTable.timeDeleted),
),
)
.innerJoin(WorkspaceTable, eq(WorkspaceTable.id, input.workspaceID))
.where(
and(
eq(AuthTable.provider, "email"),
eq(AuthTable.subject, input.requesterEmail),
isNull(AuthTable.timeDeleted),
),
)
.then((rows) => rows[0])
if (!requester) throw new Error("Requester is not an administrator of this workspace")
await tx
.update(WorkspaceTable)
.set({ timeDeleted: sql`now()` })
.where(and(eq(WorkspaceTable.id, input.workspaceID), isNull(WorkspaceTable.timeDeleted)))
await tx
.update(KeyTable)
.set({ timeDeleted: sql`now()` })
.where(and(eq(KeyTable.workspaceID, input.workspaceID), isNull(KeyTable.timeDeleted)))
})
},
)
export const unblock = fn(z.string().startsWith("wrk_"), async (workspaceID) => {
await Database.transaction(async (tx) => {
const workspace = await tx