registry.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. export * as SystemContextRegistry from "./registry"
  2. import { Context, Effect, Layer, Ref, Scope } from "effect"
  3. import { SystemContext } from "./index"
  4. export interface Entry {
  5. readonly key: SystemContext.Key
  6. readonly load: Effect.Effect<SystemContext.SystemContext>
  7. }
  8. export interface Interface {
  9. readonly register: (entry: Entry) => Effect.Effect<void, never, Scope.Scope>
  10. readonly load: () => Effect.Effect<SystemContext.SystemContext>
  11. }
  12. export class Service extends Context.Service<Service, Interface>()("@opencode/v2/SystemContextRegistry") {}
  13. export const layer = Layer.effect(
  14. Service,
  15. Effect.gen(function* () {
  16. const entries = yield* Ref.make<ReadonlyArray<Entry>>([])
  17. return Service.of({
  18. register: Effect.fn("SystemContextRegistry.register")(function* (entry) {
  19. yield* Effect.acquireRelease(
  20. Ref.modify(entries, (current) => {
  21. if (current.some((item) => item.key === entry.key)) return [false, current]
  22. return [true, [...current, entry]]
  23. }).pipe(
  24. Effect.flatMap((added) =>
  25. added ? Effect.void : Effect.die(`Duplicate system context entry key: ${entry.key}`),
  26. ),
  27. Effect.as(entry),
  28. ),
  29. (entry) => Ref.update(entries, (current) => current.filter((item) => item !== entry)),
  30. )
  31. }),
  32. load: Effect.fn("SystemContextRegistry.load")(function* () {
  33. const current = (yield* Ref.get(entries)).toSorted((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
  34. return SystemContext.combine(
  35. yield* Effect.forEach(current, (entry) => entry.load, { concurrency: "unbounded" }),
  36. )
  37. }),
  38. })
  39. }),
  40. )