/** * 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, any>>(self: R, options: { readonly key: string; readonly schema: S; } & InitialValueOptions): R & Serializable; }; /** * The type id used to mark atoms with a server-side read override. * * @stability unstable * @category type IDs * @since 4.0.0 */ export declare const ServerValueTypeId: "~effect-atom/atom/Atom/ServerValue"; /** * Sets the value of an Atom when read on the server. * * @stability unstable * @category transforming * @since 4.0.0 */ export declare const withServerValue: { /** * Sets the value of an Atom when read on the server. * * @stability unstable * @category transforming * @since 4.0.0 */ >(read: (get: (atom: Atom) => A) => Type): (self: A) => A; /** * Sets the value of an Atom when read on the server. * * @stability unstable * @category transforming * @since 4.0.0 */ >(self: A, read: (get: (atom: Atom) => A) => Type): A; }; /** * Sets an `AsyncResult` atom's server-side value to * `AsyncResult.initial(true)`. * * @stability unstable * @category transforming * @since 4.0.0 */ export declare const withServerValueInitial: >>(self: A) => A; /** * Reads an atom from a registry, using its server-side read override when one is * present. * * **Details** * * Nested reads performed by the override are resolved against the same registry. * * @stability unstable * @category getters * @since 4.0.0 */ export declare const getServerValue: { /** * Reads an atom from a registry, using its server-side read override when one is * present. * * **Details** * * Nested reads performed by the override are resolved against the same registry. * * @stability unstable * @category getters * @since 4.0.0 */ (registry: Registry.AtomRegistry): (self: Atom) => A; /** * Reads an atom from a registry, using its server-side read override when one is * present. * * **Details** * * Nested reads performed by the override are resolved against the same registry. * * @stability unstable * @category getters * @since 4.0.0 */ (self: Atom, registry: Registry.AtomRegistry): A; }; //# sourceMappingURL=Atom.d.ts.map