session-location.ts 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import { Database } from "@kirincode-ai/core/database/database"
  2. import { LocationServiceMap } from "@kirincode-ai/core/location-services"
  3. import { Location } from "@kirincode-ai/core/location"
  4. import { AbsolutePath } from "@kirincode-ai/core/schema"
  5. import { SessionV2 } from "@kirincode-ai/core/session"
  6. import { SessionTable } from "@kirincode-ai/core/session/sql"
  7. import { WorkspaceV2 } from "@kirincode-ai/core/workspace"
  8. import { eq } from "drizzle-orm"
  9. import { Effect, Layer, Schema } from "effect"
  10. import { HttpRouter } from "effect/unstable/http"
  11. import { HttpApiMiddleware } from "effect/unstable/httpapi"
  12. import { InvalidRequestError, SessionNotFoundError } from "@kirincode-ai/protocol/errors"
  13. import type { LocationServices } from "../location"
  14. export class SessionLocationMiddleware extends HttpApiMiddleware.Service<
  15. SessionLocationMiddleware,
  16. { provides: LocationServices }
  17. >()("@kirincode/HttpApiSessionLocation", {
  18. error: [InvalidRequestError, SessionNotFoundError],
  19. }) {}
  20. const decodeSessionID = Schema.decodeUnknownEffect(SessionV2.ID)
  21. export const sessionLocationLayer = Layer.effect(
  22. SessionLocationMiddleware,
  23. Effect.gen(function* () {
  24. const { db } = yield* Database.Service
  25. const locations = yield* LocationServiceMap.Service
  26. return SessionLocationMiddleware.of((effect) =>
  27. Effect.gen(function* () {
  28. const route = yield* HttpRouter.RouteContext
  29. const sessionID = yield* decodeSessionID(route.params.sessionID).pipe(
  30. Effect.mapError(
  31. () =>
  32. new InvalidRequestError({
  33. message: "Invalid session ID",
  34. field: "sessionID",
  35. }),
  36. ),
  37. )
  38. const row = yield* db
  39. .select({ directory: SessionTable.directory, workspaceID: SessionTable.workspace_id })
  40. .from(SessionTable)
  41. .where(eq(SessionTable.id, sessionID))
  42. .get()
  43. .pipe(Effect.orDie)
  44. if (!row)
  45. return yield* new SessionNotFoundError({
  46. sessionID,
  47. message: `Session not found: ${sessionID}`,
  48. })
  49. return yield* effect.pipe(
  50. Effect.provide(
  51. locations.get(
  52. Location.Ref.make({
  53. directory: AbsolutePath.make(row.directory),
  54. workspaceID: row.workspaceID ? WorkspaceV2.ID.make(row.workspaceID) : undefined,
  55. }),
  56. ),
  57. ),
  58. )
  59. }),
  60. )
  61. }),
  62. )