import { Cause, Context, Effect, identity, Layer, PubSub, Stream } from "effect" import type { Mutable } from "effect/Types" export interface QueryErrorHandler { readonly errors: Stream.Stream> readonly handle: (self: Effect.Effect) => Effect.Effect, R> } export type Fallback = T extends QueryErrorHandler ? A : never export type Error = T extends QueryErrorHandler ? E : never export interface ServiceResult< Self, Id extends string, FallbackA, HandledE, > extends Context.TagClass< Self, Id, QueryErrorHandler > { readonly Default: Layer.Layer } export const Service = () => ( ( id: Id, f: ( self: Effect.Effect, failure: (failure: HandledE) => Effect.Effect, defect: (defect: unknown) => Effect.Effect, ) => Effect.Effect, ): ServiceResult => { const TagClass = Context.Tag(id)() as ServiceResult (TagClass as Mutable).Default = Layer.effect(TagClass, Effect.gen(function*() { const pubsub = yield* PubSub.unbounded>() const errors = Stream.fromPubSub(pubsub) const handle = ( self: Effect.Effect ): Effect.Effect, R> => f( self as unknown as Effect.Effect, (failure: HandledE) => PubSub.publish(pubsub, Cause.fail(failure)).pipe( Effect.andThen(Effect.failCause(Cause.empty)) ), (defect: unknown) => PubSub.publish(pubsub, Cause.die(defect)).pipe( Effect.andThen(Effect.failCause(Cause.empty)) ), ) return { errors, handle } })) return TagClass } ) export class DefaultQueryErrorHandler extends Service()( "@reffuse/extension-query/DefaultQueryErrorHandler", identity, ) {}