0.2.1 #26
@@ -1,24 +1,46 @@
|
|||||||
import { type Cause, Context, type Effect, Layer, type Queue, type Scope } from "effect"
|
import { type Cause, Context, Effect, Layer, Option, Pipeable, Predicate, PubSub, type Queue, type Scope } from "effect"
|
||||||
|
|
||||||
|
|
||||||
export interface ErrorObserver<E = never> {
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/ErrorObserver/ErrorObserver")
|
||||||
handle<Eff extends Effect.Effect<any, any, any>>(effect: Eff): Eff
|
export type TypeId = typeof TypeId
|
||||||
|
|
||||||
|
export interface ErrorObserver<in out E = never> extends Pipeable.Pipeable {
|
||||||
|
readonly [TypeId]: TypeId
|
||||||
|
handle<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
|
||||||
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ErrorObserver = <E = never>(): Context.Tag<ErrorObserver<E>, ErrorObserver<E>> => Context.GenericTag("@effect-fc/ErrorObserver/ErrorObserver")
|
export const ErrorObserver = <E = never>(): Context.Tag<ErrorObserver, ErrorObserver<E>> => Context.GenericTag("@effect-fc/ErrorObserver/ErrorObserver")
|
||||||
|
|
||||||
|
class ErrorObserverImpl<in out E = never>
|
||||||
|
extends Pipeable.Class() implements ErrorObserver<E> {
|
||||||
|
readonly [TypeId]: TypeId = TypeId
|
||||||
|
readonly subscribe: Effect.Effect<Queue.Dequeue<Cause.Cause<E>>, never, Scope.Scope>
|
||||||
|
|
||||||
export namespace make {
|
constructor(
|
||||||
export type Handler<EIn, EOut> = (
|
private readonly pubsub: PubSub.PubSub<Cause.Cause<E>>
|
||||||
self: Effect.Effect<never, NoInfer<EIn>>,
|
) {
|
||||||
push: {
|
super()
|
||||||
failure(failure: NoInfer<EIn>): Effect.Effect<never>
|
this.subscribe = pubsub.subscribe
|
||||||
defect(defect: unknown): Effect.Effect<never>
|
}
|
||||||
},
|
|
||||||
) => Effect.Effect<EOut>
|
handle<A, EffE, R>(effect: Effect.Effect<A, EffE, R>): Effect.Effect<A, EffE, R> {
|
||||||
|
return Effect.tapErrorCause(effect, cause => PubSub.publish(this.pubsub, cause as Cause.Cause<E>))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const make = <EIn = never>() => <EOut>(
|
|
||||||
f: make.Handler<NoInfer<EIn>, EOut>
|
export const isErrorObserver = (u: unknown): u is ErrorObserver<unknown> => Predicate.hasProperty(u, TypeId)
|
||||||
): Effect.Effect<ErrorObserver<EIn, EOut>> =>
|
|
||||||
|
export const layer: Layer.Layer<ErrorObserver> = Layer.effect(ErrorObserver(), Effect.andThen(
|
||||||
|
PubSub.unbounded<Cause.Cause<never>>(),
|
||||||
|
pubsub => new ErrorObserverImpl(pubsub),
|
||||||
|
))
|
||||||
|
|
||||||
|
export const handle = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => Effect.andThen(
|
||||||
|
Effect.serviceOption(ErrorObserver()),
|
||||||
|
Option.match({
|
||||||
|
onSome: observer => observer.handle(effect),
|
||||||
|
onNone: () => effect,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { Effect, Layer, ManagedRuntime, Predicate, type Runtime } from "effect"
|
import { Effect, Layer, ManagedRuntime, Predicate, type Runtime } from "effect"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as Component from "./Component.js"
|
import * as Component from "./Component.js"
|
||||||
|
import * as ErrorObserver from "./ErrorObserver.js"
|
||||||
|
|
||||||
|
|
||||||
export const TypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime")
|
||||||
@@ -16,16 +17,21 @@ export interface ReactRuntime<R, ER> {
|
|||||||
|
|
||||||
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
|
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
|
||||||
|
|
||||||
|
export const Prelude: Layer.Layer<Component.ScopeMap | ErrorObserver.ErrorObserver> = Layer.mergeAll(
|
||||||
|
Component.ScopeMap.Default,
|
||||||
|
ErrorObserver.layer,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
export const isReactRuntime = (u: unknown): u is ReactRuntime<unknown, unknown> => Predicate.hasProperty(u, TypeId)
|
export const isReactRuntime = (u: unknown): u is ReactRuntime<unknown, unknown> => Predicate.hasProperty(u, TypeId)
|
||||||
|
|
||||||
export const make = <R, ER>(
|
export const make = <R, ER>(
|
||||||
layer: Layer.Layer<R, ER>,
|
layer: Layer.Layer<R, ER>,
|
||||||
memoMap?: Layer.MemoMap,
|
memoMap?: Layer.MemoMap,
|
||||||
): ReactRuntime<R | Component.ScopeMap, ER> => Object.setPrototypeOf(
|
): ReactRuntime<Layer.Layer.Success<typeof Prelude> | R, ER> => Object.setPrototypeOf(
|
||||||
Object.assign(function() {}, {
|
Object.assign(function() {}, {
|
||||||
runtime: ManagedRuntime.make(
|
runtime: ManagedRuntime.make(
|
||||||
Layer.merge(layer, Component.ScopeMap.Default),
|
Layer.merge(layer, Prelude),
|
||||||
memoMap,
|
memoMap,
|
||||||
),
|
),
|
||||||
// biome-ignore lint/style/noNonNullAssertion: context initialization
|
// biome-ignore lint/style/noNonNullAssertion: context initialization
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export * as Async from "./Async.js"
|
export * as Async from "./Async.js"
|
||||||
export * as Component from "./Component.js"
|
export * as Component from "./Component.js"
|
||||||
|
export * as ErrorObserver from "./ErrorObserver.js"
|
||||||
export * as Form from "./Form.js"
|
export * as Form from "./Form.js"
|
||||||
export * as Memoized from "./Memoized.js"
|
export * as Memoized from "./Memoized.js"
|
||||||
export * as PropertyPath from "./PropertyPath.js"
|
export * as PropertyPath from "./PropertyPath.js"
|
||||||
|
|||||||
Reference in New Issue
Block a user