mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-21 18:26:09 +00:00
fix(server): include cors headers on 404s
This commit is contained in:
@@ -190,17 +190,45 @@ const docRoute = HttpRouter.use((router) => router.add("GET", "/doc", () => Effe
|
||||
Layer.provide(authOnlyRouterLayer),
|
||||
)
|
||||
|
||||
const uiRoute = HttpRouter.use((router) =>
|
||||
const uiRoute = (corsOptions?: CorsOptions) => HttpRouter.use((router) =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* FSUtil.Service
|
||||
const client = yield* HttpClient.HttpClient
|
||||
const flags = yield* RuntimeFlags.Service
|
||||
yield* router.add("*", "/*", (request) =>
|
||||
serveUIEffect(request, { fs, client, disableEmbeddedWebUi: flags.disableEmbeddedWebUi }),
|
||||
serveUIEffect(request, { fs, client, disableEmbeddedWebUi: flags.disableEmbeddedWebUi }).pipe(
|
||||
Effect.map((response) => withNotFoundCors(response, request.headers.origin, corsOptions)),
|
||||
),
|
||||
)
|
||||
}),
|
||||
).pipe(Layer.provide(authOnlyRouterLayer))
|
||||
|
||||
const apiNotFoundRoute = (corsOptions?: CorsOptions) =>
|
||||
HttpRouter.use((router) =>
|
||||
router.add("*", "/api/*", (request) =>
|
||||
Effect.succeed(
|
||||
withNotFoundCors(
|
||||
HttpServerResponse.jsonUnsafe({ error: "Not Found" }, { status: 404 }),
|
||||
request.headers.origin,
|
||||
corsOptions,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
function withNotFoundCors(
|
||||
response: HttpServerResponse.HttpServerResponse,
|
||||
origin: string | undefined,
|
||||
opts?: CorsOptions,
|
||||
) {
|
||||
if (response.status !== 404 || !origin || !isAllowedCorsOrigin(origin, opts)) return response
|
||||
const vary = response.headers["vary"]
|
||||
const next = HttpServerResponse.setHeader(response, "access-control-allow-origin", origin)
|
||||
if (!vary) return HttpServerResponse.setHeader(next, "vary", "Origin")
|
||||
if (vary.split(",").some((value) => value.trim().toLowerCase() === "origin")) return next
|
||||
return HttpServerResponse.setHeader(next, "vary", `${vary}, Origin`)
|
||||
}
|
||||
|
||||
type RouteRequirements =
|
||||
| HttpRouter.HttpRouter
|
||||
| HttpRouter.Request<"Error", unknown>
|
||||
@@ -278,7 +306,8 @@ export function createRoutes(
|
||||
instanceRoutes,
|
||||
serverRoutes,
|
||||
docRoute,
|
||||
uiRoute,
|
||||
apiNotFoundRoute(corsOptions),
|
||||
uiRoute(corsOptions),
|
||||
).pipe(
|
||||
Layer.provide([
|
||||
errorLayer,
|
||||
|
||||
@@ -82,6 +82,35 @@ describe("HttpApi CORS", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("adds CORS headers to not found responses", () =>
|
||||
Effect.gen(function* () {
|
||||
const handler = HttpRouter.toWebHandler(
|
||||
HttpApiApp.createRoutes().pipe(
|
||||
Layer.provide(
|
||||
ConfigProvider.layer(
|
||||
ConfigProvider.fromUnknown({
|
||||
OPENCODE_DISABLE_EMBEDDED_WEB_UI: "true",
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
{ disableLogger: true },
|
||||
).handler
|
||||
const response = yield* Effect.promise(() =>
|
||||
handler(
|
||||
new Request(new URL("/api/health", "http://localhost"), {
|
||||
method: "POST",
|
||||
headers: { origin: "https://app.opencode.ai" },
|
||||
}),
|
||||
HttpApiApp.context,
|
||||
),
|
||||
)
|
||||
|
||||
expect(response.status).toBe(404)
|
||||
expect(response.headers.get("access-control-allow-origin")).toBe("https://app.opencode.ai")
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("uses custom CORS origins passed to the server", () =>
|
||||
Effect.gen(function* () {
|
||||
const listener = yield* Effect.acquireRelease(
|
||||
|
||||
Reference in New Issue
Block a user