diff --git a/packages/opencode/src/server/instance/httpapi/server.ts b/packages/opencode/src/server/instance/httpapi/server.ts index 299a177f50bb..362d0970b9d9 100644 --- a/packages/opencode/src/server/instance/httpapi/server.ts +++ b/packages/opencode/src/server/instance/httpapi/server.ts @@ -25,106 +25,106 @@ const Headers = Schema.Struct({ "x-opencode-directory": Schema.optional(Schema.String), }) -export namespace ExperimentalHttpApiServer { - function decode(input: string) { - try { - return decodeURIComponent(input) - } catch { - return input - } +function decode(input: string) { + try { + return decodeURIComponent(input) + } catch { + return input } +} - class Unauthorized extends Schema.TaggedErrorClass()( - "Unauthorized", - { message: Schema.String }, - { httpApiStatus: 401 }, - ) {} +class Unauthorized extends Schema.TaggedErrorClass()( + "Unauthorized", + { message: Schema.String }, + { httpApiStatus: 401 }, +) {} - class Authorization extends HttpApiMiddleware.Service()("@opencode/ExperimentalHttpApiAuthorization", { - error: Unauthorized, - security: { - basic: HttpApiSecurity.basic, - }, - }) {} +class Authorization extends HttpApiMiddleware.Service()("@opencode/ExperimentalHttpApiAuthorization", { + error: Unauthorized, + security: { + basic: HttpApiSecurity.basic, + }, +}) {} - const normalize = HttpRouter.middleware()( - Effect.gen(function* () { - return (effect) => - Effect.gen(function* () { - const query = yield* HttpServerRequest.schemaSearchParams(Query) - if (!query.auth_token) return yield* effect - const req = yield* HttpServerRequest.HttpServerRequest - const next = req.modify({ - headers: { - ...req.headers, - authorization: `Basic ${query.auth_token}`, - }, - }) - return yield* effect.pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, next)) +const normalize = HttpRouter.middleware()( + Effect.gen(function* () { + return (effect) => + Effect.gen(function* () { + const query = yield* HttpServerRequest.schemaSearchParams(Query) + if (!query.auth_token) return yield* effect + const req = yield* HttpServerRequest.HttpServerRequest + const next = req.modify({ + headers: { + ...req.headers, + authorization: `Basic ${query.auth_token}`, + }, }) - }), - ).layer + return yield* effect.pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, next)) + }) + }), +).layer - const auth = Layer.succeed( - Authorization, - Authorization.of({ - basic: (effect, { credential }) => - Effect.gen(function* () { - if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect +const auth = Layer.succeed( + Authorization, + Authorization.of({ + basic: (effect, { credential }) => + Effect.gen(function* () { + if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect - const user = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" - if (credential.username !== user) { - return yield* new Unauthorized({ message: "Unauthorized" }) - } - if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) { - return yield* new Unauthorized({ message: "Unauthorized" }) - } - return yield* effect - }), - }), - ) + const user = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" + if (credential.username !== user) { + return yield* new Unauthorized({ message: "Unauthorized" }) + } + if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) { + return yield* new Unauthorized({ message: "Unauthorized" }) + } + return yield* effect + }), + }), +) - const instance = HttpRouter.middleware()( - Effect.gen(function* () { - return (effect) => - Effect.gen(function* () { - const query = yield* HttpServerRequest.schemaSearchParams(Query) - const headers = yield* HttpServerRequest.schemaHeaders(Headers) - const raw = query.directory || headers["x-opencode-directory"] || process.cwd() - const workspace = query.workspace || undefined - const ctx = yield* Effect.promise(() => - Instance.provide({ - directory: Filesystem.resolve(decode(raw)), - init: () => AppRuntime.runPromise(InstanceBootstrap), - fn: () => Instance.current, - }), - ) +const instance = HttpRouter.middleware()( + Effect.gen(function* () { + return (effect) => + Effect.gen(function* () { + const query = yield* HttpServerRequest.schemaSearchParams(Query) + const headers = yield* HttpServerRequest.schemaHeaders(Headers) + const raw = query.directory || headers["x-opencode-directory"] || process.cwd() + const workspace = query.workspace || undefined + const ctx = yield* Effect.promise(() => + Instance.provide({ + directory: Filesystem.resolve(decode(raw)), + init: () => AppRuntime.runPromise(InstanceBootstrap), + fn: () => Instance.current, + }), + ) - const next = workspace ? effect.pipe(Effect.provideService(WorkspaceRef, workspace)) : effect - return yield* next.pipe(Effect.provideService(InstanceRef, ctx)) - }) - }), - ).layer + const next = workspace ? effect.pipe(Effect.provideService(WorkspaceRef, workspace)) : effect + return yield* next.pipe(Effect.provideService(InstanceRef, ctx)) + }) + }), +).layer - const QuestionSecured = QuestionApi.middleware(Authorization) - const PermissionSecured = PermissionApi.middleware(Authorization) - const ProviderSecured = ProviderApi.middleware(Authorization) +const QuestionSecured = QuestionApi.middleware(Authorization) +const PermissionSecured = PermissionApi.middleware(Authorization) +const ProviderSecured = ProviderApi.middleware(Authorization) - export const routes = Layer.mergeAll( - HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), - HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), - HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)), - ).pipe( - Layer.provide(auth), - Layer.provide(normalize), - Layer.provide(instance), - Layer.provide(HttpServer.layerServices), - Layer.provideMerge(Observability.layer), - ) +export const routes = Layer.mergeAll( + HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)), + HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)), + HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)), +).pipe( + Layer.provide(auth), + Layer.provide(normalize), + Layer.provide(instance), + Layer.provide(HttpServer.layerServices), + Layer.provideMerge(Observability.layer), +) - export const webHandler = lazy(() => - HttpRouter.toWebHandler(routes, { - memoMap, - }), - ) -} +export const webHandler = lazy(() => + HttpRouter.toWebHandler(routes, { + memoMap, + }), +) + +export * as ExperimentalHttpApiServer from "./server"