import { Context, Data, Effect, Layer, RequestResolver } from "effect-app" import { dual } from "effect/Function" import type * as Request from "effect/Request" import { ContextMap } from "./service.js" // TODO: we have to create a new contextmap on every request. // we want to share one map during startup // but we want to make sure we don't re-use the startup map after startup // we can call another start after startup. but it would be even better if we could Die on accessing rootmap // we could also make the ContextMap optional, and when missing, issue a warning instead? export class ContextMapContainer extends Context.Reference("ContextMapContainer", { defaultValue: (): ContextMap | "root" => "root" }) { static readonly layer = Layer.effect(this, ContextMap.make.pipe(Effect.map(ContextMap.of))) } export class ContextMapNotStartedError extends Data.TaggedError("ContextMapNotStartedError") {} export const getContextMap = ContextMapContainer.asEffect().pipe( Effect.filterOrFail((_) => _ !== "root", () => new ContextMapNotStartedError()) ) /** * Uses the official `RequestResolver.withCache` internally, * creating one cached resolver per ContextMap (i.e. per request). * Uses a shared semaphore in the ContextMap to ensure safe single initialization. */ export const withRequestResolverCache: { >(options: { readonly capacity: number readonly strategy?: "lru" | "fifo" | undefined }): ( self: RequestResolver.RequestResolver ) => Effect.Effect, ContextMapNotStartedError> >( self: RequestResolver.RequestResolver, options: { readonly capacity: number readonly strategy?: "lru" | "fifo" | undefined } ): Effect.Effect, ContextMapNotStartedError> } = dual(2, >( self: RequestResolver.RequestResolver, options: { readonly capacity: number readonly strategy?: "lru" | "fifo" | undefined } ): Effect.Effect, ContextMapNotStartedError> => { const cacheKey = Symbol() return getContextMap.pipe( Effect.flatMap((ctxMap) => ctxMap.getOrCreateStoreEffect( cacheKey, RequestResolver.withCache(self, options) ) ) ) })