Browse Source

feat(server): extract question handler factory

Shoubhit Dash 3 days ago
parent
commit
467e5689ec

+ 12 - 24
packages/opencode/src/server/instance/httpapi/question.ts

@@ -3,39 +3,27 @@ import { memoMap } from "@/effect/run-service"
 import { Question } from "@/question"
 import { QuestionID } from "@/question/schema"
 import { lazy } from "@/util/lazy"
-import { QuestionReply, QuestionRequest, questionApi } from "@opencode-ai/server"
-import { Effect, Layer, Schema } from "effect"
+import { makeQuestionHandler, questionApi } from "@opencode-ai/server"
+import { Effect, Layer } from "effect"
 import { HttpRouter, HttpServer } from "effect/unstable/http"
 import { HttpApiBuilder } from "effect/unstable/httpapi"
 import type { Handler } from "hono"
 
 const root = "/experimental/httpapi/question"
 
-const QuestionLive = HttpApiBuilder.group(
-  questionApi,
-  "question",
-  Effect.fn("QuestionHttpApi.handlers")(function* (handlers) {
+const QuestionLive = makeQuestionHandler({
+  list: Effect.fn("QuestionHttpApi.host.list")(function* () {
     const svc = yield* Question.Service
-    const decode = Schema.decodeUnknownSync(Schema.Array(QuestionRequest))
-
-    const list = Effect.fn("QuestionHttpApi.list")(function* () {
-      return decode(yield* svc.list())
-    })
-
-    const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: {
-      params: { requestID: string }
-      payload: Schema.Schema.Type<typeof QuestionReply>
-    }) {
-      yield* svc.reply({
-        requestID: QuestionID.make(ctx.params.requestID),
-        answers: ctx.payload.answers,
-      })
-      return true
+    return yield* svc.list()
+  }),
+  reply: Effect.fn("QuestionHttpApi.host.reply")(function* (input) {
+    const svc = yield* Question.Service
+    yield* svc.reply({
+      requestID: QuestionID.make(input.requestID),
+      answers: input.answers,
     })
-
-    return handlers.handle("list", list).handle("reply", reply)
   }),
-).pipe(Layer.provide(Question.defaultLayer))
+}).pipe(Layer.provide(Question.defaultLayer))
 
 const web = lazy(() =>
   HttpRouter.toWebHandler(

+ 2 - 1
packages/server/package.json

@@ -10,7 +10,8 @@
     "./definition": "./src/definition/index.ts",
     "./definition/api": "./src/definition/api.ts",
     "./definition/question": "./src/definition/question.ts",
-    "./api": "./src/api/index.ts"
+    "./api": "./src/api/index.ts",
+    "./api/question": "./src/api/question.ts"
   },
   "files": [
     "dist"

+ 2 - 1
packages/server/src/api/index.ts

@@ -1 +1,2 @@
-export {}
+export { makeQuestionHandler } from "./question.js"
+export type { QuestionOps } from "./question.js"

+ 37 - 0
packages/server/src/api/question.ts

@@ -0,0 +1,37 @@
+import { Effect, Schema } from "effect"
+import { HttpApiBuilder } from "effect/unstable/httpapi"
+import { QuestionReply, QuestionRequest, questionApi } from "../definition/question.js"
+
+export interface QuestionOps<R = never> {
+  readonly list: () => Effect.Effect<ReadonlyArray<unknown>, never, R>
+  readonly reply: (input: {
+    requestID: string
+    answers: Schema.Schema.Type<typeof QuestionReply>["answers"]
+  }) => Effect.Effect<void, never, R>
+}
+
+export const makeQuestionHandler = <R>(ops: QuestionOps<R>) =>
+  HttpApiBuilder.group(
+    questionApi,
+    "question",
+    Effect.fn("QuestionHttpApi.handlers")(function* (handlers) {
+      const decode = Schema.decodeUnknownSync(Schema.Array(QuestionRequest))
+
+      const list = Effect.fn("QuestionHttpApi.list")(function* () {
+        return decode(yield* ops.list())
+      })
+
+      const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: {
+        params: { requestID: string }
+        payload: Schema.Schema.Type<typeof QuestionReply>
+      }) {
+        yield* ops.reply({
+          requestID: ctx.params.requestID,
+          answers: ctx.payload.answers,
+        })
+        return true
+      })
+
+      return handlers.handle("list", list).handle("reply", reply)
+    }),
+  )

+ 2 - 0
packages/server/src/index.ts

@@ -1,4 +1,6 @@
 export { openapi } from "./openapi.js"
+export { makeQuestionHandler } from "./api/question.js"
 export { api } from "./definition/api.js"
 export { questionApi, QuestionReply, QuestionRequest } from "./definition/question.js"
 export type { OpenApiSpec, ServerApi } from "./types.js"
+export type { QuestionOps } from "./api/question.js"