0.2.1 #26

Merged
Thilawyn merged 144 commits from next into master 2025-12-01 23:37:40 +01:00
3 changed files with 46 additions and 17 deletions
Showing only changes of commit 7e14f27df4 - Show all commits

View File

@@ -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> {
handle<Eff extends Effect.Effect<any, any, any>>(effect: Eff): Eff
export const TypeId: unique symbol = Symbol.for("@effect-fc/ErrorObserver/ErrorObserver")
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>
}
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 {
export type Handler<EIn, EOut> = (
self: Effect.Effect<never, NoInfer<EIn>>,
push: {
failure(failure: NoInfer<EIn>): Effect.Effect<never>
defect(defect: unknown): Effect.Effect<never>
},
) => Effect.Effect<EOut>
constructor(
private readonly pubsub: PubSub.PubSub<Cause.Cause<E>>
) {
super()
this.subscribe = pubsub.subscribe
}
export const make = <EIn = never>() => <EOut>(
f: make.Handler<NoInfer<EIn>, EOut>
): Effect.Effect<ErrorObserver<EIn, 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 isErrorObserver = (u: unknown): u is ErrorObserver<unknown> => Predicate.hasProperty(u, TypeId)
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,
}),
)

View File

@@ -2,6 +2,7 @@
import { Effect, Layer, ManagedRuntime, Predicate, type Runtime } from "effect"
import * as React from "react"
import * as Component from "./Component.js"
import * as ErrorObserver from "./ErrorObserver.js"
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)
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 make = <R, ER>(
layer: Layer.Layer<R, ER>,
memoMap?: Layer.MemoMap,
): ReactRuntime<R | Component.ScopeMap, ER> => Object.setPrototypeOf(
): ReactRuntime<Layer.Layer.Success<typeof Prelude> | R, ER> => Object.setPrototypeOf(
Object.assign(function() {}, {
runtime: ManagedRuntime.make(
Layer.merge(layer, Component.ScopeMap.Default),
Layer.merge(layer, Prelude),
memoMap,
),
// biome-ignore lint/style/noNonNullAssertion: context initialization

View File

@@ -1,5 +1,6 @@
export * as Async from "./Async.js"
export * as Component from "./Component.js"
export * as ErrorObserver from "./ErrorObserver.js"
export * as Form from "./Form.js"
export * as Memoized from "./Memoized.js"
export * as PropertyPath from "./PropertyPath.js"