import { Effect, ScopedCache, Scope } from "effect" import { Instance, type Shape } from "@/project/instance" import { registerDisposer } from "./instance-registry" const TypeId = "~opencode/InstanceState" export interface InstanceState { readonly [TypeId]: typeof TypeId readonly cache: ScopedCache.ScopedCache } export namespace InstanceState { export const make = ( init: (ctx: Shape) => Effect.Effect, ): Effect.Effect>, never, R | Scope.Scope> => Effect.gen(function* () { const cache = yield* ScopedCache.make({ capacity: Number.POSITIVE_INFINITY, lookup: () => init(Instance.current), }) const off = registerDisposer((directory) => Effect.runPromise(ScopedCache.invalidate(cache, directory))) yield* Effect.addFinalizer(() => Effect.sync(off)) return { [TypeId]: TypeId, cache, } }) export const get = (self: InstanceState) => Effect.suspend(() => ScopedCache.get(self.cache, Instance.directory)) export const use = (self: InstanceState, select: (value: A) => B) => Effect.map(get(self), select) export const useEffect = ( self: InstanceState, select: (value: A) => Effect.Effect, ) => Effect.flatMap(get(self), select) export const has = (self: InstanceState) => Effect.suspend(() => ScopedCache.has(self.cache, Instance.directory)) export const invalidate = (self: InstanceState) => Effect.suspend(() => ScopedCache.invalidate(self.cache, Instance.directory)) }