diff --git a/packages/opencode/test/server/httpapi-bridge.test.ts b/packages/opencode/test/server/httpapi-bridge.test.ts index dac23a654d..4417cc4464 100644 --- a/packages/opencode/test/server/httpapi-bridge.test.ts +++ b/packages/opencode/test/server/httpapi-bridge.test.ts @@ -4,8 +4,23 @@ import { Flag } from "@opencode-ai/core/flag/flag" import { Instance } from "../../src/project/instance" import { InstanceRoutes } from "../../src/server/routes/instance" import { WorkspaceRoutes } from "../../src/server/routes/control/workspace" -import { FilePaths } from "../../src/server/routes/instance/httpapi/file" +import { ConfigApi } from "../../src/server/routes/instance/httpapi/config" +import { EventPaths } from "../../src/server/routes/instance/httpapi/event" +import { ExperimentalApi } from "../../src/server/routes/instance/httpapi/experimental" +import { FileApi, FilePaths } from "../../src/server/routes/instance/httpapi/file" +import { InstanceApi } from "../../src/server/routes/instance/httpapi/instance" +import { McpApi } from "../../src/server/routes/instance/httpapi/mcp" +import { PermissionApi } from "../../src/server/routes/instance/httpapi/permission" +import { ProjectApi } from "../../src/server/routes/instance/httpapi/project" +import { ProviderApi } from "../../src/server/routes/instance/httpapi/provider" +import { PtyApi, PtyPaths } from "../../src/server/routes/instance/httpapi/pty" +import { QuestionApi } from "../../src/server/routes/instance/httpapi/question" +import { SessionApi } from "../../src/server/routes/instance/httpapi/session" +import { SyncApi } from "../../src/server/routes/instance/httpapi/sync" +import { TuiApi } from "../../src/server/routes/instance/httpapi/tui" +import { WorkspaceApi } from "../../src/server/routes/instance/httpapi/workspace" import * as Log from "@opencode-ai/core/util/log" +import { HttpApi, HttpApiGroup } from "effect/unstable/httpapi" import { resetDatabase } from "../fixture/db" import { tmpdir } from "../fixture/fixture" @@ -30,6 +45,39 @@ function routeKey(route: ReturnType["routes"][number]) { return `${route.method} ${route.path}` } +function reflectedHttpApiRoutes() { + const routes = [ + `GET ${EventPaths.event}`, + `GET ${PtyPaths.connect}`, + ] + + function addRoutes(api: HttpApi.HttpApi) { + HttpApi.reflect(api, { + onGroup() {}, + onEndpoint({ endpoint }) { + routes.push(`${endpoint.method} ${endpoint.path}`) + }, + }) + } + + addRoutes(ConfigApi) + addRoutes(ExperimentalApi) + addRoutes(FileApi) + addRoutes(InstanceApi) + addRoutes(McpApi) + addRoutes(PermissionApi) + addRoutes(ProjectApi) + addRoutes(ProviderApi) + addRoutes(PtyApi) + addRoutes(QuestionApi) + addRoutes(SessionApi) + addRoutes(SyncApi) + addRoutes(TuiApi) + addRoutes(WorkspaceApi) + + return [...new Set(routes)] +} + function authorization(username: string, password: string) { return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}` } @@ -69,6 +117,21 @@ describe("HttpApi Hono bridge", () => { expect([...bridgeRoutes].filter((route) => !legacyRoutes.includes(route)).sort()).toEqual([]) }) + test("mounts every Effect HttpApi route through the Hono bridge", () => { + Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = false + const legacy = InstanceRoutes(websocket) + Flag.OPENCODE_EXPERIMENTAL_HTTPAPI = true + const experimental = InstanceRoutes(websocket) + + const bridgeRoutes = new Set( + experimental.routes.slice(0, experimental.routes.length - legacy.routes.length).map(routeKey), + ) + const httpApiRoutes = reflectedHttpApiRoutes() + + expect(httpApiRoutes.filter((route) => !bridgeRoutes.has(route))).toEqual([]) + expect([...bridgeRoutes].filter((route) => !httpApiRoutes.includes(route)).sort()).toEqual([]) + }) + test("allows requests when auth is disabled", async () => { await using tmp = await tmpdir({ git: true }) await Bun.write(`${tmp.path}/hello.txt`, "hello")