47 lines
1.7 KiB
TypeScript
47 lines
1.7 KiB
TypeScript
export * as SystemContextRegistry from "./registry"
|
|
|
|
import { Context, Effect, Layer, Ref, Scope } from "effect"
|
|
import { SystemContext } from "./index"
|
|
|
|
export interface Entry {
|
|
readonly key: SystemContext.Key
|
|
readonly load: Effect.Effect<SystemContext.SystemContext>
|
|
}
|
|
|
|
export interface Interface {
|
|
readonly register: (entry: Entry) => Effect.Effect<void, never, Scope.Scope>
|
|
readonly load: () => Effect.Effect<SystemContext.SystemContext>
|
|
}
|
|
|
|
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/SystemContextRegistry") {}
|
|
|
|
export const layer = Layer.effect(
|
|
Service,
|
|
Effect.gen(function* () {
|
|
const entries = yield* Ref.make<ReadonlyArray<Entry>>([])
|
|
|
|
return Service.of({
|
|
register: Effect.fn("SystemContextRegistry.register")(function* (entry) {
|
|
yield* Effect.acquireRelease(
|
|
Ref.modify(entries, (current) => {
|
|
if (current.some((item) => item.key === entry.key)) return [false, current]
|
|
return [true, [...current, entry]]
|
|
}).pipe(
|
|
Effect.flatMap((added) =>
|
|
added ? Effect.void : Effect.die(`Duplicate system context entry key: ${entry.key}`),
|
|
),
|
|
Effect.as(entry),
|
|
),
|
|
(entry) => Ref.update(entries, (current) => current.filter((item) => item !== entry)),
|
|
)
|
|
}),
|
|
load: Effect.fn("SystemContextRegistry.load")(function* () {
|
|
const current = (yield* Ref.get(entries)).toSorted((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
|
|
return SystemContext.combine(
|
|
yield* Effect.forEach(current, (entry) => entry.load, { concurrency: "unbounded" }),
|
|
)
|
|
}),
|
|
})
|
|
}),
|
|
)
|