# Fx.Fx

`Fx` is a reactive stream of values that supports concurrency, error handling,
and context management, fully integrated with the Effect ecosystem.

Conceptually, an `Fx<A, E, R>` is a push-based stream that:
- Emits values of type `A`
- Can fail with an error of type `E`
- Requires a context/environment of type `R`

Unlike a standard `Effect` which produces a single value, `Fx` can produce
0, 1, or many values over time. It is similar to RxJS Observables or
AsyncIterables, but built on top of Effect's fiber-based concurrency model.

## Signatures

```ts
export interface Fx<A, E = never, R = never> extends Pipeable {
    readonly [FxTypeId]: Fx.Variance<A, E, R>;
    readonly run: <RSink>(sink: Sink.Sink<A, E, RSink>) => Effect.Effect<unknown, never, R | RSink>;
}
```

```ts
export declare namespace Fx {
    type Any = Fx<any, any, any>;
    interface Variance<A, E, R> {
        readonly _A: Types.Covariant<A>;
        readonly _E: Types.Covariant<E>;
        readonly _R: Types.Covariant<R>;
    }
    type Success<T> = [
        T
    ] extends [
        never
    ] ? never : T extends Fx<infer _A, infer _E, infer _R> ? _A : never;
    type Error<T> = [
        T
    ] extends [
        never
    ] ? never : T extends Fx<infer _A, infer _E, infer _R> ? _E : never;
    type Services<T> = [
        T
    ] extends [
        never
    ] ? never : [
        T
    ] extends [
        Fx<infer _A, infer _E, infer _R>
    ] ? _R : never;
    interface Service<Self, Id extends string, A, E> extends Fx<A, E, Self> {
        readonly id: Id;
        readonly service: Context.Service<Self, Fx<A, E>>;
        readonly make: <R = never>(fx: Fx<A, E, R> | Effect.Effect<Fx<A, E, R>, E, R>) => Layer<Self, E, Exclude<R, Scope.Scope>>;
    }
    interface Class<Self, Id extends string, A, E> extends Service<Self, Id, A, E> {
        new (): Service<Self, Id, A, E>;
    }
}
```

## Why

Browser events, clocks, sockets, and users decide when work exists. `Fx`
models that producer-driven direction while retaining Effect's explicit
success, error, and service channels. An `Effect`, `Stream`, `Promise`,
`ReadableStream`, iterable, or custom source can participate through an
explicit constructor; `Fx` extends the Effect ecosystem rather than
replacing it.

## Ownership and lifetime

Constructing an `Fx` starts no work. Calling `run` returns an `Effect` whose
running fiber and `Scope` own subscriptions, child fibers, and finalizers.
Interruption propagates through that Effect lifetime. The supplied `Sink`
contributes its requirements to `run`; failures are delivered to the Sink,
which is why the returned Effect itself cannot fail.

## Composition

The type parameters follow Effect's `A`, `E`, `R` vocabulary. Consequently,
an `Fx<RenderEvent, E, R>` can describe arbitrary UI without hiding its
failures or required services.

## Effect foundations

`Fx` execution is an [Effect](https://effect.website/docs/v4/api/effect/Effect),
resource ownership uses [Scope](https://effect.website/docs/v4/api/effect/Scope),
concurrent runs use [Fiber](https://effect.website/docs/v4/api/effect/Fiber), and
failures retain Effect's structured [Cause](https://effect.website/docs/v4/api/effect/Cause).

## Property: [[computed:[FxTypeId]]]

Identifies this value as an `Fx` and records its success, error, and service variance.

## Property: [[computed:[FxTypeId]]]: Why

The marker makes `Fx` distinguishable at runtime without executing it, while its
type carries the three channels through structural composition.

## Property: [[computed:[FxTypeId]]]: Ownership and lifetime

Reading the marker starts no work and acquires no resources.

## Property: run

Connects this producer to a `Sink` and returns the `Effect` that owns the connection.

## Property: run: Why

Keeping execution behind an `Effect` preserves typed services, structured
concurrency, and interruption instead of starting hidden work during construction.
Values are offered to the sink in the order chosen by this `Fx`; the producer may
emit zero, one, or many values.

## Property: run: Ownership and lifetime

Work starts when the returned `Effect` runs. Its fiber owns the subscription and
any child scopes. Interrupting it interrupts the producer and runs its finalizers.
Producer failures are delivered to `sink.onFailure`, so they are not repeated in
the returned Effect's error channel.

## Examples

```ts
import { Effect } from "effect"
import { Fx } from "@typed/fx"

const keys: Fx.Fx<KeyboardEvent> = Fx.callback((emit) => {
  const onKey = (event: KeyboardEvent) => emit.succeed(event)
  document.addEventListener("keydown", onKey)
  return Effect.sync(() => document.removeEventListener("keydown", onKey))
})
```
