mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-03 07:33:45 +00:00
feat(id): brand WorkspaceID through Drizzle and Zod schemas (#16964)
This commit is contained in:
17
packages/opencode/src/control-plane/schema.ts
Normal file
17
packages/opencode/src/control-plane/schema.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Schema } from "effect"
|
||||
import z from "zod"
|
||||
|
||||
import { withStatics } from "@/util/schema"
|
||||
import { Identifier } from "@/id/id"
|
||||
|
||||
const workspaceIdSchema = Schema.String.pipe(Schema.brand("WorkspaceId"))
|
||||
|
||||
export type WorkspaceID = typeof workspaceIdSchema.Type
|
||||
|
||||
export const WorkspaceID = workspaceIdSchema.pipe(
|
||||
withStatics((schema: typeof workspaceIdSchema) => ({
|
||||
make: (id: string) => schema.makeUnsafe(id),
|
||||
ascending: (id?: string) => schema.makeUnsafe(Identifier.ascending("workspace", id)),
|
||||
zod: z.string().startsWith("wrk").pipe(z.custom<WorkspaceID>()),
|
||||
})),
|
||||
)
|
||||
@@ -1,9 +1,9 @@
|
||||
import z from "zod"
|
||||
import { Identifier } from "@/id/id"
|
||||
import { ProjectID } from "@/project/schema"
|
||||
import { WorkspaceID } from "./schema"
|
||||
|
||||
export const WorkspaceInfo = z.object({
|
||||
id: Identifier.schema("workspace"),
|
||||
id: WorkspaceID.zod,
|
||||
type: z.string(),
|
||||
branch: z.string().nullable(),
|
||||
name: z.string().nullable(),
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Context } from "../util/context"
|
||||
import type { WorkspaceID } from "./schema"
|
||||
|
||||
interface Context {
|
||||
workspaceID?: string
|
||||
workspaceID?: WorkspaceID
|
||||
}
|
||||
|
||||
const context = Context.create<Context>("workspace")
|
||||
|
||||
export const WorkspaceContext = {
|
||||
async provide<R>(input: { workspaceID?: string; fn: () => R }): Promise<R> {
|
||||
async provide<R>(input: { workspaceID?: WorkspaceID; fn: () => R }): Promise<R> {
|
||||
return context.provide({ workspaceID: input.workspaceID }, async () => {
|
||||
return input.fn()
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import { InstanceBootstrap } from "../../project/bootstrap"
|
||||
import { SessionRoutes } from "../../server/routes/session"
|
||||
import { WorkspaceServerRoutes } from "./routes"
|
||||
import { WorkspaceContext } from "../workspace-context"
|
||||
import { WorkspaceID } from "../schema"
|
||||
|
||||
export namespace WorkspaceServer {
|
||||
export function App() {
|
||||
@@ -20,9 +21,9 @@ export namespace WorkspaceServer {
|
||||
|
||||
return new Hono()
|
||||
.use(async (c, next) => {
|
||||
const workspaceID = c.req.query("workspace") || c.req.header("x-opencode-workspace")
|
||||
const rawWorkspaceID = c.req.query("workspace") || c.req.header("x-opencode-workspace")
|
||||
const raw = c.req.query("directory") || c.req.header("x-opencode-directory")
|
||||
if (workspaceID == null) {
|
||||
if (rawWorkspaceID == null) {
|
||||
throw new Error("workspaceID parameter is required")
|
||||
}
|
||||
if (raw == null) {
|
||||
@@ -38,7 +39,7 @@ export namespace WorkspaceServer {
|
||||
})()
|
||||
|
||||
return WorkspaceContext.provide({
|
||||
workspaceID,
|
||||
workspaceID: WorkspaceID.make(rawWorkspaceID),
|
||||
async fn() {
|
||||
return Instance.provide({
|
||||
directory,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { sqliteTable, text } from "drizzle-orm/sqlite-core"
|
||||
import { ProjectTable } from "../project/project.sql"
|
||||
import type { ProjectID } from "../project/schema"
|
||||
import type { WorkspaceID } from "./schema"
|
||||
|
||||
export const WorkspaceTable = sqliteTable("workspace", {
|
||||
id: text().primaryKey(),
|
||||
id: text().$type<WorkspaceID>().primaryKey(),
|
||||
type: text().notNull(),
|
||||
branch: text(),
|
||||
name: text(),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import z from "zod"
|
||||
import { Identifier } from "@/id/id"
|
||||
import { fn } from "@/util/fn"
|
||||
import { Database, eq } from "@/storage/db"
|
||||
import { Project } from "@/project/project"
|
||||
@@ -10,6 +9,7 @@ import { ProjectID } from "@/project/schema"
|
||||
import { WorkspaceTable } from "./workspace.sql"
|
||||
import { getAdaptor } from "./adaptors"
|
||||
import { WorkspaceInfo } from "./types"
|
||||
import { WorkspaceID } from "./schema"
|
||||
import { parseSSE } from "./sse"
|
||||
|
||||
export namespace Workspace {
|
||||
@@ -46,7 +46,7 @@ export namespace Workspace {
|
||||
}
|
||||
|
||||
const CreateInput = z.object({
|
||||
id: Identifier.schema("workspace").optional(),
|
||||
id: WorkspaceID.zod.optional(),
|
||||
type: Info.shape.type,
|
||||
branch: Info.shape.branch,
|
||||
projectID: ProjectID.zod,
|
||||
@@ -54,7 +54,7 @@ export namespace Workspace {
|
||||
})
|
||||
|
||||
export const create = fn(CreateInput, async (input) => {
|
||||
const id = Identifier.ascending("workspace", input.id)
|
||||
const id = WorkspaceID.ascending(input.id)
|
||||
const adaptor = await getAdaptor(input.type)
|
||||
|
||||
const config = await adaptor.configure({ ...input, id, name: null, directory: null })
|
||||
@@ -94,13 +94,13 @@ export namespace Workspace {
|
||||
return rows.map(fromRow).sort((a, b) => a.id.localeCompare(b.id))
|
||||
}
|
||||
|
||||
export const get = fn(Identifier.schema("workspace"), async (id) => {
|
||||
export const get = fn(WorkspaceID.zod, async (id) => {
|
||||
const row = Database.use((db) => db.select().from(WorkspaceTable).where(eq(WorkspaceTable.id, id)).get())
|
||||
if (!row) return
|
||||
return fromRow(row)
|
||||
})
|
||||
|
||||
export const remove = fn(Identifier.schema("workspace"), async (id) => {
|
||||
export const remove = fn(WorkspaceID.zod, async (id) => {
|
||||
const row = Database.use((db) => db.select().from(WorkspaceTable).where(eq(WorkspaceTable.id, id)).get())
|
||||
if (row) {
|
||||
const info = fromRow(row)
|
||||
|
||||
Reference in New Issue
Block a user