instances.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { Effect, Layer, LayerMap, ServiceMap } from "effect"
  2. import { registerDisposer } from "./instance-registry"
  3. import { ProviderAuthService } from "@/provider/auth-service"
  4. import { QuestionService } from "@/question/service"
  5. import { PermissionService } from "@/permission/service"
  6. import { Instance } from "@/project/instance"
  7. import type { Project } from "@/project/project"
  8. export declare namespace InstanceContext {
  9. export interface Shape {
  10. readonly directory: string
  11. readonly project: Project.Info
  12. }
  13. }
  14. export class InstanceContext extends ServiceMap.Service<InstanceContext, InstanceContext.Shape>()(
  15. "opencode/InstanceContext",
  16. ) {}
  17. export type InstanceServices = QuestionService | PermissionService | ProviderAuthService
  18. function lookup(directory: string) {
  19. const project = Instance.project
  20. const ctx = Layer.sync(InstanceContext, () => InstanceContext.of({ directory, project }))
  21. return Layer.mergeAll(
  22. Layer.fresh(QuestionService.layer),
  23. Layer.fresh(PermissionService.layer),
  24. Layer.fresh(ProviderAuthService.layer),
  25. ).pipe(Layer.provide(ctx))
  26. }
  27. export class Instances extends ServiceMap.Service<Instances, LayerMap.LayerMap<string, InstanceServices>>()(
  28. "opencode/Instances",
  29. ) {
  30. static readonly layer = Layer.effect(
  31. Instances,
  32. Effect.gen(function* () {
  33. const layerMap = yield* LayerMap.make(lookup, { idleTimeToLive: Infinity })
  34. const unregister = registerDisposer((directory) => Effect.runPromise(layerMap.invalidate(directory)))
  35. yield* Effect.addFinalizer(() => Effect.sync(unregister))
  36. return Instances.of(layerMap)
  37. }),
  38. )
  39. static get(directory: string): Layer.Layer<InstanceServices, never, Instances> {
  40. return Layer.unwrap(Instances.use((map) => Effect.succeed(map.get(directory))))
  41. }
  42. static invalidate(directory: string): Effect.Effect<void, never, Instances> {
  43. return Instances.use((map) => map.invalidate(directory))
  44. }
  45. }