refactor(core): move database schema ownership (#29068)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent
6bcb9cb9bb
commit
7f571d36ea
@@ -1,20 +1,25 @@
|
||||
import { Flag } from "@opencode-ai/core/flag/flag"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { Effect } from "effect"
|
||||
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
||||
import * as Fence from "@/server/shared/fence"
|
||||
|
||||
const ignoredMethods = new Set(["GET", "HEAD", "OPTIONS"])
|
||||
|
||||
export const fenceLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) =>
|
||||
export const fenceLayer = HttpRouter.middleware<{ requires: Database.Service; handles: unknown }>()(
|
||||
Effect.gen(function* () {
|
||||
const request = yield* HttpServerRequest.HttpServerRequest
|
||||
if (!Flag.OPENCODE_WORKSPACE_ID || ignoredMethods.has(request.method)) return yield* effect
|
||||
const { db } = yield* Database.Service
|
||||
return (effect) =>
|
||||
Effect.gen(function* () {
|
||||
const request = yield* HttpServerRequest.HttpServerRequest
|
||||
if (!Flag.OPENCODE_WORKSPACE_ID || ignoredMethods.has(request.method)) return yield* effect
|
||||
|
||||
const previous = Fence.load()
|
||||
const response = yield* effect
|
||||
const current = Fence.diff(previous, Fence.load())
|
||||
if (Object.keys(current).length === 0) return response
|
||||
const previous = yield* Fence.load(db)
|
||||
const response = yield* effect
|
||||
const current = Fence.diff(previous, yield* Fence.load(db))
|
||||
if (Object.keys(current).length === 0) return response
|
||||
|
||||
return HttpServerResponse.setHeader(response, Fence.HEADER, JSON.stringify(current))
|
||||
return HttpServerResponse.setHeader(response, Fence.HEADER, JSON.stringify(current))
|
||||
})
|
||||
}),
|
||||
).layer
|
||||
|
||||
+14
-14
@@ -1,4 +1,4 @@
|
||||
import { WorkspaceID } from "@/control-plane/schema"
|
||||
import { WorkspaceV2 } from "@opencode-ai/core/workspace"
|
||||
import type { Target } from "@/control-plane/types"
|
||||
import { Workspace } from "@/control-plane/workspace"
|
||||
import { WorkspaceAdapterRuntime } from "@/control-plane/workspace-adapter-runtime"
|
||||
@@ -30,8 +30,8 @@ type RemoteTarget = Extract<Target, { type: "remote" }>
|
||||
|
||||
type RequestPlan = Data.TaggedEnum<{
|
||||
InvalidWorkspace: {}
|
||||
MissingWorkspace: { readonly workspaceID: WorkspaceID }
|
||||
Local: { readonly directory: string; readonly workspaceID?: WorkspaceID }
|
||||
MissingWorkspace: { readonly workspaceID: WorkspaceV2.ID }
|
||||
Local: { readonly directory: string; readonly workspaceID?: WorkspaceV2.ID }
|
||||
Remote: {
|
||||
readonly request: HttpServerRequest.HttpServerRequest
|
||||
readonly workspace: Workspace.Info
|
||||
@@ -46,7 +46,7 @@ export class WorkspaceRouteContext extends Context.Service<
|
||||
WorkspaceRouteContext,
|
||||
{
|
||||
readonly directory: string
|
||||
readonly workspaceID?: WorkspaceID
|
||||
readonly workspaceID?: WorkspaceV2.ID
|
||||
}
|
||||
>()("@opencode/ExperimentalHttpApiWorkspaceRouteContext") {}
|
||||
|
||||
@@ -62,23 +62,23 @@ function requestURL(request: HttpServerRequest.HttpServerRequest): URL {
|
||||
return new URL(request.url, "http://localhost")
|
||||
}
|
||||
|
||||
function configuredWorkspaceID(): WorkspaceID | undefined {
|
||||
return Flag.OPENCODE_WORKSPACE_ID ? WorkspaceID.make(Flag.OPENCODE_WORKSPACE_ID) : undefined
|
||||
function configuredWorkspaceID(): WorkspaceV2.ID | undefined {
|
||||
return Flag.OPENCODE_WORKSPACE_ID ? WorkspaceV2.ID.make(Flag.OPENCODE_WORKSPACE_ID) : undefined
|
||||
}
|
||||
|
||||
function selectedWorkspaceID(url: URL, sessionWorkspaceID?: WorkspaceID): WorkspaceID | undefined {
|
||||
function selectedWorkspaceID(url: URL, sessionWorkspaceID?: WorkspaceV2.ID): WorkspaceV2.ID | undefined {
|
||||
const workspaceParam = url.searchParams.get("workspace")
|
||||
return sessionWorkspaceID ?? (workspaceParam ? WorkspaceID.make(workspaceParam) : undefined)
|
||||
return sessionWorkspaceID ?? (workspaceParam ? WorkspaceV2.ID.make(workspaceParam) : undefined)
|
||||
}
|
||||
|
||||
function selectedV2WorkspaceID(
|
||||
url: URL,
|
||||
sessionWorkspaceID?: WorkspaceID,
|
||||
): WorkspaceID | typeof InvalidWorkspaceID | undefined {
|
||||
sessionWorkspaceID?: WorkspaceV2.ID,
|
||||
): WorkspaceV2.ID | typeof InvalidWorkspaceID | undefined {
|
||||
if (sessionWorkspaceID) return sessionWorkspaceID
|
||||
const workspaceParam = url.searchParams.get("workspace")
|
||||
if (!workspaceParam) return undefined
|
||||
const workspaceID = Schema.decodeUnknownOption(WorkspaceID)(workspaceParam)
|
||||
const workspaceID = Schema.decodeUnknownOption(WorkspaceV2.ID)(workspaceParam)
|
||||
if (Option.isNone(workspaceID)) return InvalidWorkspaceID
|
||||
return workspaceID.value
|
||||
}
|
||||
@@ -92,14 +92,14 @@ function shouldStayOnControlPlane(request: HttpServerRequest.HttpServerRequest,
|
||||
}
|
||||
|
||||
function resolveWorkspace(
|
||||
id: WorkspaceID | undefined,
|
||||
envWorkspaceID: WorkspaceID | undefined,
|
||||
id: WorkspaceV2.ID | undefined,
|
||||
envWorkspaceID: WorkspaceV2.ID | undefined,
|
||||
): Effect.Effect<Workspace.Info | void, never, Workspace.Service> {
|
||||
if (!id || envWorkspaceID) return Effect.void
|
||||
return Workspace.Service.use((workspace) => workspace.get(id))
|
||||
}
|
||||
|
||||
function missingWorkspaceResponse(id: WorkspaceID): HttpServerResponse.HttpServerResponse {
|
||||
function missingWorkspaceResponse(id: WorkspaceV2.ID): HttpServerResponse.HttpServerResponse {
|
||||
return HttpServerResponse.text(`Workspace not found: ${id}`, {
|
||||
status: 500,
|
||||
contentType: "text/plain; charset=utf-8",
|
||||
|
||||
Reference in New Issue
Block a user