Download packages/console/core/src/workspace.ts from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 5.33 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/console/core/src/workspace.ts
- Command line
-
hf download hf://SaylorTwift/opencode/packages/console/core/src/workspace.ts
-
curl -L -o workspace.ts https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/console/core/src/workspace.ts
5.33 kB
| import { z } from "zod" | |
| import { fn } from "./util/fn" | |
| import { Actor } from "./actor" | |
| import { Database } from "./drizzle" | |
| import { Identifier } from "./identifier" | |
| 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 { Key } from "./key" | |
| import { and, eq, inArray, isNull, sql } from "drizzle-orm" | |
| export namespace Workspace { | |
| export const Region = z.enum(["us", "eu", "sg", "cn"]) | |
| export type Region = z.infer<typeof Region> | |
| export const create = fn( | |
| z.object({ | |
| name: z.string().min(1), | |
| }), | |
| async ({ name }) => { | |
| const account = Actor.assert("account") | |
| const workspaceID = Identifier.create("workspace") | |
| const userID = Identifier.create("user") | |
| await Database.transaction(async (tx) => { | |
| const active = await tx | |
| .select({ id: AccountTable.id }) | |
| .from(AccountTable) | |
| .where(and(eq(AccountTable.id, account.properties.accountID), isNull(AccountTable.timeDeleted))) | |
| .then((rows) => rows[0]) | |
| if (!active) throw new Error("Account is not active") | |
| await tx.insert(WorkspaceTable).values({ | |
| id: workspaceID, | |
| name, | |
| }) | |
| await tx.insert(UserTable).values({ | |
| workspaceID, | |
| id: userID, | |
| accountID: account.properties.accountID, | |
| name: "", | |
| role: "admin", | |
| }) | |
| await tx.insert(BillingTable).values({ | |
| workspaceID, | |
| id: Identifier.create("billing"), | |
| balance: 0, | |
| }) | |
| }) | |
| await Actor.provide( | |
| "system", | |
| { | |
| workspaceID, | |
| }, | |
| () => Key.create({ userID, name: "Default API Key" }), | |
| ) | |
| return workspaceID | |
| }, | |
| ) | |
| export const update = fn( | |
| z.object({ | |
| name: z.string().min(1).max(255).optional(), | |
| region: z.array(Region).min(1).optional(), | |
| allow_training: z.boolean().optional(), | |
| }), | |
| async (input) => { | |
| Actor.assertAdmin() | |
| const workspaceID = Actor.workspace() | |
| return await Database.use((tx) => | |
| tx | |
| .update(WorkspaceTable) | |
| .set({ | |
| ...("name" in input ? { name: input.name } : {}), | |
| ...("region" in input ? { region: input.region } : {}), | |
| ...("allow_training" in input ? { allow_training: input.allow_training } : {}), | |
| }) | |
| .where(eq(WorkspaceTable.id, workspaceID)), | |
| ) | |
| }, | |
| ) | |
| export const setDefaultRegion = fn( | |
| z.object({ | |
| country: z.string().optional(), | |
| }), | |
| async (input) => { | |
| const region: Workspace.Region[] = | |
| input.country?.toUpperCase() === "CN" ? ["us", "eu", "sg", "cn"] : ["us", "eu", "sg"] | |
| await Database.use((tx) => | |
| tx | |
| .update(WorkspaceTable) | |
| .set({ region }) | |
| .where(and(eq(WorkspaceTable.id, Actor.workspace()), isNull(WorkspaceTable.region))), | |
| ) | |
| return region | |
| }, | |
| ) | |
| export const unblock = fn( | |
| z.object({ | |
| workspaceID: Identifier.schema("workspace"), | |
| }), | |
| async (input) => { | |
| const result = await Database.use((tx) => | |
| tx.update(WorkspaceTable).set({ is_blocked: false }).where(eq(WorkspaceTable.id, input.workspaceID)), | |
| ) | |
| if (result.rowsAffected === 0) throw new Error("Workspace not found") | |
| }, | |
| ) | |
| export const blockBatch = fn( | |
| z.object({ | |
| workspaceIDs: z.array(Identifier.schema("workspace")).min(1), | |
| }), | |
| async (input) => { | |
| const { applied, notFound } = await setBlockedBatch(input, true) | |
| return { blocked: applied, notFound } | |
| }, | |
| ) | |
| export const unblockBatch = fn( | |
| z.object({ | |
| workspaceIDs: z.array(Identifier.schema("workspace")).min(1), | |
| }), | |
| async (input) => { | |
| const { applied, notFound } = await setBlockedBatch(input, false) | |
| return { unblocked: applied, notFound } | |
| }, | |
| ) | |
| export const remove = fn(z.void(), async () => { | |
| await Database.use((tx) => | |
| tx | |
| .update(WorkspaceTable) | |
| .set({ timeDeleted: sql`now()` }) | |
| .where(eq(WorkspaceTable.id, Actor.workspace())), | |
| ) | |
| }) | |
| } | |
| // No size cap by design; large IN lists degrade on Vitess, so chunks stay fixed-size and | |
| // sequential to share one connection inside ambient transactions. Existence comes from the | |
| // follow-up select rather than rowsAffected, so no-op rows (already in the target state) | |
| // still report as applied instead of "not found". | |
| const setBlockedBatch = async (input: { workspaceIDs: string[] }, isBlocked: boolean) => { | |
| const ids = [...new Set(input.workspaceIDs)] | |
| return await Database.use(async (tx) => { | |
| const applied = new Set<string>() | |
| for (let index = 0; index < ids.length; index += 500) { | |
| const chunk = ids.slice(index, index + 500) | |
| await tx.update(WorkspaceTable).set({ is_blocked: isBlocked }).where(inArray(WorkspaceTable.id, chunk)) | |
| const rows = await tx | |
| .select({ id: WorkspaceTable.id }) | |
| .from(WorkspaceTable) | |
| .where(inArray(WorkspaceTable.id, chunk)) | |
| for (const row of rows) applied.add(row.id) | |
| } | |
| return { | |
| applied: ids.filter((id) => applied.has(id)), | |
| notFound: ids.filter((id) => !applied.has(id)), | |
| } | |
| }) | |
| } | |