/**
* Reactive state primitives for values managed by an `AtomRegistry`.
*
* An `Atom` describes how to produce or update one piece of reactive state. The
* registry runs atom reads, remembers current values, tracks dependencies
* between atoms, starts effects and streams, and cleans up atoms that are no
* longer used. This module includes the atom constructors and update helpers
* used for cached values, effect-backed values, streams, browser state, stored
* values, and server-rendered values.
*
* @stability unstable
* @since 4.0.0
*/
import * as Arr from "../Array.ts";
import * as Cause from "../Cause.ts";
import * as Context from "../Context.ts";
import * as Duration from "../Duration.ts";
import * as Effect from "../Effect.ts";
import type { LazyArg } from "../Function.ts";
import type * as Inspectable from "../Inspectable.ts";
import * as Layer from "../Layer.ts";
import * as Option from "../Option.ts";
import * as KeyValueStore from "../persistence/KeyValueStore.ts";
import type { Pipeable } from "../Pipeable.ts";
import * as Schema from "../Schema.ts";
import * as Scope from "../Scope.ts";
import * as Stream from "../Stream.ts";
import * as SubscriptionRef from "../SubscriptionRef.ts";
import type { NoInfer } from "../Types.ts";
import * as AsyncResult from "./AsyncResult.ts";
import { AtomRegistry } from "./AtomRegistry.ts";
import * as Registry from "./AtomRegistry.ts";
import * as Reactivity from "./Reactivity.ts";
/**
* Type-level identifier used to recognize `Atom` values.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export type TypeId = "~effect/reactivity/Atom";
/**
* Runtime identifier attached to `Atom` values and used by `isAtom`.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export declare const TypeId: TypeId;
/**
* Reactive value read by an `AtomRegistry`, with metadata controlling caching, laziness, refresh behavior, and initial value targeting.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface Atom extends Pipeable, Inspectable.Inspectable {
readonly [TypeId]: TypeId;
readonly keepAlive: boolean;
readonly lazy: boolean;
readonly read: (get: AtomContext) => A;
equals(value: A, next: A): boolean;
readonly refresh?: (f: (atom: Atom) => void) => void;
readonly label?: readonly [name: string, stack: string];
readonly idleTTL?: number;
readonly initialValueTarget?: Atom;
}
/**
* Returns `true` when a value is an `Atom`.
*
* @stability unstable
* @category guards
* @since 4.0.0
*/
export declare const isAtom: (u: unknown) => u is Atom;
/**
* Extracts the value type produced by an `Atom`.
*
* @stability unstable
* @category utility types
* @since 4.0.0
*/
export type Type> = T extends Atom ? A : never;
/**
* Extracts the success value type from an atom whose value is an `AsyncResult`.
*
* @stability unstable
* @category utility types
* @since 4.0.0
*/
export type Success> = T extends Atom> ? A : never;
/**
* Extracts the item type from an atom whose value is a `PullResult`.
*
* @stability unstable
* @category utility types
* @since 4.0.0
*/
export type PullSuccess> = T extends Atom> ? A : never;
/**
* Extracts the failure error type from an atom whose value is an `AsyncResult`.
*
* @stability unstable
* @category utility types
* @since 4.0.0
*/
export type Failure> = T extends Atom> ? E : never;
/**
* Returns an atom type without serializable metadata, preserving `Writable` read and write types when the input atom is writable.
*
* @stability unstable
* @category utility types
* @since 4.0.0
*/
export type WithoutSerializable> = T extends Writable ? Writable : Atom>;
/**
* Runtime identifier attached to writable atoms and used by `isWritable`.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export declare const WritableTypeId: WritableTypeId;
/**
* Type-level identifier used to recognize writable atoms.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export type WritableTypeId = "~effect/reactivity/Atom/Writable";
/**
* Atom that can also be written to, using a `WriteContext` and an input value to update reactive state.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface Writable extends Atom {
readonly [WritableTypeId]: WritableTypeId;
readonly write: (ctx: WriteContext, value: W) => void;
}
/**
* Context passed to atom read functions for reading dependencies, awaiting `AsyncResult` or `Option` values, managing subscriptions and finalizers, refreshing atoms, and updating writable atoms.
*
* @stability unstable
* @category context
* @since 4.0.0
*/
export interface AtomContext {
(atom: Atom): A;
get(this: AtomContext, atom: Atom): A;
result(this: AtomContext, atom: Atom>, options?: {
readonly suspendOnWaiting?: boolean | undefined;
}): Effect.Effect;
resultOnce(this: AtomContext, atom: Atom>, options?: {
readonly suspendOnWaiting?: boolean | undefined;
}): Effect.Effect;
once(this: AtomContext, atom: Atom): A;
addFinalizer(this: AtomContext, f: () => void): void;
mount(this: AtomContext, atom: Atom): void;
refresh(this: AtomContext, atom: Atom): void;
refreshSelf(this: AtomContext): void;
self(this: AtomContext): Option.Option;
setSelf(this: AtomContext, a: A): void;
set(this: AtomContext, atom: Writable, value: W): void;
setResult(this: AtomContext, atom: Writable, W>, value: W): Effect.Effect;
some(this: AtomContext, atom: Atom>): Effect.Effect;
someOnce(this: AtomContext, atom: Atom>): Effect.Effect;
stream(this: AtomContext, atom: Atom, options?: {
readonly withoutInitialValue?: boolean;
readonly bufferSize?: number;
}): Stream.Stream;
streamResult(this: AtomContext, atom: Atom>, options?: {
readonly withoutInitialValue?: boolean;
readonly bufferSize?: number;
}): Stream.Stream;
subscribe(this: AtomContext, atom: Atom, f: (_: A) => void, options?: {
readonly immediate?: boolean;
}): void;
readonly registry: Registry.AtomRegistry;
}
/**
* Context passed to writable atom write functions for reading atoms, refreshing or setting the current atom, and writing to other writable atoms.
*
* @stability unstable
* @category context
* @since 4.0.0
*/
export interface WriteContext {
get(this: WriteContext, atom: Atom): T;
refreshSelf(this: WriteContext): void;
setSelf(this: WriteContext, a: A): void;
set(this: WriteContext, atom: Writable, value: W): void;
}
/**
* Returns a copy of an atom with an idle time-to-live: finite durations dispose it after inactivity, while an infinite duration keeps it alive.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const setIdleTTL: {
/**
* Returns a copy of an atom with an idle time-to-live: finite durations dispose it after inactivity, while an infinite duration keeps it alive.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(duration: Duration.Input): >(self: A) => A;
/**
* Returns a copy of an atom with an idle time-to-live: finite durations dispose it after inactivity, while an infinite duration keeps it alive.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: A, duration: Duration.Input): A;
};
/**
* Returns `true` when an atom is writable.
*
* @stability unstable
* @category guards
* @since 4.0.0
*/
export declare const isWritable: (atom: Atom) => atom is Writable;
/**
* Creates a read-only atom from a read function and an optional custom refresh registration callback.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const readable: (read: (get: AtomContext) => A, refresh?: (f: (atom: Atom) => void) => void) => Atom;
/**
* Creates a writable atom from read and write functions, with an optional custom refresh registration callback.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const writable: (read: (get: AtomContext) => R, write: (ctx: WriteContext, value: W) => void, refresh?: (f: (atom: Atom) => void) => void) => Writable;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const make: {
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(create: (get: AtomContext) => Effect.Effect, options?: {
readonly initialValue?: A | undefined;
readonly uninterruptible?: boolean | undefined;
}): Atom>;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(effect: Effect.Effect, options?: {
readonly initialValue?: A;
readonly uninterruptible?: boolean | undefined;
}): Atom>;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(create: (get: AtomContext) => Stream.Stream, options?: {
readonly initialValue?: A;
}): Atom>;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(stream: Stream.Stream, options?: {
readonly initialValue?: A;
}): Atom>;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(create: (get: AtomContext) => A): Atom;
/**
* Creates an atom from a synchronous value or read function, or from an `Effect` or `Stream` whose state is exposed as an `AsyncResult`; plain values create writable state atoms.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(initialValue: A): Writable;
};
/**
* Atom that builds a `Context` from a `Layer` and exposes constructors for atoms, functions, pulls, and subscription refs that run with that context.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface AtomRuntime extends Atom, ER>> {
readonly factory: RuntimeFactory;
readonly layer: Atom>;
readonly atom: {
(create: (get: AtomContext) => Effect.Effect, options?: {
readonly initialValue?: A;
readonly uninterruptible?: boolean | undefined;
}): Atom>;
(effect: Effect.Effect, options?: {
readonly initialValue?: A;
readonly uninterruptible?: boolean | undefined;
}): Atom>;
(create: (get: AtomContext) => Stream.Stream, options?: {
readonly initialValue?: A;
}): Atom>;
(stream: Stream.Stream, options?: {
readonly initialValue?: A;
}): Atom>;
};
readonly fn: {
(): {
(fn: (arg: Arg, get: FnContext) => Effect.Effect, options?: {
readonly initialValue?: A | undefined;
readonly reactivityKeys?: Reactivity.KeysInput | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
(fn: (arg: Arg, get: FnContext) => Stream.Stream, options?: {
readonly initialValue?: A | undefined;
readonly reactivityKeys?: Reactivity.KeysInput | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
};
(fn: (arg: Arg, get: FnContext) => Effect.Effect, options?: {
readonly initialValue?: A | undefined;
readonly reactivityKeys?: Reactivity.KeysInput | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
(fn: (arg: Arg, get: FnContext) => Stream.Stream, options?: {
readonly initialValue?: A | undefined;
readonly reactivityKeys?: Reactivity.KeysInput | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
};
readonly pull: (create: ((get: AtomContext) => Stream.Stream) | Stream.Stream, options?: {
readonly disableAccumulation?: boolean;
readonly initialValue?: ReadonlyArray;
}) => Writable, void>;
readonly subscriptionRef: (create: Effect.Effect, E, Scope.Scope | R | AtomRegistry | Reactivity.Reactivity> | ((get: AtomContext) => Effect.Effect, E, Scope.Scope | R | AtomRegistry | Reactivity.Reactivity>)) => Writable, A>;
}
/**
* Factory for `AtomRuntime` values that share a set of global layers.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface RuntimeFactory {
(create: Layer.Layer | ((get: AtomContext) => Layer.Layer)): AtomRuntime;
readonly addGlobalLayer: (layer: Layer.Layer) => void;
/**
* Uses the `Reactivity` service from the runtime to refresh the atom whenever
* the keys change.
*/
readonly withReactivity: (keys: Reactivity.KeysInput) => >(atom: A) => A;
}
/**
* A `RuntimeFactory` backed by an atom whose memo map is scoped to each registry.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface RegistryRuntimeFactory extends RuntimeFactory {
readonly memoMap: Atom;
}
/**
* A `RuntimeFactory` backed by a concrete memo map shared across registries.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface SharedRuntimeFactory extends RuntimeFactory {
readonly memoMap: Layer.MemoMap;
}
/**
* Creates a `RuntimeFactory` backed by a registry-scoped memo map by default,
* or by the supplied atom or concrete `Layer.MemoMap`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare function context(): RegistryRuntimeFactory;
/**
* @stability unstable
*/
export declare function context(options: {
readonly memoMap: Atom;
}): RegistryRuntimeFactory;
/**
* @stability unstable
*/
export declare function context(options: {
readonly memoMap: Layer.MemoMap;
}): SharedRuntimeFactory;
/**
* Default registry-scoped `RuntimeFactory`.
*
* @stability unstable
* @category context
* @since 4.0.0
*/
export declare const runtime: RegistryRuntimeFactory;
/**
* Alias for `Atom.runtime.withReactivity` for refreshing an atom whenever the
* keys change in the `Reactivity` service.
*
* **When to use**
*
* Use to refresh an atom whenever one or more invalidation keys change in the
* default reactivity runtime.
*
* @stability unstable
* @category reactivity
* @since 4.0.0
*/
export declare const withReactivity: (keys: Reactivity.KeysInput) => >(atom: A) => A;
/**
* Creates a writable atom backed by a `SubscriptionRef`, or by an effect that produces one, updating from ref changes and writing atom updates back to the ref.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const subscriptionRef: {
/**
* Creates a writable atom backed by a `SubscriptionRef`, or by an effect that produces one, updating from ref changes and writing atom updates back to the ref.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(ref: SubscriptionRef.SubscriptionRef | ((get: AtomContext) => SubscriptionRef.SubscriptionRef)): Writable;
/**
* Creates a writable atom backed by a `SubscriptionRef`, or by an effect that produces one, updating from ref changes and writing atom updates back to the ref.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(effect: Effect.Effect, E, Scope.Scope | AtomRegistry> | ((get: AtomContext) => Effect.Effect, E, Scope.Scope | AtomRegistry>)): Writable, A>;
};
/**
* Context passed to `fn` and `fnSync` computations for reading atoms, awaiting results, registering finalizers, refreshing atoms, subscribing to changes, and writing updates.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface FnContext {
(atom: Atom): A;
result(this: FnContext, atom: Atom>, options?: {
readonly suspendOnWaiting?: boolean | undefined;
}): Effect.Effect;
addFinalizer(this: FnContext, f: () => void): void;
mount(this: FnContext, atom: Atom): void;
refresh(this: FnContext, atom: Atom): void;
self(this: FnContext): Option.Option;
setSelf(this: FnContext, a: A): void;
set(this: FnContext, atom: Writable, value: W): void;
setResult(this: FnContext, atom: Writable, W>, value: W): Effect.Effect;
some(this: FnContext, atom: Atom>): Effect.Effect;
stream(this: FnContext, atom: Atom, options?: {
readonly withoutInitialValue?: boolean;
readonly bufferSize?: number;
}): Stream.Stream;
streamResult(this: FnContext, atom: Atom>, options?: {
readonly withoutInitialValue?: boolean;
readonly bufferSize?: number;
}): Stream.Stream;
subscribe(this: FnContext, atom: Atom, f: (_: A) => void, options?: {
readonly immediate?: boolean;
}): void;
readonly registry: Registry.AtomRegistry;
}
/**
* Creates a writable atom for a synchronous function; writing an argument re-runs the function, returning `Option.none` before the first call unless an initial value is supplied.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const fnSync: {
/**
* Creates a writable atom for a synchronous function; writing an argument re-runs the function, returning `Option.none` before the first call unless an initial value is supplied.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(): {
(f: (arg: Arg, get: FnContext) => A): Writable, Arg>;
(f: (arg: Arg, get: FnContext) => A, options: {
readonly initialValue: A;
}): Writable;
};
/**
* Creates a writable atom for a synchronous function; writing an argument re-runs the function, returning `Option.none` before the first call unless an initial value is supplied.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(f: (arg: Arg, get: FnContext) => A): Writable, Arg>;
/**
* Creates a writable atom for a synchronous function; writing an argument re-runs the function, returning `Option.none` before the first call unless an initial value is supplied.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(f: (arg: Arg, get: FnContext) => A, options: {
readonly initialValue: A;
}): Writable;
};
/**
* Writable async function atom whose value is an `AsyncResult` and whose writes accept function arguments plus `Reset` and `Interrupt` controls.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface AtomResultFn extends Writable, Arg | Reset | Interrupt> {
}
/**
* Defines the control symbol that can be written to an `AtomResultFn` to reset it to its initial state.
*
* **When to use**
*
* Use when you need an `AtomResultFn` write value that clears the current async
* result and returns it to the initial state.
*
* @stability unstable
* @category symbols
* @since 4.0.0
*/
export declare const Reset: unique symbol;
/**
* Type of the `Reset` control symbol accepted by `AtomResultFn` writes.
*
* @stability unstable
* @category symbols
* @since 4.0.0
*/
export type Reset = typeof Reset;
/**
* Defines the control symbol that can be written to an `AtomResultFn` to interrupt the current asynchronous computation.
*
* **When to use**
*
* Use when you need an `AtomResultFn` write value that interrupts the currently
* running async computation.
*
* @stability unstable
* @category symbols
* @since 4.0.0
*/
export declare const Interrupt: unique symbol;
/**
* Type of the `Interrupt` control symbol accepted by `AtomResultFn` writes.
*
* @stability unstable
* @category symbols
* @since 4.0.0
*/
export type Interrupt = typeof Interrupt;
/**
* Creates a writable atom for an `Effect` or `Stream` function; writing an argument starts the computation and exposes its state as an `AsyncResult`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const fn: {
/**
* Creates a writable atom for an `Effect` or `Stream` function; writing an argument starts the computation and exposes its state as an `AsyncResult`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(): (fn: (arg: Arg, get: FnContext) => Effect.Effect, options?: {
readonly initialValue?: A | undefined;
readonly concurrent?: boolean | undefined;
}) => AtomResultFn;
/**
* Creates a writable atom for an `Effect` or `Stream` function; writing an argument starts the computation and exposes its state as an `AsyncResult`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(fn: (arg: Arg, get: FnContext) => Effect.Effect, options?: {
readonly initialValue?: A | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
/**
* Creates a writable atom for an `Effect` or `Stream` function; writing an argument starts the computation and exposes its state as an `AsyncResult`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(): (fn: (arg: Arg, get: FnContext) => Stream.Stream, options?: {
readonly initialValue?: A | undefined;
readonly concurrent?: boolean | undefined;
}) => AtomResultFn;
/**
* Creates a writable atom for an `Effect` or `Stream` function; writing an argument starts the computation and exposes its state as an `AsyncResult`.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
(fn: (arg: Arg, get: FnContext) => Stream.Stream, options?: {
readonly initialValue?: A | undefined;
readonly concurrent?: boolean | undefined;
}): AtomResultFn;
};
/**
* `AsyncResult` produced by `pull`, containing a non-empty batch of pulled items and a `done` flag, or `NoSuchElementError` when the stream completes without items.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export type PullResult = AsyncResult.AsyncResult<{
readonly done: boolean;
readonly items: Arr.NonEmptyArray;
}, E | Cause.NoSuchElementError>;
/**
* Creates a writable atom that pulls an initial chunk from a stream and then pulls the next chunk whenever it is written to, accumulating items unless `disableAccumulation` is enabled.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const pull: (create: ((get: AtomContext) => Stream.Stream) | Stream.Stream, options?: {
readonly disableAccumulation?: boolean | undefined;
}) => Writable, void>;
/**
* Creates a memoized atom factory that returns the same object for the same argument, using weak references for cached values when the platform supports them.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const family: (f: (arg: Arg) => T) => (arg: Arg) => T;
/**
* Uses a fallback `AsyncResult` atom while the primary atom is `Initial`, marking the fallback result as waiting until the primary atom produces a non-initial result.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const withFallback: {
/**
* Uses a fallback `AsyncResult` atom while the primary atom is `Initial`, marking the fallback result as waiting until the primary atom produces a non-initial result.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(fallback: Atom>): >>(self: R) => [R] extends [Writable] ? Writable> | A2, AsyncResult.AsyncResult.Failure> | E2>, RW> : Atom> | A2, AsyncResult.AsyncResult.Failure> | E2>>;
/**
* Uses a fallback `AsyncResult` atom while the primary atom is `Initial`, marking the fallback result as waiting until the primary atom produces a non-initial result.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>, A2, E2>(self: R, fallback: Atom>): [R] extends [Writable] ? Writable> | A2, AsyncResult.AsyncResult.Failure> | E2>, RW> : Atom> | A2, AsyncResult.AsyncResult.Failure> | E2>>;
};
/**
* Returns a copy of an atom that remains cached and mounted even when no subscribers are using it.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const keepAlive: >(self: A) => A;
/**
* Allows a reactive value to be disposed of when it is not in use.
*
* **Details**
*
* Atoms have this behavior by default, so use this to undo `keepAlive` on a copied atom.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const autoDispose: >(self: A) => A;
/**
* Sets whether an atom should be lazy.
*
* **Details**
*
* Lazy atoms defer recomputation while they have no active listeners or active
* non-lazy dependents, rebuilding the next time their value is observed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const setLazy: {
/**
* Sets whether an atom should be lazy.
*
* **Details**
*
* Lazy atoms defer recomputation while they have no active listeners or active
* non-lazy dependents, rebuilding the next time their value is observed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(lazy: boolean): >(self: A) => A;
/**
* Sets whether an atom should be lazy.
*
* **Details**
*
* Lazy atoms defer recomputation while they have no active listeners or active
* non-lazy dependents, rebuilding the next time their value is observed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: A, lazy: boolean): A;
};
/**
* Returns a copy of an atom that uses a custom equality function to detect
* value changes.
*
* **Details**
*
* When an atom's value is rebuilt or written, the registry compares the new
* value against the current one to decide whether dependents and listeners
* should be notified. By default the comparison uses `Object.is`, so a
* structurally equal but referentially distinct value still triggers
* notifications. Providing an equality function lets the atom skip updates
* when the new value is equal to the current one.
*
* **Example** (Comparing values structurally)
*
* ```ts import.meta.vitest
* import { Atom } from "effect/reactivity"
*
* const point = Atom.make({ x: 0, y: 0 }).pipe(
* Atom.withEquality<{ x: number; y: number }>((a, b) => a.x === b.x && a.y === b.y)
* )
* point.equals({ x: 1, y: 2 }, { x: 1, y: 2 }) // => true
* ```
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const withEquality: {
/**
* Returns a copy of an atom that uses a custom equality function to detect
* value changes.
*
* **Details**
*
* When an atom's value is rebuilt or written, the registry compares the new
* value against the current one to decide whether dependents and listeners
* should be notified. By default the comparison uses `Object.is`, so a
* structurally equal but referentially distinct value still triggers
* notifications. Providing an equality function lets the atom skip updates
* when the new value is equal to the current one.
*
* **Example** (Comparing values structurally)
*
* ```ts import.meta.vitest
* import { Atom } from "effect/reactivity"
*
* const point = Atom.make({ x: 0, y: 0 }).pipe(
* Atom.withEquality<{ x: number; y: number }>((a, b) => a.x === b.x && a.y === b.y)
* )
* point.equals({ x: 1, y: 2 }, { x: 1, y: 2 }) // => true
* ```
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(equals: (value: A, next: A) => boolean): >(self: T) => T;
/**
* Returns a copy of an atom that uses a custom equality function to detect
* value changes.
*
* **Details**
*
* When an atom's value is rebuilt or written, the registry compares the new
* value against the current one to decide whether dependents and listeners
* should be notified. By default the comparison uses `Object.is`, so a
* structurally equal but referentially distinct value still triggers
* notifications. Providing an equality function lets the atom skip updates
* when the new value is equal to the current one.
*
* **Example** (Comparing values structurally)
*
* ```ts import.meta.vitest
* import { Atom } from "effect/reactivity"
*
* const point = Atom.make({ x: 0, y: 0 }).pipe(
* Atom.withEquality<{ x: number; y: number }>((a, b) => a.x === b.x && a.y === b.y)
* )
* point.equals({ x: 1, y: 2 }, { x: 1, y: 2 }) // => true
* ```
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: T, equals: (value: Type, next: Type) => boolean): T;
};
/**
* Attaches a diagnostic label to an atom.
*
* **Details**
*
* The label is used for inspection and debugging metadata and does not change the
* atom's read or write behavior.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const withLabel: {
/**
* Attaches a diagnostic label to an atom.
*
* **Details**
*
* The label is used for inspection and debugging metadata and does not change the
* atom's read or write behavior.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(name: string): >(self: A) => A;
/**
* Attaches a diagnostic label to an atom.
*
* **Details**
*
* The label is used for inspection and debugging metadata and does not change the
* atom's read or write behavior.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: A, name: string): A;
};
/**
* Options for seeding an effect or stream atom through registry initial values
* or hydration.
*
* **Details**
*
* By default a seeded effect or stream atom still runs its effect on mount,
* because the dependencies read inside the effect are only known once it has
* run. With `skipInitialRun`, the atom keeps the seeded value until it is
* refreshed or one of its dependencies changes. The factory and any wrappers
* still build, so `get(...)` calls in the factory and `withReactivity` keys are
* tracked; only the first effect or stream run is skipped. Dependencies read
* inside the effect are tracked from its first real run. An `Initial` seed
* never skips the effect.
*
* @stability unstable
* @category models
* @since 4.1.0
*/
export interface InitialValueOptions {
readonly skipInitialRun?: boolean | undefined;
}
/**
* Pairs an atom with an initial value for registry initialization.
*
* **When to use**
*
* Use to preload an atom value when constructing or seeding a registry.
*
* **Details**
*
* The returned tuple can be supplied to `AtomRegistry` initial values so the atom
* starts with the provided value before it is first rebuilt. Pass
* `{ skipInitialRun: true }` to keep the value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const initialValue: {
/**
* Pairs an atom with an initial value for registry initialization.
*
* **When to use**
*
* Use to preload an atom value when constructing or seeding a registry.
*
* **Details**
*
* The returned tuple can be supplied to `AtomRegistry` initial values so the atom
* starts with the provided value before it is first rebuilt. Pass
* `{ skipInitialRun: true }` to keep the value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(initialValue: A): (self: Atom) => readonly [Atom, A];
/**
* Pairs an atom with an initial value for registry initialization.
*
* **When to use**
*
* Use to preload an atom value when constructing or seeding a registry.
*
* **Details**
*
* The returned tuple can be supplied to `AtomRegistry` initial values so the atom
* starts with the provided value before it is first rebuilt. Pass
* `{ skipInitialRun: true }` to keep the value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(self: Atom, initialValue: A): readonly [Atom, A];
/**
* Pairs an atom with an initial value for registry initialization.
*
* **When to use**
*
* Use to preload an atom value when constructing or seeding a registry.
*
* **Details**
*
* The returned tuple can be supplied to `AtomRegistry` initial values so the atom
* starts with the provided value before it is first rebuilt. Pass
* `{ skipInitialRun: true }` to keep the value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(self: Atom, initialValue: A, options: InitialValueOptions): readonly [Atom, A, InitialValueOptions];
};
/**
* Creates a derived atom by reading another atom with a custom `AtomContext`
* function.
*
* **Details**
*
* If the source is writable, the derived atom keeps the source write input and
* forwards writes to the source. `initialValueTarget` controls which atom receives
* preloaded initial values for the derived atom.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const transform: {
/**
* Creates a derived atom by reading another atom with a custom `AtomContext`
* function.
*
* **Details**
*
* If the source is writable, the derived atom keeps the source write input and
* forwards writes to the source. `initialValueTarget` controls which atom receives
* preloaded initial values for the derived atom.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, B>(f: (get: AtomContext, atom: R) => B, options?: {
readonly initialValueTarget?: Atom | undefined;
}): (self: R) => [R] extends [Writable] ? Writable : Atom;
/**
* Creates a derived atom by reading another atom with a custom `AtomContext`
* function.
*
* **Details**
*
* If the source is writable, the derived atom keeps the source write input and
* forwards writes to the source. `initialValueTarget` controls which atom receives
* preloaded initial values for the derived atom.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, B>(self: R, f: (get: AtomContext, atom: R) => B, options?: {
readonly initialValueTarget?: Atom | undefined;
}): [R] extends [Writable] ? Writable : Atom;
};
/**
* Maps the current value of an atom with a pure function.
*
* **Details**
*
* When the source atom is writable, the returned atom remains writable and keeps
* the source atom's write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const map: {
/**
* Maps the current value of an atom with a pure function.
*
* **Details**
*
* When the source atom is writable, the returned atom remains writable and keeps
* the source atom's write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, B>(f: (_: Type) => B): (self: R) => [R] extends [Writable] ? Writable : Atom;
/**
* Maps the current value of an atom with a pure function.
*
* **Details**
*
* When the source atom is writable, the returned atom remains writable and keeps
* the source atom's write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, B>(self: R, f: (_: Type) => B): [R] extends [Writable] ? Writable : Atom;
};
/**
* Maps the successful value inside an `AsyncResult` atom.
*
* **Details**
*
* Initial and failure states are preserved, and writable source atoms keep their
* original write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const mapResult: {
/**
* Maps the successful value inside an `AsyncResult` atom.
*
* **Details**
*
* Initial and failure states are preserved, and writable source atoms keep their
* original write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>, B>(f: (_: AsyncResult.AsyncResult.Success>) => B): (self: R) => [R] extends [Writable] ? Writable>>, RW> : Atom>>>;
/**
* Maps the successful value inside an `AsyncResult` atom.
*
* **Details**
*
* Initial and failure states are preserved, and writable source atoms keep their
* original write input type.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>, B>(self: R, f: (_: AsyncResult.AsyncResult.Success>) => B): [R] extends [Writable] ? Writable>>, RW> : Atom>>>;
};
/**
* Creates an atom that publishes source changes only after the source has stopped
* changing for the specified duration.
*
* **Details**
*
* The current source value is used immediately, and any pending debounce timer is
* cleared when the derived atom is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const debounce: {
/**
* Creates an atom that publishes source changes only after the source has stopped
* changing for the specified duration.
*
* **Details**
*
* The current source value is used immediately, and any pending debounce timer is
* cleared when the derived atom is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(duration: Duration.Input): >(self: A) => WithoutSerializable;
/**
* Creates an atom that publishes source changes only after the source has stopped
* changing for the specified duration.
*
* **Details**
*
* The current source value is used immediately, and any pending debounce timer is
* cleared when the derived atom is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: A, duration: Duration.Input): WithoutSerializable;
};
/**
* Creates a derived atom that reads the source and schedules a refresh after the
* specified duration.
*
* **Details**
*
* The scheduled refresh is canceled when the derived atom's lifetime is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const withRefresh: {
/**
* Creates a derived atom that reads the source and schedules a refresh after the
* specified duration.
*
* **Details**
*
* The scheduled refresh is canceled when the derived atom's lifetime is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(duration: Duration.Input): >(self: A) => WithoutSerializable;
/**
* Creates a derived atom that reads the source and schedules a refresh after the
* specified duration.
*
* **Details**
*
* The scheduled refresh is canceled when the derived atom's lifetime is disposed.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>(self: A, duration: Duration.Input): WithoutSerializable;
};
/**
* Adds stale-while-revalidate refresh behavior to an async result atom.
*
* **Details**
*
* Returns the current result and defers stale-source revalidation until after the read.
* Skips revalidation if the source becomes fresh or the atom is disposed.
* Manual refreshes still forward to the source. `revalidateOnMount` controls
* initial stale refreshes; `revalidateOnFocus` controls focus refreshes
* (`true` respects `staleTime`, `"always"` forces refresh).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const swr: {
/**
* Adds stale-while-revalidate refresh behavior to an async result atom.
*
* **Details**
*
* Returns the current result and defers stale-source revalidation until after the read.
* Skips revalidation if the source becomes fresh or the atom is disposed.
* Manual refreshes still forward to the source. `revalidateOnMount` controls
* initial stale refreshes; `revalidateOnFocus` controls focus refreshes
* (`true` respects `staleTime`, `"always"` forces refresh).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(options: {
readonly staleTime: Duration.Input;
readonly revalidateOnMount?: boolean | undefined;
readonly revalidateOnFocus?: boolean | "always" | undefined;
readonly focusSignal?: Atom | undefined;
}): >>(self: R) => WithoutSerializable;
/**
* Adds stale-while-revalidate refresh behavior to an async result atom.
*
* **Details**
*
* Returns the current result and defers stale-source revalidation until after the read.
* Skips revalidation if the source becomes fresh or the atom is disposed.
* Manual refreshes still forward to the source. `revalidateOnMount` controls
* initial stale refreshes; `revalidateOnFocus` controls focus refreshes
* (`true` respects `staleTime`, `"always"` forces refresh).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
>>(self: R, options: {
readonly staleTime: Duration.Input;
readonly revalidateOnMount?: boolean | undefined;
readonly revalidateOnFocus?: boolean | "always" | undefined;
readonly focusSignal?: Atom | undefined;
}): WithoutSerializable;
};
/**
* Wraps an atom in a writable optimistic atom.
*
* **Details**
*
* Writes accept transition atoms containing `AsyncResult` values. Waiting
* successes are shown optimistically while transitions run; when successful
* transitions finish, the source atom is refreshed, and failures roll the value
* back to the latest source value.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const optimistic: (self: Atom) => Writable>>;
/**
* Creates an `AtomResultFn` that applies an optimistic update before running the
* underlying mutation.
*
* **Details**
*
* The reducer computes the provisional value from the current value and mutation
* input. The wrapped function result then completes the transition or updates the
* optimistic value through the provided setter callback.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const optimisticFn: {
/**
* Creates an `AtomResultFn` that applies an optimistic update before running the
* underlying mutation.
*
* **Details**
*
* The reducer computes the provisional value from the current value and mutation
* input. The wrapped function result then completes the transition or updates the
* optimistic value through the provided setter callback.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(options: {
readonly reducer: (current: NoInfer, update: OW) => NoInfer;
readonly fn: AtomResultFn | ((set: (result: NoInfer) => void) => AtomResultFn);
}): (self: Writable>>) => AtomResultFn;
/**
* Creates an `AtomResultFn` that applies an optimistic update before running the
* underlying mutation.
*
* **Details**
*
* The reducer computes the provisional value from the current value and mutation
* input. The wrapped function result then completes the transition or updates the
* optimistic value through the provided setter callback.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
(self: Writable>>, options: {
readonly reducer: (current: NoInfer, update: OW) => NoInfer;
readonly fn: AtomResultFn | ((set: (result: NoInfer) => void) => AtomResultFn);
}): AtomResultFn;
};
/**
* Runs synchronous atom updates as a batch.
*
* **Details**
*
* Stale nodes are rebuilt and listeners are notified after the callback completes,
* so dependent updates observe the final batched state.
*
* @stability unstable
* @category batching
* @since 4.0.0
*/
export declare const batch: (f: () => void) => void;
/**
* Creates a signal atom that increments when the document becomes visible.
*
* **Details**
*
* It listens for `visibilitychange` events on `window` and removes the listener
* when the atom is disposed. Without `window`, it stays at `0` and adds no listener.
*
* @stability unstable
* @category constants
* @since 4.0.0
*/
export declare const windowFocusSignal: Atom;
/**
* Creates a combinator that refreshes an atom whenever the supplied signal atom
* changes.
*
* **Details**
*
* The derived atom also subscribes to the source atom so normal source updates are
* forwarded to its own value.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const makeRefreshOnSignal: <_>(signal: Atom<_>) => >(self: A) => WithoutSerializable;
/**
* Refreshes an atom whenever `windowFocusSignal` changes.
*
* **Details**
*
* Without `window`, this helper does not trigger refreshes. Source atom updates
* are still forwarded.
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const refreshOnWindowFocus: >(self: A) => WithoutSerializable;
/**
* Creates a writable atom backed by a `KeyValueStore` entry.
*
* **Details**
*
* Values are encoded and decoded with the supplied schema. In sync mode the atom
* exposes the decoded value and writes the default value when the key is missing;
* in async mode it exposes an `AsyncResult` of the decoded value.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const kvs: , const Mode extends "sync" | "async" = never>(options: {
readonly runtime: AtomRuntime;
readonly key: string;
readonly schema: S;
readonly defaultValue: LazyArg;
readonly mode?: Mode | undefined;
}) => Writable<"async" extends Mode ? AsyncResult.AsyncResult : S["Type"], S["Type"]>;
/**
* Creates an atom that reads and writes a URL search parameter.
*
* **Gotchas**
*
* If you pass a schema, it has to be synchronous and have no context.
*
* @stability unstable
* @category constructors
* @since 4.0.0
*/
export declare const searchParam: = never>(name: string, options?: {
readonly schema?: S | undefined;
}) => Writable<[S] extends [never] ? string : Option.Option>;
/**
* Converts an atom into a stream using the `AtomRegistry` service.
*
* **Details**
*
* The stream emits the atom's current value immediately and then emits subsequent
* changes until the stream scope is closed.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const toStream: (self: Atom) => Stream.Stream;
/**
* Converts an `AsyncResult` atom into a stream using the `AtomRegistry` service.
*
* **Details**
*
* Initial results are skipped, successes are emitted as stream values, and
* failures fail the stream with the result cause.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const toStreamResult: (self: Atom>) => Stream.Stream;
/**
* Reads an atom's current value from the `AtomRegistry` service.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const get: (self: Atom) => Effect.Effect;
/**
* Reads a writable atom, computes a return value and next write value, writes the
* next value, and returns the computed result.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const modify: {
/**
* Reads a writable atom, computes a return value and next write value, writes the
* next value, and returns the computed result.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(f: (_: R) => [returnValue: A, nextValue: W]): (self: Writable) => Effect.Effect;
/**
* Reads a writable atom, computes a return value and next write value, writes the
* next value, and returns the computed result.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(self: Writable, f: (_: R) => [returnValue: A, nextValue: W]): Effect.Effect;
};
/**
* Writes a value to a writable atom through the `AtomRegistry` service.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const set: {
/**
* Writes a value to a writable atom through the `AtomRegistry` service.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(value: W): (self: Writable) => Effect.Effect;
/**
* Writes a value to a writable atom through the `AtomRegistry` service.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(self: Writable, value: W): Effect.Effect;
};
/**
* Updates a writable atom by reading its current value from the registry and
* writing the value returned by the update function.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const update: {
/**
* Updates a writable atom by reading its current value from the registry and
* writing the value returned by the update function.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(f: (_: R) => W): (self: Writable) => Effect.Effect;
/**
* Updates a writable atom by reading its current value from the registry and
* writing the value returned by the update function.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
(self: Writable, f: (_: R) => W): Effect.Effect;
};
/**
* Reads an `AsyncResult` atom as an effect through the `AtomRegistry` service.
*
* **Details**
*
* The effect waits while the result is `Initial`, and also while it is waiting
* when `suspendOnWaiting` is enabled. Successes succeed with the value and
* failures fail with the result cause.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const getResult: (self: Atom>, options?: {
readonly suspendOnWaiting?: boolean | undefined;
}) => Effect.Effect;
/**
* Runs a refresh request for an atom through the `AtomRegistry` service.
*
* **When to use**
*
* Use to invalidate and recompute an atom from an Effect that has access to the
* active registry.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const refresh: (self: Atom) => Effect.Effect;
/**
* Mounts an atom in the `AtomRegistry` for the lifetime of the current scope.
*
* **Details**
*
* Mounting keeps the atom subscribed with a no-op listener until the scope
* finalizer releases it.
*
* @stability unstable
* @category converting
* @since 4.0.0
*/
export declare const mount: (self: Atom) => Effect.Effect;
/**
* The type id used to mark atoms that carry serialization metadata.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export declare const SerializableTypeId: SerializableTypeId;
/**
* The literal type of the serializable atom marker.
*
* @stability unstable
* @category type IDs
* @since 4.0.0
*/
export type SerializableTypeId = "~effect-atom/atom/Atom/Serializable";
/**
* Serialization metadata attached to an atom.
*
* **Details**
*
* The key identifies the atom in dehydrated state, and the encode/decode
* functions convert between the atom value and its JSON encoding.
*
* @stability unstable
* @category models
* @since 4.0.0
*/
export interface Serializable {
readonly [SerializableTypeId]: {
readonly key: string;
readonly encode: (value: S["Type"]) => Schema.Json;
readonly decode: (value: Schema.Json) => S["Type"];
readonly skipInitialRun?: boolean | undefined;
};
}
/**
* Returns `true` when an atom carries `Serializable` metadata.
*
* @stability unstable
* @category guards
* @since 4.0.0
*/
export declare const isSerializable: (self: Atom) => self is Atom & Serializable;
/**
* Attaches serialization metadata to an atom using a schema and stable key.
*
* **Details**
*
* The schema is converted to a JSON codec for synchronous encode/decode, and the
* key is also used as the atom label when the atom does not already have one.
* Set `skipInitialRun` to keep a hydrated value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
export declare const serializable: {
/**
* Attaches serialization metadata to an atom using a schema and stable key.
*
* **Details**
*
* The schema is converted to a JSON codec for synchronous encode/decode, and the
* key is also used as the atom label when the atom does not already have one.
* Set `skipInitialRun` to keep a hydrated value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, S extends Schema.ConstraintCodec, any>>(options: {
readonly key: string;
readonly schema: S;
} & InitialValueOptions): (self: R) => R & Serializable;
/**
* Attaches serialization metadata to an atom using a schema and stable key.
*
* **Details**
*
* The schema is converted to a JSON codec for synchronous encode/decode, and the
* key is also used as the atom label when the atom does not already have one.
* Set `skipInitialRun` to keep a hydrated value of an effect or stream atom
* instead of running its effect on mount (see {@link InitialValueOptions}).
*
* @stability unstable
* @category combinators
* @since 4.0.0
*/
, S extends Schema.ConstraintCodec