Files
anomalyco_opencode/packages/opencode/src/effect/config-service.ts
T
James Long 8c94e9005f chore: merge dev into v2 (#34788)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com>
Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ben Guthrie <benjee.012@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Max Anderson <max.a.anderson95@gmail.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
2026-07-01 17:12:00 -04:00

68 lines
2.5 KiB
TypeScript

import { Config, Context, Effect, Layer } from "effect"
type ConfigMap = Record<string, Config.Config<unknown>>
/**
* The service shape inferred from an object of Effect `Config` definitions.
*/
export type Shape<Fields extends ConfigMap> = {
readonly [Key in keyof Fields]: Config.Success<Fields[Key]>
}
/**
* A Context service class with generated layers for config-backed services.
*/
export type ServiceClass<Self, Id extends string, Service> = Context.ServiceClass<Self, Id, Service> & {
/** Provide already-parsed config, useful in tests. */
readonly configLayer: (input: Service) => Layer.Layer<Self>
/** Parse config once from the active Effect ConfigProvider and provide the service. */
readonly layer: Layer.Layer<Self, Config.ConfigError>
}
/**
* Create a Context service whose implementation is derived from Effect `Config`.
*
* This keeps Effect `Config` as the source of truth for env names, defaults, and
* validation while generating a typed service plus convenient production/test
* layers.
*
* ```ts
* class ServerAuthConfig extends ConfigService.Service<ServerAuthConfig>()(
* "@opencode/ServerAuthConfig",
* {
* password: Config.string("OPENCODE_SERVER_PASSWORD").pipe(Config.option),
* username: Config.string("OPENCODE_SERVER_USERNAME").pipe(Config.withDefault("opencode")),
* },
* ) {}
*
* const live = ServerAuthConfig.layer
* const test = ServerAuthConfig.configLayer({ password: Option.some("secret"), username: "kit" })
* ```
*/
export const Service =
<Self>() =>
<const Id extends string, const Fields extends ConfigMap>(id: Id, fields: Fields) => {
class ConfigTag extends Context.Service<Self, Shape<Fields>>()(id) {
static configLayer(input: Shape<Fields>) {
return Layer.succeed(this, this.of(input))
}
static get layer() {
const tag = this
return Layer.effect(
tag,
Effect.gen(function* () {
const config = yield* Config.all(fields)
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Config.all preserves the field shape, but its conditional return type also supports iterable inputs.
return tag.of(config as Shape<Fields>)
}),
)
}
}
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- The generated class carries typed static helpers.
return ConfigTag as ServiceClass<Self, Id, Shape<Fields>>
}
export * as ConfigService from "./config-service"