/* eslint-disable @typescript-eslint/no-explicit-any */ import { Context, Effect, type Layer, type NonEmptyReadonlyArray, Option } from "effect-app" import { InfraLogger } from "../logger.js" // TODO: These LayerUtils are flaky, like in dependencies as a readonly array, it breaks when there are two entries // we should look at Service.MakeDeps[E/RIn/ROut] etc. // and in general make sure `dependencies` are NonEmptyReadonlyArrays, so they infer to consts. export namespace LayerUtils { export type GetLayersSuccess> = Layers extends NonEmptyReadonlyArray ? { [k in keyof Layers]: Layer.Success }[number] : Layer.Success export type GetLayersContext> = Layers extends NonEmptyReadonlyArray ? { [k in keyof Layers]: Layer.Services }[number] : Layer.Services export type GetLayersError> = Layers extends NonEmptyReadonlyArray ? { [k in keyof Layers]: Layer.Error }[number] : Layer.Error } export type ContextTagWithDefault = & Context.Service & { Default: Layer.Layer } export namespace ContextTagWithDefault { export type Base = ContextTagWithDefault } export type GetContext = T extends Context.Context ? Y : never export const mergeContexts = Effect.fnUntraced( function*< T extends readonly { maker: any handle: Effect.Effect | Option.Option>> }[] >( makers: T ) { let context = Context.empty() for (const mw of makers) { const ctx = yield* mw.handle.pipe(Effect.provide(context)) const moreContext = Context.isContext(ctx) ? Option.some(ctx) : ctx yield* InfraLogger.logDebug( "Built dynamic context for middleware" + (mw.maker.key ?? mw.maker), Option.map(moreContext, (c) => (c as any).toJSON().services) ) if (moreContext.value) { context = Context.merge(context, moreContext.value) } } return context as Context.Context> } )