/** * TypeScript type representation of the standard `setTimeout` function. * * This type is isolated in a separate file to avoid referencing the global * `setTimeout` directly in the main bundle, which would automatically add a * Node.js reference (`/// `) to the bundle. * * @remarks * The separation is necessary because using `typeof setTimeout` in the same * file where `setTimeout` is referenced as a variable in the module scope * would cause TypeScript to add Node.js type references, potentially creating * issues in non-Node environments. * @example * // How to use this type * import { SetTimeout } from '@reatom/core' * * function setupTimer(customTimeout: SetTimeout) { * return customTimeout(() => console.log('Timer fired'), 1000) * } * * @public * @see {@link https://github.com/reatom/reatom/issues/983} for the original issue and discussion */import { StandardSchemaV1 } from "@standard-schema/spec"; //#region src/setTimeout.d.ts type SetTimeout = typeof setTimeout; //#endregion //#region src/utils.d.ts /** * Generic function type representing any function that takes any parameters and * returns any value. Used throughout Reatom for typing function parameters and * callbacks. */ interface Fn { (...params: any[]): any; } /** * Type alias for Record for brevity. Represents an object with * string keys and values of type T. * * @template T - The type of values in the record (defaults to any) */ type Rec = Record; /** * Function interface for unsubscribing from subscriptions. Used consistently * throughout Reatom for cleanup functions. */ interface Unsubscribe { (): void; } /** * Type representing different possible return values from observable * subscription methods. Supports both function-based unsubscribers and objects * with unsubscribe methods. */ type MaybeUnsubscribe = void | Exclude<{}, Fn> | Unsubscribe | { unsubscribe: Unsubscribe; }; /** * Utility type that converts properties with undefined values to optional * properties. Makes properties with object or null values required, while * making other properties optional. * * @template T - The object type to transform */ type UndefinedToOptional = Partial & PickValues; /** * Union type of all JavaScript falsy values except for NaN. Includes: false, 0, * empty string, null, and undefined. * * @see https://stackoverflow.com/a/51390763 */ type Falsy = false | 0 | '' | null | undefined; /** * Removes named generics to produce a plain type representation. Preserves * function signatures and object structure while eliminating generic parameter * names. * * This is useful for presenting cleaner types in documentation and error * messages. * * @template Intersection - The type to convert to a plain representation */ type Plain = Intersection extends ((...params: infer I) => infer O) ? ((...params: I) => O) & { [Key in keyof Intersection]: Intersection[Key] } : Intersection extends (new (...params: any[]) => any) ? Intersection : Intersection extends object ? { [Key in keyof Intersection]: Intersection[Key] } : Intersection; /** * Creates a shallow clone type of T. Useful for creating a new type that has * the same shape but is a distinct type. * * @template T - The type to create a shallow clone of */ type Shallow = { [K in keyof T]: T[K] } & {}; /** * Represents a constructor function that can be instantiated with the new * operator. * * @template ReturnType - The type of object that will be created when * instantiated */ interface Newable { new (...params: any[]): ReturnType; } /** * Extracts the union type of all values in an object type. * * @template T - The object type to extract values from */ type Values = T[keyof T]; /** * Extracts keys from type T where the corresponding value does not extend type * V. * * @template T - The object type to extract keys from * @template V - The value type to exclude */ type OmitValuesKeys = Values<{ [K in keyof T]: T[K] extends V ? never : K }>; /** * Creates a type with all properties from T except those with values extending * V. * * @template T - The object type to filter properties from * @template V - The value type to exclude */ type OmitValues = { [K in OmitValuesKeys]: T[K] }; /** * Extracts keys from type T where the corresponding value extends type V. * * @template T - The object type to extract keys from * @template V - The value type to include */ type PickValuesKeys = Values<{ [K in keyof T]: T[K] extends V ? K : never }>; /** * Creates a type with only properties from T with values extending V. * * @template T - The object type to filter properties from * @template V - The value type to include */ type PickValues = { [K in PickValuesKeys]: T[K] }; /** * Flattens a function type with up to 5 overloads into a single function * signature. This creates a union of the parameter types and return types. * * Useful for generic type handling of overloaded functions. * * @template T - The overloaded function type to flatten */ type Overloads = T extends { (...params: infer Overload1Params): infer Return1; (...params: infer Overload2Params): infer Return2; (...params: infer Overload3Params): infer Return3; (...params: infer Overload4Params): infer Return4; (...params: infer Overload5Params): infer Return5; } ? (...params: Overload1Params | Overload2Params | Overload3Params | Overload4Params | Overload5Params) => Return1 | Return2 | Return3 | Return4 | Return5 : never; /** * Extracts the parameters type from an overloaded function. Returns a union of * all possible parameter tuples. * * @template T - The overloaded function type to extract parameters from */ type OverloadParameters = Parameters>; /** * Asserts that a value is truthy, throwing an error if it's falsy. This is a * TypeScript type assertion function that helps with type narrowing. * * @param value - The value to check * @param message - The error message to use if the assertion fails * @param ErrorConstructor - Optional custom error constructor to use (defaults * to Error) * @throws {Error} Throws an error with the provided message if value is falsy */ declare function assert(value: unknown, message: string, ErrorConstructor?: Newable): asserts value; /** * No-operation function that accepts any parameters and returns undefined. * Useful as a default callback or for stubbing functionality. */ declare const noop: (...params: any[]) => any; /** * Identity function that returns the first argument unchanged. Can accept * additional parameters but ignores them. * * @template T - The type of value being passed through * @param value - The value to return * @returns The same value that was passed in */ declare const identity: (value: T, ...a: any[]) => T; /** * Creates a promise that resolves after the specified number of milliseconds. * Useful for creating delays in async functions. * * @param ms - The number of milliseconds to sleep (defaults to 0) * @returns A promise that resolves after the specified delay */ declare const sleep: (ms?: number) => Promise; /** * Type guard that checks if a value is an object (non-null and typeof * 'object'). Provides advanced type narrowing to either the original object * type or a generic object type. * * @template T - The type of value being checked * @param thing - The value to check * @returns True if the value is a non-null object, false otherwise */ declare const isObject: (thing: T) => thing is T extends Record ? T : Record; /** * Type guard that checks if a value is a plain object (a simple object literal * or created with Object.create(null)). Verifies that the object either has no * prototype or its prototype is Object.prototype. * * @param thing - The value to check * @returns True if the value is a plain object, false otherwise */ declare const isRec: (thing: unknown) => thing is Record; /** * Performs a shallow equality comparison between two values. Handles * primitives, objects, dates, regular expressions, arrays, maps, and sets. * * For iterables, compares each item in sequence for equality. For objects, * compares direct property values but not nested objects deeply. * * @param a - First value to compare * @param b - Second value to compare * @param is - Optional comparison function to use for individual values * (defaults to Object.is) * @returns True if the values are shallowly equal, false otherwise */ declare const isShallowEqual: (a: any, b: any, is?: (value1: any, value2: any) => boolean) => any; /** * Performs a deep equality comparison between two values. Recursively compares * nested objects and arrays while properly handling cyclic references. * * Handles primitives, objects, dates, regular expressions, arrays, maps, and * sets. Uses a WeakMap to track visited objects to avoid infinite recursion * with circular references. * * @param a - First value to compare * @param b - Second value to compare * @returns True if the values are deeply equal, false otherwise */ declare const isDeepEqual: (a: any, b: any) => any; /** * Type utility for merging up to four types with proper type safety. Properties * from later types override properties from earlier types. Preserves function * signatures from T1 if it's a function type. * * @template T1 - First type to merge * @template T2 - Second type to merge, overrides T1 properties * @template T3 - Optional third type to merge, overrides T1 and T2 properties * @template T4 - Optional fourth type to merge, overrides T1, T2, and T3 * properties */ type Assign = Plain<(T1 extends ((...params: infer I) => infer O) ? (...params: I) => O : {}) & Omit & Omit & Omit & T4>; /** * Type-safe version of Object.assign that properly handles type merging. Unlike * standard Object.assign typing, properties with the same name are replaced * rather than becoming a union type. * * @template T1 - Type of the target object * @template T2 - Type of the first source object * @template T3 - Type of the optional second source object * @template T4 - Type of the optional third source object * @returns A new object with merged properties */ declare const assign: { (a1: T1, a2: T2): Assign; (a1: T1, a2: T2, a3?: T3): Assign; (a1: T1, a2: T2, a3?: T3, a4?: T4): Assign; }; /** * Creates a new object with merged properties from all provided objects. * Similar to Object.assign but always creates a new object rather than mutating * the first argument. * * @example * // Creates a new object: { a: 1, b: 2, c: 3 } * const obj = merge({ a: 1 }, { b: 2 }, { c: 3 }) * * @returns A new object with all properties from the provided objects */ declare const merge: typeof assign; /** * Type-safe version of Object.keys that preserves the key type information. * Returns an array of keys with the correct type for the object. * * @template T - The object type * @param thing - The object to get keys from * @returns An array of the object's keys with proper typing */ declare const keys: { (thing: T): Array; }; /** * Type-safe version of Object.entries that preserves key and value type * information. Returns an array of key-value pairs with correct types. * * @template T - The object type * @param thing - The object to get entries from * @returns An array of [key, value] pairs with proper typing */ declare const entries: { (thing: T): Array<[keyof T, T[keyof T]]>; }; /** * Type-safe version of Object.fromEntries that preserves key and value type * information. Creates an object from an iterable of key-value pairs. * * @template K - The key type * @template V - The value type * @param entries - An iterable of [key, value] pairs * @returns An object with the specified keys and values */ declare const fromEntries: { (entries: Iterable): Record; }; /** * Creates a new object with only the specified keys from the original object. * * @example * const user = { id: 1, name: 'Alice', email: 'alice@example.com' } * const userInfo = pick(user, ['name', 'email']) * // Result: { name: 'Alice', email: 'alice@example.com' } * * @template T - The source object type * @template K - The keys to pick from the object * @param target - The source object * @param keys - Array of keys to include in the result * @returns A new object containing only the specified keys and their values */ declare const pick: (target: T, keys: Array) => Plain>; /** * Creates a new object excluding the specified keys from the original object. * * @example * const user = { id: 1, name: 'Alice', password: 'secret' } * const safeUser = omit(user, ['password']) * // Result: { id: 1, name: 'Alice' } * * @template T - The source object type * @template K - The keys to omit from the object * @param target - The source object * @param keys - Array of keys to exclude from the result * @returns A new object containing all keys except the specified ones */ declare const omit: (target: T, keys: Array) => Plain>; /** * Creates a deep clone of a value using JSON serialization/deserialization. * This is a type-safe shortcut to `JSON.parse(JSON.stringify(value))`. * * Note: This has limitations with circular references, functions, symbols, and * special objects like Date (converts to string). Consider using the native * structuredClone when available. * * @template T - The type of value being cloned * @param value - The value to clone * @returns A deep clone of the input value * @see https://developer.mozilla.org/en-US/docs/Web/API/structuredClone */ declare const jsonClone: (value: T) => T; /** * Generates a random integer between min and max (inclusive). * * @param min - The minimum integer value (defaults to 0) * @param max - The maximum integer value (defaults to Number.MAX_SAFE_INTEGER - * 1) * @returns A random integer between min and max */ declare const random: (min?: number, max?: number) => number; /** * Replaces the default random number generator with a custom implementation. * Useful for testing to provide deterministic "random" values. * * @example * // Set up deterministic random values for testing * const restore = mockRandom(() => 42) * console.log(random()) // Always returns 42 * restore() // Back to normal random behavior * * @param fn - The custom random function to use * @returns A restore function that reverts to the original random * implementation when called */ declare const mockRandom: (fn: typeof random) => () => void; /** * Asserts that a value is not null or undefined. Throws a TypeError if the * value is null or undefined. Also serves as a type guard to narrow the type to * non-nullable. * * @example * const name = nonNullable(user.name) // TypeScript knows name is not null or undefined * * @template T - The type of value to check * @param value - The value to check * @param message - Optional custom error message * @returns The input value if it's not null or undefined * @throws {TypeError} If the value is null or undefined */ declare const nonNullable: (value: T, message?: string) => NonNullable; /** * Converts any JavaScript value to a stable string representation. Handles * complex data structures and edge cases that JSON.stringify cannot manage. * * Provides special handling for: * * - Circular references * - Maps and Sets * - Symbols * - Functions * - Custom class instances * - Regular objects (with sorted keys for stability) * * @example * // Handles circular references * const obj = { name: 'test' } * obj.self = obj * const key = toStringKey(obj) // No infinite recursion! * * // Stable representation of objects (key order doesn't matter) * toStringKey({ a: 1, b: 2 }) === toStringKey({ b: 2, a: 1 }) // true * * @param thing - The value to convert to a string * @param immutable - Whether to memoize results for complex objects (defaults * to true) * @returns A string representation of the value */ declare const toStringKey: (thing: any, immutable?: boolean) => string; /** * Interface extending DOMException for abort-specific error handling. Used to * represent errors triggered by AbortController signal aborts. * * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortController */ interface AbortError extends DOMException { name: 'AbortError'; } /** * Converts any value to an AbortError. If the value is already an AbortError, * it will be returned as is. Otherwise, creates a new AbortError with * appropriate information. * * Handles different environments by using DOMException when available or * falling back to regular Error with name set to 'AbortError'. * * @param reason - The value to convert to an AbortError * @returns An AbortError instance */ declare const toAbortError: (reason: any) => AbortError; /** * Checks if an AbortController is aborted and throws an AbortError if it is. * Useful for quick abort checks at the beginning of async operations. * * @param controller - The AbortController to check (can be undefined, null or * void) * @throws {AbortError} If the controller's signal is aborted */ declare const throwIfAborted: (controller?: void | AbortController | null | undefined) => void; /** * Type guard that checks if a value is an AbortError. * * @param thing - The value to check * @returns True if the value is an AbortError, false otherwise */ declare const isAbort: (thing: any) => thing is AbortError; /** * Creates and throws an AbortError with the provided message. Optionally aborts * the provided controller with the same error. * * @param message - The error message * @param controller - Optional AbortController to abort * @throws {AbortError} Always throws the created AbortError */ declare const throwAbort: (message?: string, controller?: AbortController) => never; declare const setTimeout$1: SetTimeout; /** * Maximum safe integer value for setTimeout delay. Any timeout value larger * than this may cause overflow issues in some browsers. * * @see https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value */ declare const MAX_SAFE_TIMEOUT: number; /** * Represents a constructor function that can be instantiated with the new * operator. * * @template T - The type of object that will be created when instantiated */ type Constructor = new (...args: any[]) => T; /** * Detects whether the code is running in a browser environment. Checks for the * existence of window and document objects. * * @returns True if running in a browser environment, false otherwise */ declare const isBrowser: () => boolean; /** * Creates a Promise and returns it along with its resolve and reject functions. * This utility is similar to the upcoming `Promise.withResolvers()` static * method. It allows for manual control over a Promise's settlement from outside * its constructor. * * @example * const { promise, resolve, reject } = withResolvers() * * promise * .then((value) => console.log('Resolved:', value)) * .catch((error) => console.error('Rejected:', error)) * * // Sometime later, or in a different part of the code: * if (Math.random() > 0.5) { * resolve('Success!') * } else { * reject(new Error('Failed!')) * } * * @template T - The type of the value the promise will resolve with. * @property {Promise} promise - The created Promise. * @property {(value: T) => void} resolve - A function to resolve the promise * with a value of type T. * @property {(reason?: any) => void} reject - A function to reject the promise * with an optional reason. * @returns An object containing the `promise`, and its `resolve` and `reject` * functions. */ declare const withResolvers: () => { promise: Promise; resolve: (value: T) => void; reject: (reason?: any) => void; }; /** * Removes the first occurrence of an item from an array in a single iteration. * Mutates the array in place by splicing out the found element. * * More efficient than using `indexOf` + `splice` as it only walks the array * once. * * @example * const items = [1, 2, 3, 4] * removeItem(items, 3) // returns true, items is now [1, 2, 4] * removeItem(items, 5) // returns false, items unchanged * * @template T - The type of elements in the array * @param array - The array to remove the item from * @param item - The item to remove (compared using strict equality) * @returns True if the item was found and removed, false otherwise */ declare const removeItem: (array: T[], item: T) => boolean; //#endregion //#region src/core/action.d.ts interface ActionCall { params: Params; payload: Payload; } /** Autoclearable array of processed events */ interface ActionState extends Array> {} /** Logic container with atom features */ interface Action extends AtomLike, Params, Payload> { subscribe: (cb?: (payload: Payload, params: Params) => any) => Unsubscribe; } /** Action type that supports all overloads of the original function */ type GAction = T & Action, ReturnType>; /** * Type guard to check if a value is a Reatom action. * * This function determines whether the given value is an action by checking if * it's an atom with non-reactive behavior (actions are non-reactive atoms). * * @param target - The value to check * @returns `true` if the value is a Reatom action, `false` otherwise */ declare let isAction: (target: unknown) => target is Action; /** * Creates an extension that adds middleware to an action, wrapping only the * call function, not the state. * * Unlike `withMiddleware`, which wraps the entire middleware chain (including * the state update), `withActionMiddleware` wraps only the call function that * gets passed to `actionMiddleware`. This allows you to decorate the action's * execution logic without interfering with the action's state management. * * @example * // Creating a retry middleware for actions * const withRetry = (maxAttempts: number) => * withActionMiddleware((target) => { * return (next, ...params) => { * let attempts = 0 * while (attempts < maxAttempts) { * try { * return next(...params) * } catch (error) { * attempts++ * if (attempts >= maxAttempts) throw error * } * } * } * }) * * // Using the middleware * const fetchData = action(async () => { * const response = await fetch('/api/data') * return response.json() * }).extend(withRetry(3)) * * @template Target - The type of action the middleware will be applied to * @param cb - A function that receives the target action and returns a * middleware function that wraps the call * @returns An extension that applies the middleware when used with .extend() */ declare let withActionMiddleware: { (cb: (target: Action) => (next: Fn, ...params: Params) => Payload): Ext>; }; /** * Creates a logic and side effect container. * * Actions are used to encapsulate complex logic, perform side effects (like API * calls), and orchestrate multiple state updates. Unlike atoms, actions are * meant to be called with parameters and can return values. * * Actions also have atom-like features (subscribe, extend) and track their call * history. * * @example * // Create an action that fetches data and updates state * const fetchUserData = action(async (userId: string) => { * const response = await wrap(fetch(`/api/users/${userId}`)) * const data = await wrap(response.json()) * * // Update state atoms with the fetched data * userName(data.name) * userEmail(data.email) * * return data // Actions can return values * }, 'fetchUserData') * * // Call the action * fetchUserData('user123') * * @template Params - The parameter types the action accepts * @template Payload - The return type of the action * @param cb - The function containing the action's logic * @param name - Optional name for debugging purposes * @returns An action instance that can be called with the specified parameters */ declare function action any>(cb: T, name?: string): GAction; declare function action(cb: (...params: Params) => Payload, name?: string): Action; //#endregion //#region src/core/actions.d.ts /** * Type representing a set of methods converted to Reatom actions. * * This type maps each method in the original record to a corresponding Reatom * action with the same parameter and return types. * * @template Methods - Record of functions to be converted to actions */ type ActionsExt> = { [K in keyof Methods]: Methods[K] extends ((...params: infer Params) => infer Payload) ? Action : never }; /** * Extension that binds actions to an atom or action as methods. * * This extension adds methods to an atom or action by converting them to Reatom * actions. Each method is converted to an action with the same name and bound * to the target. The name of each action will be prefixed with the target's * name for better debugging. * * @example * const counter = atom(0, 'counter').extend( * withActions({ * increment: (amount = 1) => counter((prev) => prev + amount), * decrement: (amount = 1) => counter((prev) => prev - amount), * reset: () => counter(0), * }), * ) * * counter.increment(5) // Can now call these methods directly * counter.reset() * * @example * const counter = atom(0, 'counter').extend( * withActions((target) => ({ * increment: (amount = 1) => target.set((prev) => prev + amount), * decrement: (amount = 1) => target.set((prev) => prev - amount), * reset: () => target.set(0), * })), * ) * * @template Target - The atom or action being extended * @template Methods - Record of functions to convert to actions * @param options - Either a record of methods or a function that creates * methods given the target * @returns An extension that adds the methods as actions * @throws {ReatomError} If a method name collides with an existing property on * the target */ declare function withActions>(options: Methods | ((target: Target) => Methods)): (target: Target) => ActionsExt; //#endregion //#region src/extensions/withAbort.d.ts interface AbortExt { abort: Action<[reason?: any]>; } /** * Extension to add abort handling to actions and computed atoms. * * @example * // last-in-win: only the last request matters * const fetchUser = action(async (id: number) => { * const response = await wrap(fetch(`/api/user/${id}`)) * return response.json() * }).extend(withAbort()) * * fetchUser(1) // will be aborted * fetchUser(2) // will be aborted * fetchUser(3) // this one wins * * @example * // first-in-win: ignore subsequent calls until the first completes * const fetchOnce = action(async () => { * await wrap(fetch('/api/data')) * }).extend(withAbort('first-in-win')) * * fetchOnce() // runs * fetchOnce() // ignored, returns previous promise * fetchOnce() // ignored, returns previous promise * * @example * // manual with manual abort (useful for polling/long-running tasks) * const poll = action(async () => { * while (true) { * await wrap(sleep(1000)) * doSome() * } * }).extend(withAbort('manual')) * * // start * poll() * * // stop * poll.abort() * * @param strategy - The abort strategy to use: * * - `'last-in-win'` (default): Aborts previous concurrent calls when a new one * starts * - `'first-in-win'`: Ignores new calls while a previous one is still running * - `'manual'`: No automatic abort, just adds the `abort` action for manual * control */ declare let withAbort: (strategy?: "last-in-win" | "first-in-win" | "finally" | "manual") => AssignerExt; //#endregion //#region src/persist/index.d.ts interface PersistRecord { data: Snapshot; id: number; timestamp: number; version: number | string; /** Time stamp after which the record is cleared. */ to: number; } declare let isPersistRecord: (value: unknown) => value is PersistRecord; declare function assertPersistRecord(value: unknown, storage?: string): asserts value is PersistRecord; interface PersistStorageCacheOption { cache?: Map; } type PersistCache = Map; interface PersistStorage { name: string; cache: PersistCache; get(options: Options & { key: string; }): null | PersistRecord | Promise>; set(options: Options & { key: string; }, rec: PersistRecord): void | Promise; clear?(options: Options & { key: string; }): void | Promise; subscribe?(options: Options & { key: string; }, callback: (record: PersistRecord) => void): Unsubscribe; } interface SyncPersistStorage { name: string; get(options: Options & { key: string; }): null | PersistRecord; set(options: Options & { key: string; }, rec: PersistRecord): void; clear?(options: Options & { key: string; }): void; subscribe?(options: Options & { key: string; }, callback: (record: PersistRecord) => void): Unsubscribe; } interface WithPersistOptions { /** Key of the storage record. */ key: string; /** Custom snapshot serializer. */ toSnapshot?: (state: State) => Snapshot; /** Custom snapshot deserializer. */ fromSnapshot?: (snapshot: Snapshot, state?: State) => State; /** Schema to validate and transform the snapshot. */ schema?: StandardSchemaV1; /** * A callback to call if the version of a stored snapshot is older than * `version` option. */ migration?: (persistRecord: PersistRecord, version: number | string) => State; /** * Determines whether the atom is updated on storage updates. * * @defaultValue true */ subscribe?: boolean; /** * Number of milliseconds from the snapshot creation time after which it will * be deleted. * * @defaultValue MAX_SAFE_TIMEOUT */ time?: number; /** * Version of the stored snapshot. Triggers `migration`. * * @defaultValue 0 */ version?: number | string; } type WithRequiredPersistOptions = WithPersistOptions & Shallow, 'fromSnapshot' | 'toSnapshot'>>>; interface WithPersist { (options: Options & WithPersistOptions, Decode>): Ext; (options: AtomState extends Snapshot ? ({} extends Options ? string : never) | (Options & WithPersistOptions, Decode>) : Options & WithRequiredPersistOptions, Decode>): Ext; /** * Atom that holds the current storage instance, useful other environments, * like SSR or tests to provide the storage instance to the user. */ storageAtom: Atom>; } declare const reatomPersist: (storage: Omit, "cache">) => WithPersist; declare const createMemStorage: ({ name, mutable, snapshot, subscribe: subscribeOption }: { name: string; mutable?: boolean; snapshot?: Rec; subscribe?: boolean; }) => PersistStorage & { snapshotAtom: Atom>; }; //#endregion //#region src/primitives/reatomMap.d.ts type StateInit$1 = Map | ConstructorParameters>[0]; interface MapAtom extends AtomLike, []> { /** * Update the atom's state using a function that receives the previous state * * @param update - Function that takes the current state and returns a new * state * @returns The new state value */ setState(update: (state: Map) => StateInit$1): Map; /** * Set the atom's state to a new value * * @param newState - The new state value * @returns The new state value */ setState(newState: StateInit$1): Map; getOrCreate: (key: Key, creator: () => Value) => Value; set: Action<[key: Key, value: Value], Map>; delete: Action<[key: Key], Map>; clear: Action<[], Map>; reset: Action<[], Map>; size: Computed; } /** * Creates a map atom for keyed entities, caches, and registries where random * access matters more than iteration order. * * @remarks * Use `getOrCreate` for lazy initialization, and `size` when you need a cheap * derived counter for badges or limits. * @example * // Cache user presence by id * const presenceByUserId = reatomMap( * [], * 'presenceByUserId', * ) * * presenceByUserId.getOrCreate('alice', () => ({ online: false })) * presenceByUserId.set('bob', { online: true }) * presenceByUserId.delete('alice') * * presenceByUserId.size() // 1 */ declare const reatomMap: (initState?: StateInit$1, name?: string) => MapAtom; //#endregion //#region src/extensions/withCache.d.ts type AsyncAtom = AtomLike>; interface CacheRecord { clearTimeoutId: ReturnType; isAsync?: boolean; /** * It is more like **"lastRequest"**, which is expected for failed fetching, * we don't want to remove the cache, if we couldn't fetch new one. */ lastUpdate: number; params: AtomParams; promise: undefined | ReturnType; controller: AbortController; value: undefined | Awaited>; version: number; } interface CacheAtom extends MapAtom> { /** Clear all records and call the effect with the last params. */ invalidate: Action<[], null | ReturnType>; setWithParams: Action<[params: AtomParams, value: Awaited>]>; deleteWithParams: Action<[params: AtomParams]>; options: WithCacheOptions; } type CacheMapRecord = undefined | CacheRecord; type WithCacheOptions = { /** * Define if the effect should be prevented from abort. The outer abort * strategy is not affected, which means that all hooks and returned promise * will behave the same. But the effect execution could be continued even if * abort appears, to save the result in the cache. * * @default true for empty params, false otherwise */ ignoreAbort?: boolean; /** * Define the behavior of `data()` atom from `withAsyncData` * * @default true for empty params, false otherwise */ initData?: boolean; /** * Maximum amount of cache records. * * @default 5 */ length?: number; /** * The number of excepted parameters, which will used as a cache key. * * @default undefined (all) */ paramsLength?: number; /** * The amount of milliseconds after which a cache record cleanups. * * @default 5 * 60 * 1000 ms (5 minutes) */ staleTime?: number; /** * (stale while revalidate) Define if fetching should be triggered even if the * cache is exists. A boolean value applies to all options * * @default false */ swr?: boolean | { /** * Success revalidation should trigger `onFulfill` to notify about the * fresh data * * @default true */ shouldFulfill?: boolean; /** * Error revalidation trigger `onReject` to notify about the error * * @default false */ shouldReject?: boolean; }; /** Persist adapter, which will used with predefined optimal parameters */ withPersist?: (options: WithPersistOptions>>) => Ext>; } & ({ /** * Convert params to stable string and use as a map key. Alternative to * `isEqual`. Disabled by default. */ paramsToKey?: (params: AtomParams) => string; } | { /** * Check the equality of a cache record and passed params to find the * cache. Alternative to `paramsToKey`. * * @default `isDeepEqual` from @reatom/utils */ isEqual?: (prev: AtomParams, next: AtomParams) => boolean; }); interface CacheVarState { isCached: boolean; isSWR: boolean; payload?: { value: unknown; }; promise?: Promise; } type CacheVarRecord = Pick | undefined; declare const cacheVar: Variable | undefined]>; declare let withCache: ; }>({ ignoreAbort: ignoreAbortOption, initData: _initData, length, paramsLength, staleTime, swr: swrOptions, withPersist, paramsToKey, isEqual }?: WithCacheOptions) => Ext; }>; //#endregion //#region src/extensions/withChangeHook.d.ts /** * Executes a callback whenever the target atom's state changes. * * This extension is essential for creating stable, declarative connections * between independent modules or features. The hook fires in the "Hooks" phase * of Reatom's lifecycle (after Updates, before Computations), making it perfect * for triggering side effects or synchronizing state across module boundaries. * * **When to use:** * * - Creating stable connections between features that shouldn't depend on each * other directly * - Triggering validation when a field's value or state changes * - Syncing derived state in response to source state changes * - Managing side effects like DOM updates or analytics based on state changes * - Coordinating behavior across module boundaries without coupling them * * **When NOT to use:** * * - In dynamic features, like from computed factories (use `take` or `effect` and * `ifChanged` instead) * - When a regular computed dependency would suffice * - For connection/disconnection events (use `withConnectHook` instead) * * The callback receives the new state and previous state. It only fires when * the state actually changes (referential inequality check via `Object.is`). * The callback executes within the same reactive context, so you can safely * call other atoms and actions. * * @example * // Basic usage: React to atom state changes * const theme = reatomEnum(['light', 'dark', 'system']).extend( * withChangeHook((state, prevState) => { * document.body.classList.remove(prevState) * document.body.classList.add(state) * }), * ) * * @example * // Stable feature connection: Analytics tracking * // In userModule.ts * export const userAtom = atom({ id: null, name: '' }, 'user') * * // In analyticsModule.ts * import { userAtom } from './userModule' * userAtom.extend( * withChangeHook((user, prevUser) => { * if (user.id !== prevUser?.id) { * analytics.identify(user.id, { name: user.name }) * } * }), * ) * * @template Target - The atom type being extended * @param cb - Callback fired when state changes. Receives: * * - `state` - The new state value * - `prevState` - The previous state value (undefined on first change) * * @returns Extension function to be used with `.extend()` * @throws {ReatomError} If callback is not a function * @see {@link addChangeHook} For dynamically adding/removing change hooks * @see {@link withCallHook} For reacting to action calls instead of state changes * @see {@link withErrorHook} For reacting to failed updates and action calls * @see {@link withConnectHook} For reacting to connection lifecycle events */ declare let withChangeHook: (cb: (state: AtomState, prevState: undefined | AtomState) => void) => Ext; /** * Dynamically adds a change hook to an existing atom and returns a function to * remove it. * * Unlike `withChangeHook` which is applied at atom definition time, * `addChangeHook` allows you to add and remove hooks at runtime. This is useful * for temporary subscriptions or when you need conditional hook behavior that * can be enabled/disabled dynamically. * * This feature is rarely needed, you should prefer using `effect` with * `ifChanged` or `take` instead. * * @template T - The atom type * @param target - The atom to attach the hook to * @param cb - Callback fired when state changes * @returns Unsubscribe function to remove this specific hook * @see {@link withChangeHook} For adding hooks at atom definition time */ declare let addChangeHook: (target: T, cb: (state: AtomState, prevState?: AtomState) => void) => Unsubscribe; /** * Executes a callback whenever the target action is called. * * This extension enables you to react to action invocations, making it * invaluable for creating stable connections between independent features. The * hook fires in the "Hooks" phase (after Updates, before Computations) and * receives both the action's return value and its parameters. * * **When to use:** * * - Creating stable cross-module connections that react to specific actions * - Tracking action calls for analytics, logging, or debugging * - Triggering side effects in response to action completions * - Coordinating behavior between independent features without coupling them * - Implementing event-driven communication patterns * * **When NOT to use:** * * - In dynamic features, like from computed factories (`take` or `effect` and * `getCalls` instead) * - When you can achieve the same goal with direct action composition * * For actions extended with `withAsync`, you can also hook into `.onFulfill`, * `.onReject`, or `.onSettle` to react to async completion events. * * @example * // Cross-module coordination: Analytics tracking * // In checkoutModule.ts * export const submitOrder = action(async (order) => { * const result = await api.submitOrder(order) * return result * }, 'submitOrder') * * // In analyticsModule.ts * import { submitOrder } from './checkoutModule' * submitOrder.extend( * withCallHook((promise, params) => { * const [order] = params * analytics.track('new_order', { * orderId: order.id, * total: order.total, * }) * }), * ) * * @example * // Stable feature connection: Form submission tracking * const fetch = action(async (param: number) => { * const data = await api.fetch(param) * return data * }, 'fetch').extend(withAsync()) * * fetch.onFulfill.extend( * withCallHook((call) => { * console.log('Fetch completed', call.payload) * }), * ) * * @template Target - The action type being extended * @param cb - Callback fired when action is called. Receives: * * - `payload` - The return value of the action * - `params` - The parameters passed to the action as an array * * @returns Extension function to be used with `.extend()` * @throws {ReatomError} If callback is not a function * @throws {ReatomError} If applied to an atom instead of an action * @see {@link addCallHook} For dynamically adding/removing call hooks * @see {@link withChangeHook} For reacting to atom state changes instead * @see {@link withAsync} For async action lifecycle hooks (onFulfill, onReject, onSettle) */ declare let withCallHook: (cb: (payload: ReturnType, params: OverloadParameters) => void) => Ext; /** * Dynamically adds a call hook to an existing action and returns a function to * remove it. * * Unlike `withCallHook` which is applied at action definition time, * `addCallHook` allows you to add and remove hooks at runtime. This is useful * for temporary subscriptions, conditional hook behavior, or when integrating * with external systems that need to be connected and disconnected * dynamically. * * This feature is rarely needed, you should prefer using `effect` with * `getCalls` or `take` instead. * * @template Target - The action type * @param target - The action to attach the hook to * @param cb - Callback fired when the action is called * @returns Unsubscribe function to remove this specific hook * @see {@link withCallHook} For adding hooks at action definition time */ declare let addCallHook: (target: Target, cb: (payload: ReturnType, params: OverloadParameters) => void) => Unsubscribe; //#endregion //#region src/extensions/withComputed.d.ts /** * A middleware extension that enhances an atom with computed capabilities. * * @template Target - The target atom or action type to be extended with * computed functionality. * @param {function} computed - A function that computes the new state based on * the current state. * @param {Object} [options={}] - Configuration options. Default is `{}` * @param {boolean} [options.tail=true] - Determines the order of the passed * computed calling. ATTENTION: use `false` only for computed with fixed size * of dependencies. Default is `true` * @returns {Ext} The extended atom or action with computed * functionality. */ declare let withComputed: (computed: (state: AtomState) => AtomState, { tail }?: { tail?: boolean; }) => Ext; //#endregion //#region src/extensions/withConnectHook.d.ts declare let withConnectHook: (cb: (target: Target) => MaybeUnsubscribe) => Ext; declare let withDisconnectHook: (cb: (target: Target) => void) => Ext; //#endregion //#region src/extensions/withDynamicSubscription.d.ts /** * This interface improve `.subscribe` method behavior by relying it on * `abortVar`. It performs unsubscribe automatically, when abort will occur. */ interface DynamicSubscriptionExt {} declare let withDynamicSubscription: () => (target: Target) => Target & DynamicSubscriptionExt; //#endregion //#region src/extensions/withErrorHook.d.ts /** * Executes a callback whenever the target atom or action throws during an * update or call. * * The hook fires in the "Hooks" phase via the reactive queue, after the failed * operation throws synchronously to the caller. The original error is always * re-thrown. * * @example * const field = atom(0, 'field').extend( * withParams((value: number) => { * if (value < 0) throw new Error('negative') * return value * }), * withErrorHook((error, params) => { * console.error('Invalid value', params, error) * }), * ) * * @template Target - The atom or action type being extended * @param cb - Callback fired when the target throws. Receives: * * - `error` - The thrown error * - `params` - The parameters passed to the failed update or call * * @returns Extension function to be used with `.extend()` * @throws {ReatomError} If callback is not a function * @see {@link addErrorHook} For dynamically adding/removing error hooks * @see {@link withChangeHook} For reacting to successful state changes * @see {@link withCallHook} For reacting to successful action calls */ declare let withErrorHook: (cb: (error: unknown, params: OverloadParameters) => void) => Ext; /** * Dynamically adds an error hook to an existing atom or action and returns a * function to remove it. * * @template T - The atom or action type * @param target - The atom or action to attach the hook to * @param cb - Callback fired when the target throws * @returns Unsubscribe function to remove this specific hook * @see {@link withErrorHook} For adding hooks at atom definition time */ declare let addErrorHook: (target: T, cb: (error: unknown, params: OverloadParameters) => void) => Unsubscribe; //#endregion //#region src/extensions/withInit.d.ts /** * Checks if the current execution context is within the initialization of the * current atom. * * @example * const search = atom('', 'search').extend(withSearchParams('search')) * const page = atom(1, 'page').extend( * withSearchParams('page'), * withComputed((state) => { * search() // subscribe to the search changes * // do NOT drop the persisted state on init * return isInit() ? state : 1 * }), * ) * * @returns {boolean} True if currently in the initialization phase, false * otherwise */ declare let isInit: () => boolean; /** * Define dynamically computed initial value for an atom. * * Typically, you can use just an init callback in `atom` first argument: * `atom(() => new Date())`. But if you need to add initial callback after the * atom creation, so there this extensions is useful. * * @example * const something = reatomSomething().extend( * withInit((initState) => ({ ...initState, ...additions })), * ) * * @example * const myData = atom(null, 'myData') * if (meta.env.TEST) { * myData.extend(withInit(mockData)) * } * * @template Target - The atom type that extends AtomLike * @param {AtomState * | ((state: AtomState) => AtomState)} init * The initial value or a function that returns the initial value based on * current state * @returns {Ext} An extension that can be applied to an atom */ declare let withInit: (init: AtomState | ((state: AtomState, ...params: any[]) => AtomState)) => Ext; /** * Extension that runs the passed hook when the atom is initialized. * * @example * const userAtom = atom({ id: 1, name: 'John' }).extend( * withInitHook((initState) => { * // Perform any setup logic here * analytics.track('user_loaded', initState) * }), * ) * * @template Target - The atom type that extends AtomLike * @param {(initState: AtomState) => any} hook A function to be called * with the initial state during initialization * @returns {Ext} An extension that can be applied to an atom */ declare let withInitHook: (hook: (initState: AtomState) => any, queue?: QueueKind) => Ext; //#endregion //#region src/extensions/withMemo.d.ts declare let withMemo: (isEqual?: (prevState: AtomState, nextState: AtomState) => boolean) => Ext; //#endregion //#region src/extensions/withSuspense.d.ts /** * Internal suspense cache record tracking promise state. Do not use it * directly, only for libraries! */ interface SuspenseRecord { kind: 'pending' | 'fulfilled' | 'rejected'; value: any; } /** * Internal suspense cache mapping promises to their settlement state. Do not * use it directly, only for libraries! */ declare let SUSPENSE: WeakMap, SuspenseRecord>; /** * Checks if a promise is settled and returns its value or fallback. If the * promise is fulfilled, returns the resolved value. If the promise is rejected, * throws the error. If the promise is pending, returns the fallback value * (defaults to undefined). * * Uses an internal WeakMap cache to track promise states across calls. * * @example * const promise = Promise.resolve(42) * await promise * const value = settled(promise) // 42 * * @param promise - The promise or synchronous value to check * @param fallback - The value to return if the promise is still pending * @returns The resolved value if fulfilled, throws if rejected, or fallback if * pending */ declare let settled: (promise: Result | Promise, fallback?: Fallback) => Result | Fallback; /** * Extension type that adds a `suspended` computed atom to track resolved values * from async atoms. */ type SuspenseExt = { suspended: Computed>; }; /** * Extension that adds suspense support to async atoms. Creates a `suspended` * computed atom that tracks the resolved value of promises and throws the * promise when pending (for React Suspense compatibility). * * The `suspended` atom will: * * - Return the resolved value immediately if the promise is already fulfilled * - Throw the promise if it's still pending (allowing Suspense boundaries to * catch it) * - Propagate errors if the promise is rejected * - Automatically update when the promise resolves * * @example * const data = computed(async () => { * const response = await fetch('/api/data') * return response.json() * }, 'data').extend(withSuspense()) * * // Subscribe to resolved values * subscribe(data.suspended, (value) => { * console.log('Resolved:', value) * }) * * // Use in React component with Suspense * function Component() { * const value = useAtom(data.suspended) // throws promise if pending * return
{value}
* } * * @param options - Configuration options * @param options.preserve - If true, preserves the previous state when * suspending instead of throwing immediately. Useful for preventing * flickering in UI. * @returns An extension that adds the `suspended` computed atom */ declare let withSuspense: >>>({ preserve }?: { preserve?: boolean; }) => Ext>>; /** * Helper function to access the suspended value of an atom. Automatically * applies `withSuspense()` extension if the atom doesn't already have it. * * This function: * * - Returns the resolved value if the promise is fulfilled * - Throws the promise if it's still pending (for Suspense boundaries) * - Throws the error if the promise is rejected * * @remarks * If `withSuspense` is already applied with different `preserve` options, the * behavior may be inconsistent. Consider applying `withSuspense()` explicitly * to control options. * @example * const data = computed(async () => { * const response = await fetch('/api/data') * return response.json() * }, 'data') * * // Automatically applies withSuspense() and returns suspended value * const result = computed(() => { * try { * return suspense(data) // throws promise if pending * } catch (promise) { * if (promise instanceof Promise) { * // Handle pending state * return undefined * } * throw promise // Re-throw errors * } * }, 'result') * * @param target - The atom to get the suspended value from * @returns The resolved value (Awaited), or throws a promise/error */ declare let suspense: (target: AtomLike) => Awaited; /** * Extension that enables asynchronous initialization for synchronous atoms. * This feature bridges async data loading with sync atom semantics. * * During initialization, if the result is a Promise, it throws the promise * (suspense pattern) and schedules setting the atom's state when resolved. * After initialization completes, the atom operates fully synchronously. * * This is perfect for local-first architectures: load data asynchronously on * init, then work with it synchronously. Combine with `withChangeHook` to sync * changes back to a server or database. * * **Without callback**: Transforms `Atom>` or sync atoms that * may return or throw a suspense promise into `Atom`. * * @example * const userSettings = atom(async () => { * const response = await fetch('/api/settings') * return response.json() * }).extend(withSuspenseInit()) * // Type: Atom (not Atom>) * * effect(() => { * // After init completes, reads are synchronous * const settings = userSettings() * console.log(settings.theme) * }) * * @example * // With callback: Provides an async initializer for any atom type, keeping the original state type. * // Local-first pattern: async init + sync operations + sync-back * const todos = atom([]).extend( * withSuspenseInit(async () => { * const cached = await indexedDB.get('todos') * return cached ?? [] * }), * withChangeHook((newState) => { * // Sync changes back to storage * indexedDB.set('todos', newState) * }), * ) * * @example * // Typed async init with custom default * const profile = atom<{ username: string; age: number }>( * throwAbort, * ).extend( * withSuspenseInit(async () => { * const data = await fetchProfile() * return data ?? { username: 'guest', age: 0 } * }), * ) * * @overload * @overload * @param cb - Async or sync initializer function. Receives the current init * state and returns the new state (or Promise of it). * @returns Extension that unwraps `Atom>` to `Atom` * @returns Extension that initializes the atom with the callback result */ declare let withSuspenseInit: { (): Ext, Atom>>; (cb: (state?: AtomState) => AtomState | Promise>): Ext; }; //#endregion //#region src/extensions/withSuspenseRetry.d.ts /** * Creates a mixin that retries an async action when it fails coz of a * suspension * * This mixin wraps an async action to automatically retry it when a Promise is * thrown, which indicates a suspension. It will keep retrying until the action * completes successfully or throws a non-Promise error. * * ⚠️ Be careful with non-idempotent operations inside the action body, as they * may be executed multiple times during retries. It's recommended to carefully * plan the execution logic to handle potential retries safely. * * @example * const fetchUserBooks = action(async () => { * const id = user().id // `user` is a suspended atom * const response = await fetch(`/api/users/${id}/books`) * return response.json() * }).extend(withSuspenseRetry()) * * @returns The same passed action */ declare let withSuspenseRetry: >>() => Ext; //#endregion //#region src/extensions/withToJson.d.ts /** * Overrides default JSON serialization for an atom. * * By default, atoms serialize to their current state via `JSON.stringify`. Use * this extension when you need a custom JSON shape, for example a unix * timestamp instead of an ISO string for dates. * * @example * const createdAt = atom(new Date('2024-01-15'), 'createdAt').extend( * withToJson((state) => state.getTime()), * ) * * JSON.stringify(createdAt) // '1705276800000' */ declare const withToJson: (serialize: (state: AtomState) => unknown) => Ext; //#endregion //#region src/methods/variable.d.ts type NonUndefined = NonNullable | null; interface AsyncVariableOptions { name?: string; defaultValue?: T; create?: (...params: Params) => T; } /** * Interface for context variables in Reatom * * Variables maintain values within the context of a computation tree, allowing * for context-aware state similar to React's Context API but with more granular * control and integration with Reatom's reactive system. * * @template T - Type of the stored value * @see {@link https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextvariable} */ declare class Variable { protected _findReactiveStartIndex: number; protected create: (...params: Params) => T; readonly name: `var#${string}`; constructor(options?: AsyncVariableOptions); /** * Gets the frame value of the variable. Traverse the whole stack to find it. * * @param {Frame} [frame] - Optional frame to check (defaults to current top * frame) * @returns {T} The current value * @throws {Error} If the variable is not found in the frame tree */ get(frame?: Frame): undefined | T; /** * Gets the value of the variable and throws an error if it is not found in * the frame stack. * * This method is a stricter version of `get()` that ensures the variable has * been set to a value. Use this when you expect the variable to always be * defined and want to fail fast if it is not. * * @param {Frame} [frame] - Optional frame to check (defaults to current top * frame) * @returns {T} The current value (guaranteed to be defined) * @throws {ReatomError} If the variable is not set (undefined) */ require(frame?: Frame): T; /** * Executes a callback function with the variable set to a specific value * within that execution context * * This method creates a new frame in the context tree where the variable is * bound to the provided value. The callback function runs within this frame, * allowing any code inside (and its descendants) to access this value via * `get()`. * * @example * const userVar = variable('user') * * userVar.run('Alice', () => { * console.log(userVar.get()) // 'Alice' * }) * * // Passing parameters to callback * const result = userVar.run('Bob', (x, y) => x + y, 2, 3) * console.log(result) // 5 * * @template Params - Types of parameters passed to the callback * @template Payload - Return type of the callback * @param {T} value - The value to set for this variable during callback * execution. Cannot be undefined. * @param {(...params: Params) => Payload} cb - The callback function to * execute with the variable set * @param {...Params} params - Additional parameters to pass to the callback * @returns {Payload} The return value of the callback * @throws {ReatomError} If value is undefined */ run: GAction<((value: T, cb: (...params: Params) => Payload, ...params: Params) => Payload)>; /** * Runs a callback with an auto-created variable value. Only available when * the variable's create function requires no parameters. * * @example * const loggerVar = variable(() => console, 'logger') * * loggerVar.createAndRun(() => { * loggerVar.get()?.log('Hello!') // uses auto-created console * }) */ createAndRun: GAction<((cb: (...params: Params) => Payload, ...params: Params) => Payload)> & ([] extends Params ? {} : never); /** * This utility allow you to start a function which will NOT follow the async * context of this variable. * * @example * // If you want to start a fetch when the atom gets a subscription, * // but don't want to abort the fetch when the subscription is lost to save the data anyway. * const some = atom('...').extend( * withConnectHook((target) => { * abortVar.spawn(async () => { * // here `wrap` doesn't follow the connection abort * const data = await wrap(api.getSome()) * some(data) * }) * }), * ) */ spawn: GAction<((cb: (...params: Params) => Payload, ...params: Params) => Payload)>; /** * Gets the variable value from the first frame only, without traversing the * whole frame tree * * Unlike `get()` which searches through parent frames, this method only * checks the top frame. Returns undefined if the variable is not set in the * frame. * * @returns {undefined | T} The value in the frame, or undefined if not set */ first(frame?: Frame): undefined | T; /** * Checks if the variable exists in the passed frame stack * * @param {Frame} [frame] - Optional frame to check (defaults to current top * frame) * @returns {boolean} True if the variable exists in the context */ has(frame?: Frame): boolean; /** * Traverses the frame tree to find and map the variable value. * * @template Result - Return type of the callback * @param {(value: undefined | T) => undefined | Result} [cb] - Optional * transformation callback * @param {Frame} [frame] - Optional frame to check (defaults to current top * frame) * @returns {undefined | Result} The transformed value or undefined if not * found */ find(cb?: (payload: undefined | T) => undefined | Result, frame?: Frame): undefined | Result; /** * Sets a new variable value for CURRENT frame. Be aware that it is mostly for * internal use! * * @param {...Params} params - Parameters passed to the setter function * @returns {T} The new value */ set(...params: Params): T; } /** * Creates a new context variable with getter and setter functionality * * This implementation provides a similar capability to the proposed TC39 * AsyncContextVariable, allowing you to maintain values that are specific to a * particular execution context. Variables created with this function can be * accessed and modified within their frame context. * * Also, it can be used as IoC/DI container replacement: * * | IoC/DI Concept | Variable Equivalent | * | --------------- | ------------------------------- | * | Token/Key | `variable('name')` | * | Provider | `.run(impl, fn)` / `.set(impl)` | * | Inject/Resolve | `.require()` or `.get()` | * | Container scope | Execution context (frame stack) | * * @example * // Simple variable with string values * const currentUser = variable('currentUser') * * // Set the value * currentUser.set('Alice') * * // Get the value * console.log(currentUser.get()) // 'Alice' * * // Run code with a different value * currentUser.run('Bob', () => { * console.log(currentUser.get()) // 'Bob' * }) * * // Advanced variable with custom setter logic * const userRole = variable((role: string, permissions: string[]) => { * return { role, permissions } * }, 'userRole') * * userRole.set('admin', ['read', 'write', 'delete']) * * @example * // Using variable as IoC/DI container replacement * // Step 1: Define service interface (DI contract) * interface Logger { * log: (message: string) => void * } * * // Step 2: Create a variable as DI token/key * const loggerVar = variable('logger') * * // Step 3: Inject dependency in atoms/actions via `require()` * const fetchData = action(async (url: string) => { * const logger = loggerVar.require() * logger.log(`Fetching ${url}`) * const response = await wrap(fetch(url)) * logger.log(`Fetched ${url}`) * return response.json() * }, 'fetchData') * * // Step 4: Provide implementation at application entry point * loggerVar.run(console, () => { * fetchData('/api/users') // uses console as logger * }) * * // In tests, createAndRun a mock implementation * const mockLogger = { log: vi.fn() } * loggerVar.run(mockLogger, () => { * fetchData('/api/users') // uses mock logger * }) * * @example * // Variable with creation function for lazy initialization * // Useful when the dependency needs configuration or is expensive to create * const dbVar = variable( * (connectionString: string) => new Database(connectionString), * 'db', * ) * * // Inside a main process function, use `.set()` instead of `.run()` * // This is handy when you control the whole feature lifecycle * const initApp = action(async () => { * // `.set()` creates and binds the value to the current frame * const db = dbVar.set(process.env.DATABASE_URL) * * // All subsequent calls in this frame can access the db * await loadUsers() // uses dbVar.require() internally * await loadPosts() // uses dbVar.require() internally * }, 'initApp') * * const loadUsers = action(async () => { * const db = dbVar.require() * return db.query('SELECT * FROM users') * }, 'loadUsers') * * @template T - The type of the simple variable (when used with just a name) * @template Params - Types of parameters for the setter function * @template Payload - The type of the stored value * @see {@link https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextvariable} */ declare let variable: { (name?: string): Variable; (set: (...params: Params) => Payload, name?: string): Variable; }; //#endregion //#region src/methods/abortVar.d.ts /** * Version of abort controller with explicit name for better debugging. * * May control variable propagation by setting the `spawned` flag (used * internally to handle abort boundaries). * * @param name - The name of the abort controller * @param spawned - Whether to traverse the frame tree beyond the current frame * (default: `false`) */ declare class ReatomAbortController extends AbortController { name: string; spawned: boolean; constructor(name: string, spawned?: boolean); abort(reason?: any): void; } interface ControlledPromise extends Promise { controller: AbortController; } interface AbortSubscription { controller: ReatomAbortController; unsubscribe: Unsubscribe; [Symbol.dispose]: Unsubscribe; [Symbol.asyncDispose]: Unsubscribe; /** * Controller that managed the subscribtion itself, mostly for internal usage. * * @private */ listenerController: AbortController; } declare class AbortVariable extends Variable { protected _findReactiveStartIndex: number; find(cb?: (payload: undefined | ReatomAbortController) => undefined | Result, frame?: Frame): undefined | Result; createAndRun: GAction<((cb: (...params: Params) => Payload, ...params: Params) => Payload extends Promise ? ControlledPromise : Payload)>; constructor(); /** * Subscribes to abortion events from parent context tree (including current * frame). * * Creates a subscription that listens for abort signals from any parent * AbortController in the context tree. When an abort occurs, the callback is * invoked with the abort error and the subscription automatically cleans up. * * It is IMPORTANT to clean up the subscription when it is no longer needed, * otherwise a memory leak will occur. You can use the `unsubscribe` function * returned by this method or `using` statement. * * @example * const myResource = computed(async () => { * const { controller, unsubscribe } = abortVar.subscribe() * const { signal } = controller * * try { * const response = await fetch('/api/my-resource', { signal }) * return await response.json() * } finally { * unsubscribe() * } * }).extend(withAsyncData()) * * @example * const myResource = computed(async () => { * using { controller } = abortVar.subscribe() * const { signal } = controller * * const response = await fetch('/api/my-resource', { signal }) * return await response.json() * }).extend(withAsyncData()) * * @param {(error: AbortError) => void} cb - Callback invoked when abortion * occurs * @returns {Object} Subscription object * @returns {AbortController} Controller - The AbortController for the current * context * @returns {Function} Unsubscribe - Function to unsubscribe from abort events */ subscribe(cb?: (error: AbortError) => void): AbortSubscription; /** * NOTE: this method already used in `wrap`, that you should use in your code * instead. * * Throws if any AbortController in the parent context (frame) tree, including * the current frame, is aborted. * * @throws {AbortError} */ throwIfAborted(frame?: Frame): void; } declare let abortVar: AbortVariable; /** * Races multiple controlled promises and automatically aborts all losers when * one settles. * * Unlike `Promise.race`, this function ensures proper cleanup by aborting all * remaining promises once a winner is determined. This prevents resource leaks * from ongoing async operations that are no longer needed. * * @example * const resource = computed(async () => { * return race( * abortVar.createAndRun(() => fetchFromCache()), * abortVar.createAndRun(() => fetchFromNetwork()), * ) * }) * * @param promises - Controlled promises to race (must have `controller` * property) * @returns Promise that resolves/rejects with the first settled value */ declare let race: (...promises: Array>) => Promise; //#endregion //#region src/methods/connectLogger.d.ts declare let log: Action & { state(name: string, data: T): T; }; /** * Sets up and connects a logger to the Reatom system for debugging and tracing. * * This function enhances all non-private atoms and actions with logging * capabilities. When an atom's value changes or an action is called, it logs * the event with relevant information to the console including: * * - Previous and current state for atoms * - Parameters and return values for actions * - Complete dependency stack traces * - Error information when exceptions occur * * The logger adapts to the environment, using different formatting for browser * and Node.js. Private atoms (those with names starting with `_` or containing * `._`) are not logged. * * @example * connectLogger() * * @example * connectLogger({ match: (name) => name.startsWith('myFeature.') }) * * @example * // Highlight specific atoms with custom colors * connectLogger({ * match: (name) => (name.includes('important') ? '#ff6b6b' : true), * }) * * @param options.match - Optional matcher to control which atoms/actions are * logged. Return `true` to log, `false` to skip, or a color string to log * with custom background (browser only). */ declare let connectLogger: ({ match }?: { /** * Return `true` to log, `false` to skip, or a color string (e.g. `'#ff0000'`) * to log with custom background (browser only) */ match?: (name: string, frame: Frame) => boolean | string; }) => void; //#endregion //#region src/primitives/reatomLinkedList.d.ts type State$1 = T extends Atom ? Value : T; declare const LL_PREV: unique symbol; type LL_PREV = typeof LL_PREV; declare const LL_NEXT: unique symbol; type LL_NEXT = typeof LL_NEXT; type LLNode = T & { [LL_PREV]: null | LLNode; [LL_NEXT]: null | LLNode; }; type LinkedListSymbols = { readonly LL_PREV: LL_PREV; readonly LL_NEXT: LL_NEXT; }; type LLChanges = { kind: 'create'; node: Node; } | { kind: 'createMany'; nodes: Node[]; } | { kind: 'remove'; node: Node; } | { kind: 'removeMany'; nodes: Node[]; } | { kind: 'swap'; a: Node; b: Node; } | { kind: 'move'; node: Node; after: null | Node; } | { kind: 'clear'; }; interface LinkedList extends LinkedListSymbols { head: null | Node; tail: null | Node; size: number; version: number; changes: Array>; } interface LinkedListLikeAtom extends Atom, LinkedListSymbols { array: Computed ? LLNode : never>>; __reatomLinkedList: true; } interface LinkedListAtom extends LinkedListLikeAtom>> { batch: Action<[cb: Fn]>; create: Action>; createMany: Action<[Array], Array>>; remove: Action<[LLNode], boolean>; removeMany: Action<[Array>], number>; swap: Action<[a: LLNode, b: LLNode], void>; move: Action<[node: LLNode, after: null | LLNode], void>; clear: Action<[], void>; find: (cb: (node: LLNode) => boolean) => null | LLNode; /** * This lazy map is useful for working with serializable identifier, but it is * not recommended to use it for large (thousands elements) lists */ map: Key extends never ? never : Atom, LLNode>>; initiateFromState: (initState: Array) => LinkedList>; initiateFromSnapshot: (initSnapshot: Array) => LinkedList>; reatomMap: (cb: (node: LLNode) => T, options?: string | { name?: string; onCreate?: (node: LLNode) => void; onRemove?: (node: LLNode, origin: LLNode) => void; onSwap?: (payload: { a: LLNode; b: LLNode; }) => void; onMove?: (node: LLNode) => void; onClear?: (lastState: LinkedListDerivedState, LLNode>) => void; }) => LinkedListDerivedAtom, LLNode>; } interface LinkedListDerivedState extends LinkedList { map: WeakMap; } interface LinkedListDerivedAtom extends Computed>, LinkedListSymbols { array: Computed ? LLNode : never>>; __reatomLinkedList: true; } /** * Creates a reactive linked list for collections where inserts, removals, and * reordering are part of the main workflow. * * @remarks * Each item becomes a node with hidden prev/next links, so you can `move` or * `swap` existing items without rebuilding the whole collection. You can * start from existing nodes, a node factory, or a config with `initState` / * `initSnapshot`. Use `array()` when rendering with normal array helpers, * `key` when you need lookup by a stable id, and `batch()` when importing or * reordering many nodes at once. * @example * // Build a reorderable upload queue * const uploads = reatomLinkedList( * { * create: (fileName: string) => ({ * fileName, * progress: atom(0), * }), * key: 'fileName', * }, * 'uploads', * ) * * uploads.create('cover.png') * const hero = uploads.create('hero.png') * * uploads.move(hero, null) * uploads.map().get('cover.png')?.progress.set(100) * * uploads.array().map((upload) => ({ * fileName: upload.fileName, * progress: upload.progress(), * })) * // [ * // { fileName: 'hero.png', progress: 0 }, * // { fileName: 'cover.png', progress: 100 }, * // ] * * @example * // Keep derived row state in sync with the source order * const backlog = reatomLinkedList( * (title: string) => ({ title }), * 'backlog', * ) * const rows = backlog.reatomMap( * (task) => ({ * title: task.title, * expanded: atom(false), * }), * 'backlogRows', * ) * * const docsTask = backlog.create('Write docs') * backlog.create('Ship release') * * rows.array()[0].expanded.set(true) * backlog.remove(docsTask) * * rows.array().map((row) => ({ * title: row.title, * expanded: row.expanded(), * })) * // [{ title: 'Ship release', expanded: false }] */ declare function reatomLinkedList(initState: Array, name?: string): LinkedListAtom; declare function reatomLinkedList(initState: (...params: Params) => Node, name?: string): LinkedListAtom; declare function reatomLinkedList(initState: { create: (...params: Params) => Node; initState?: Array; key?: Key; }, name?: string): LinkedListAtom; declare function reatomLinkedList(initState: { create?: (...params: Params) => Node; initState: Array; key?: Key; }, name?: string): LinkedListAtom; declare function reatomLinkedList(initSnapshot: { create: (...params: Params) => Node; initSnapshot?: Array; key?: Key; }, name?: string): LinkedListAtom; /** * Checks whether a value is a linked list atom or a linked-list derivative * created by `reatomLinkedList`. * * @example * // Enable drag-and-drop only for linked lists * const canReorder = (value: unknown) => * isLinkedListAtom(value) && value().size > 1 */ declare const isLinkedListAtom: (thing: any) => thing is LinkedListLikeAtom; //#endregion //#region src/methods/deatomize.d.ts type Primitive = string | number | boolean | null | undefined; type Builtin = Date | RegExp | Function; /** * Type utility that recursively unwraps atom types to their state types * * This complex type recursively traverses a type structure, unwrapping atoms to * their contained state types. It handles various container types like arrays, * maps, sets, and objects. * * @template T - The type to unwrap * @returns Unwrapped version of the type with atoms replaced by their state * types */ type Deatomize = T extends LinkedListLikeAtom ? T extends LinkedList> ? Array> : never : T extends AtomLike ? T extends AtomLike, Params, Payload> ? T : Deatomize : T extends Map ? Map> : T extends Set ? Set> : T extends Array ? Array> : T extends Primitive | Builtin ? T : T extends Record ? { [K in keyof T]: Deatomize } : T; /** * Recursively unwraps atoms in a value to get their current states * * This function deeply traverses a value, including nested objects, arrays, * maps, and sets, replacing atoms with their current state values. It's useful * for serialization, debugging, or creating snapshots of state that don't * contain reactive references. * * @example * const user = { * id: 42, * name: atom('John', 'userName'), * stats: { * score: atom(100, 'userScore'), * badges: atom(['gold', 'silver'], 'userBadges'), * }, * } * * // Results in: { id: 42, name: 'John', stats: { score: 100, badges: ['gold', 'silver'] }} * const plainUser = deatomize(user) * * @template Value - The type of value to parse * @param {Value} value - The value containing atoms to unwrap * @returns {Deatomize} A new value with all atoms replaced by their * current states */ declare const deatomize: (value: Value) => Deatomize; //#endregion //#region src/methods/effect.d.ts interface Effect extends Computed { unsubscribe: Unsubscribe; } /** * Creates a reactive side effect that automatically tracks dependencies and * cleans itself up. * * `effect` is similar to `computed` but designed for running side effects. It * automatically subscribes to any atoms read within the callback (`cb`). When * the effect's reactive context is aborted (e.g., component unmount in * `reatomFactoryComponent`, cancellation in `withAbort` / `withAsyncData`), the * effect's execution is stopped, and any ongoing async operations within it * (like `await wrap(sleep(...))`) are cancelled. * * @example * import { atom, effect, wrap, sleep, isAbort } from '@reatom/core' * * const isActive = atom(true, 'isActive') * const data = atom(0, 'data') * * // This effect polls data every 5 seconds while isActive is true * const polling = effect(async () => { * if (!isActive()) return // Depends on isActive * * console.log('Polling started...') * while (true) { * const fetchedData = await wrap(fetch('/api/poll')) * const jsonData = await wrap(fetchedData.json()) * data(jsonData.value) * await wrap(sleep(5000)) // Abortable sleep == debounce * } * }, 'pollingEffect') * * // To manually stop: * // polling.unsubscribe() * * @param cb The function to run as a side effect. It can be async. Any atoms * read inside `cb` will become dependencies. * @param name Optional name for debugging purposes. Auto-generated if not * provided. * @returns The new computed atom with `unsubscribe` method to manually clean up * the effect. Calling this function is usually not necessary when `effect` is * used within managed contexts like `reatomFactoryComponent` or * `withConnectHook`, as cleanup happens automatically. */ declare let effect: (cb: () => T, name?: string) => Computed & AbortExt & DynamicSubscriptionExt & { unsubscribe: Unsubscribe; }; //#endregion //#region src/methods/framePromise.d.ts /** * Request the result of the current atom or action function as a promise. * * Returns a promise that resolves to the current execution frame's state * (action payload or atom state). Use it to catch errors from subsequent * operations in a cleaner way than traditional try-catch. Use `finally` to * clean up resources and so on. This method respects wrap and abortVar * policies. * * Inspired by TC39 explicit resource management proposal, but simpler and * coupled to Reatom's async stack for an ergonomic usage. * * @example * export const processPayment = action(async (orderId: string) => { * framePromise().catch((error) => showErrorNotification(error)) * * let order = await wrap(fetchOrder(orderId)) * await wrap(validateInventory(order)) * await wrap(chargeCustomer(order)) * await wrap(updateOrderStatus(order, 'completed')) * * return order * }) * * @example * // Classic approach - boilerplate with try-catch * export const doSome = action(async () => { * try { * await wrap(fetchUser()) * await wrap(updateProfile()) * await wrap(syncData()) * } catch (error) { * toast(error) * } * }) * * // native using - no try-catch and no "finally" logic * // only resource management with extra variables * // you can adapt `toast`, but without the payload / error data * export const doSome = action(async () => { * using _ = toast * await wrap(fetchUser()) * await wrap(updateProfile()) * await wrap(syncData()) * }) * * // With our framePromise() - clean and declarative * export const doSome = action(async () => { * framePromise().catch((error) => toast(error)) * await wrap(fetchUser()) * await wrap(updateProfile()) * await wrap(syncData()) * }) * * @example * // Native using works only within the current function scope=* * export const processOrder = action(async (orderId: string) => { * withErrorLogging() // Impossible with native using * await wrap(fetchOrder(orderId)) * }) * * // But framePromise works with the current action/atom frame! * // Helper functions can use parent's framePromise - powerful composition! * let withErrorLogging = () => { * framePromise().catch((error) => logger.error(error)) * } * export const processOrder = action(async (orderId: string) => { * withErrorLogging() // Helper uses the SAME action frame! * await wrap(fetchOrder(orderId)) * }) * * @returns Promise that resolves with the current frame's state * @see {@link https://github.com/tc39/proposal-explicit-resource-management} */ declare let framePromise: () => Promise; //#endregion //#region src/methods/getStackTrace.d.ts declare let isSkip: (target: AtomLike) => boolean; declare let getSerial: (frame?: Frame) => string; type Node = { name: string; children: Node[]; pubs: Frame['pubs']; }; /** * Concatenates a tree structure representation into a string format. * * This function recursively builds a formatted ASCII/Unicode tree * representation of a Node structure with proper branch indentation and * connections. * * @private */ declare let concatTree: (acc: string, prefix: string, indent: string, node: Node) => string; /** * Generates a formatted stack trace string based on the current execution * context. * * @private */ declare let getStackTrace: (frame?: Frame) => string; //#endregion //#region src/methods/ifChanged.d.ts declare let isChanged: (target: AtomLike) => boolean; /** * Executes a callback when an atom's state changes * * This utility evaluates if an atom's state has changed during the current * frame execution and calls the provided callback with the new state (and * optionally the previous state if available). * * @example * // Log when the user's name changes * ifChanged(userName, (newName, oldName) => { * console.log(`Name changed from ${oldName} to ${newName}`) * }) * * @template T - Type extending AtomLike * @param {T} target - The atom to monitor for changes * @param {(newState: AtomState, oldState?: AtomState) => void} cb - * Callback to execute when the atom changes * @throws {ReatomError} If target is not a reactive atom */ declare const ifChanged: (target: T, cb: (newState: AtomState, oldState?: AtomState, isFirst?: boolean) => void) => void; /** * Retrieves new action calls that occurred in the current batch. * * This utility function tracks action invocations and returns an array of new * calls that have been made during the current batch. It's particularly useful * for monitoring action activity within computed atoms or effects without * triggering side effects during the action execution itself. * * In a computed atom, the function compares the current action state with the * previous frame's state to determine which calls are new. If this is the first * time the action is being tracked, all current calls are considered new. * Otherwise, only calls that weren't present in the previous frame are * returned. If the computed triggered by some other dependent atom change, the * function may return an empty array. The past calls are not stored! * * @example * // Monitor API calls in an effect * const apiCall = action((endpoint: string) => fetch(endpoint), 'apiCall') * * effect(() => { * const newCalls = getCalls(apiCall) * newCalls.forEach(({ payload, params }) => { * console.log(`API called: ${params[0]}, Response:`, payload) * }) * }, 'apiMonitor') * * @template Params - Array type representing the action's parameter types * @template Payload - Type of the action's return value/payload * @param {Action} target - The action to monitor for new calls * @returns {{ payload: Payload; params: Params }[]} Array of new action calls, * each containing the action's payload (return value) and the parameters it * was called with * @throws {ReatomError} If target is a reactive atom instead of an action */ declare const getCalls: (target: Action) => Array<{ payload: Payload; params: Params; }>; //#endregion //#region src/methods/isCausedBy.d.ts /** * Determines if an atom is part of the causal chain leading to the current * computation * * This recursive function checks if the given atom has caused the current * computation by traversing the computation tree. It's useful for determining * dependencies and understanding the flow of state changes through your * application. * * @example * // Check if user atom changes caused the current computation * if (isCausedBy(userAtom)) { * console.log('This computation was triggered by user state change') * } * * @param {AtomLike} target - The atom to check if it's part of the causal chain * @param {number} [depth=Infinity] - The depth of the causal chain to check. * Default is `Infinity` * @param {Frame} [frame=top()] - The frame to check (defaults to the current * top frame). Default is `top()` * @returns {boolean} True if the target atom is part of the causal chain, false * otherwise */ declare let isCausedBy: (target: AtomLike, depth?: number, frame?: Frame, visited?: Set>) => boolean; //#endregion //#region src/methods/memo.d.ts /** * Internal utility for keyed memoization within an atom's execution context. * * Caches values by key within the current atom frame, creating the value on * first access and returning the cached value on subsequent calls. This enables * persistent memoization across multiple invocations of the same atom. * * The cache is scoped per-atom and persists across all calls to that atom * within the same context, making it suitable for creating internal computed * atoms or other resources that should be created once and reused. * * @example * // TODO cache * * @template T The type of value being cached * @param key Unique identifier for the cached value within the atom * @param create Factory function to create the value if not already cached * @returns The cached value, either newly created or retrieved from cache */ declare let memoKey: (key: string, create: () => T) => T; /** * Type representing the source of a function as a string. Used for caching and * identification purposes. */ type FunctionSource = string; /** * Memoize additional computation inside a different calls of an atom (computed * or an effect) or an action. * * It's useful when you want to avoid recomputing of the whole computed * function, especially if the computation is expensive. You could create an * external atom by yourself, but it is not handy sometimes. * * The `memo` function takes a callback function `cb` that returns the value to * be memoized, an optional `equal` function that compares the new and old * values to determine if the memoized value should be updated, and an optional * `key` to uniquely identify the memoized value. * * **Important note**: The created internal atom only uses the first passed * callback function. This means it's unsafe to rely on data from the closure * that changes on every recall, as subsequent calls will not update the * callback used by the internal atom. * * Note for rare cases: A created underhood atom is memorized for each memo by * the passed function sources from "toString()" method, so every computed * callback in different memos of the same atom should contain different code. * However, you can provide a custom `key` parameter to uniquely identify * different memo calls instead of relying on toString(). * * When a custom `key` is provided, the toString() duplication check is * bypassed, allowing you to use the same callback function multiple times * within the same atom by providing different keys for each usage. * * @example * // This is very useful to memoize not just the end string, * // but, for example, a template computation inside `reatomComponent` or so on. * export const listSum = computed(() => { * // Simple call of `list().length` will cause extra recomputations for elements sorting or its internal changes. * // correct optimal way, the component will rerender only on `length` change * const length = memo(() => list().length) * // you could call different `memo` many times in one computed * const sum = memo(() => list().reduce((acc, el) => acc + el().value, 0)) * * return `The sum of ${length} elements is: ${sum}` * }, 'listSum') * * @example * // An example of using the equality function as part of the logic * const scroll = atom(0, 'scroll') * const throttledScroll = computed(() => { * const { state } = memo( * () => ({ state: scroll(), time: Date.now() }), * // Only update if 50ms have passed since the last update * (next, prev) => prev.time + 50 < Date.now(), * ) * return state * }, 'throttledScroll') * * @example * // Using memo in actions for expensive computations * const processData = action((data: string[]) => { * // You can even create a service, but not one that is tied only to this action. * const myService = memo(() => new Service()) * * myService.send(data) * }, 'processData') * * @param cb A function that returns the value to be selected and memoized. * @param {function(State, State): boolean} [Object.is] An optional function to * compare the new and old states, useful for reactive context. If the memo * appears in reactive context (`computed`, `effect`) then before triggering * the host recomputation the returned value compares with the previous * returned value. This option defines the comparator algorithm. By default it * is a simple reference comparison (`Object.is`). * @param key An optional unique identifier for the memoized value. Defaults to * `cb.toString()`. Used to distinguish between different memo calls within * the same computed function. Providing a custom key is recommended when * using similar callback functions to avoid conflicts. * @returns The memoized value. */ declare let memo: (cb: (() => State) | ((state?: State) => State), equal?: (newState: State, oldState: State) => boolean, key?: string) => State; //#endregion //#region src/methods/peek.d.ts /** * Executes a callback in the current context without reactive bindings * (dependencies tracking) * * @example * // reset paging on search changes * effect(() => { * const searchState = search() * * // get page state without subscribing to it! * if (peek(page) > 1) peek(0) * }) * * @example * const query = atom('', 'query') * const someResource = computed( * async () => api.getSome(query()), * 'someResource', * ).extend(withAsyncData()) * * const tip = computed(() => { * if (!someResource.ready()) { * return 'Searching...' * } * * const list = someResource.data() * * if (list.length === 0) { * // no need to subscribe to the query changes! * return peek(query) ? 'Nothing found' : 'Try to search something' * } * * return `Found ${list.length} elements` * }) */ declare let peek: (cb: (...params: Params) => Result, ...params: Params) => Result; //#endregion //#region src/methods/reatomLens.d.ts type LensKey = string | number | symbol; type ResolveLensKey = Key extends Atom ? K : Key; type LensValue = T extends Map ? K extends MapKey ? MapValue | undefined : never : T extends ReadonlyArray ? K extends number ? V | undefined : never : K extends keyof T ? T[K] : never; /** * Creates a lens atom that provides focused access to a nested property within * a parent atom's state. * * A lens atom automatically tracks changes in the parent atom and provides * immutable updates back to the parent when modified. It supports objects, * arrays, and Maps. * * @example * // With an object * const userAtom = atom({ name: 'John', age: 30 }) * const nameAtom = reatomLens(userAtom, 'name') * nameAtom() // → 'John' * nameAtom.set('Jane') // Updates userAtom to { name: 'Jane', age: 30 } * * @example * // With an array * const listAtom = atom(['a', 'b', 'c']) * const firstAtom = reatomLens(listAtom, 0) * firstAtom() // → 'a' * firstAtom.set('x') // Updates listAtom to ['x', 'b', 'c'] * * @example * // With a Map * const mapAtom = atom(new Map([['key1', 'value1']])) * const valueAtom = reatomLens(mapAtom, 'key1') * valueAtom() // → 'value1' * valueAtom.set('value2') // Updates mapAtom with new Map * * @example * // With a dynamic atom key * const dataAtom = atom({ name: 'John', age: 30 }) * const fieldAtom = atom<'name' | 'age'>('name') * const valueAtom = reatomLens(dataAtom, fieldAtom) * valueAtom() // → 'John' * fieldAtom.set('age') * valueAtom() // → 30 * * @example * // With custom get/set functions * const dataAtom = atom({ nested: { deep: { value: 42 } } }) * const deepAtom = reatomLens(dataAtom, 'nested', { * get: (parent) => parent.nested?.deep?.value, * set: (parent, _, value) => ({ * ...parent, * nested: { * ...parent.nested, * deep: { ...parent.nested.deep, value }, * }, * }), * }) * * @template Parent - The type of the parent atom * @template Key - The key type to access the nested property * @param parent - The parent atom containing the state to lens into * @param key - The key to access the nested property (string for objects, * number for arrays, any for Maps) or an atom with the key state * @param options - Optional configuration with custom get/set functions * @param options.get - Custom function to extract the value from the parent * state. Defaults to parent[key] for objects/arrays or parent.get(key) for * Maps * @param options.set - Custom function to immutably update the parent state. * Defaults to creating new objects/arrays/Maps with the updated value * @param name - Optional name for the lens atom. Defaults to * `${parent.name}.${key}` where atom keys use the key atom name * @returns A lens atom that tracks and updates the parent atom's nested * property */ declare const reatomLens: , Key extends LensKey | Atom, ResolvedKey extends ResolveLensKey & LensKey = ResolveLensKey & LensKey, Value = LensValue, ResolvedKey>>(parent: Parent, key: Key, options?: { get?: (parent: AtomState, key: ResolvedKey) => Value; set?: (parent: AtomState, key: ResolvedKey, value: Value) => AtomState; }, name?: string) => Atom; //#endregion //#region src/methods/reatomObservable.d.ts interface ProducerObject { initState?: T; getState?: () => T; next?: (state: T) => void; subscribe?: (fn: (state: T) => void) => MaybeUnsubscribe; } type Producer = ProducerObject | ((trigger: Fn) => ProducerObject); /** * Extends an existing atom to synchronize with an observable-like data source. * * @template Target - The type of the atom being extended * @param _producer - Either an object with optional `initState`, `getState`, * `next`, and `subscribe` fields, or a function that receives a `trigger` * callback and returns such an object. * @returns An extension function that adds observable synchronization to an * atom */ declare const withObservable: (producer: Producer>) => Ext; /** * Creates a Reatom atom from an observable-like data source. * * The atom will automatically subscribe to the observable when it gains * subscribers and unsubscribe when it loses all subscribers. * * Producer fields: * * - `initState` — static initial value * - `getState` — pull current value from the external source * - `next` — called when the atom is set, to push values back to the source * - `subscribe` — called on connect, receives a callback to push values into the * atom * * Function-based producers receive a `trigger` callback that re-reads * `getState`. * * @template T - The type of values * @param producer - Object or function returning an object with optional * `initState`, `getState`, `next`, and `subscribe` fields * @param name - Optional debug name * @returns A Reatom atom synchronized with the external source */ declare function reatomObservable(producer: { initState?: T; getState: () => T; next?: (state: T) => void; subscribe?: (fn: (state: T) => void) => MaybeUnsubscribe; } | ((trigger: Fn) => { initState?: T; getState: () => T; next?: (state: T) => void; subscribe?: (fn: (state: T) => void) => MaybeUnsubscribe; }), name?: string): Atom; declare function reatomObservable(producer: { initState: T; getState?: () => T; next?: (state: T) => void; subscribe?: (fn: (state: T) => void) => MaybeUnsubscribe; } | ((trigger: Fn) => { initState: T; getState?: () => T; next?: (state: T) => void; subscribe?: (fn: (state: T) => void) => MaybeUnsubscribe; }), name?: string): Atom; declare function reatomObservable(producer: { initState?: never; getState?: never; subscribe: (fn: (state: T) => void) => MaybeUnsubscribe; } | ((trigger: Fn) => { initState?: never; getState?: never; subscribe: (fn: (state: T) => void) => MaybeUnsubscribe; }), name?: string): Atom; //#endregion //#region src/methods/retry.d.ts /** * Removes all computed atom dependencies. Useful for resources / effects * invalidation. * * Note that this method not recall and recompute the atom, it only throws it's * deps. Use `retryComputed` to reevaluate the computed. * * @param target - The reactive atom whose dependencies should be reset. * @throws {ReatomError} If the target is an action. */ declare const reset: (target: T) => void; /** * Retries computed atom by resetting its dependencies and re-evaluating the * computed function . * * @template T - The return type of the atom. * @param target - The atom to retry. * @returns The result of the atom after retrying. * @throws {ReatomError} If the target is not an action. */ declare const retryComputed: { (target: Action): never; (target: AtomLike): T; }; //#endregion //#region src/methods/schedule.d.ts /** * Schedule a callback to execute after all current computations complete. * * The callback is added to the specified queue ("effect" by default) and * processes alongside subscription callbacks and other side effects. This * method respects wrap and abortVar policies. * * @param fn - Callback function to execute * @param queue - Queue type to schedule in (default: "effect") * @returns Promise that resolves with the callback's return value */ declare let schedule: (fn: () => T, queue?: QueueKind) => Promise; //#endregion //#region src/methods/take.d.ts /** * Awaits the next update of an atom or call of an action. * * This function returns a Promise that resolves when the specified atom's state * changes or when the specified action is called. This is valuable for * orchestrating workflows that depend on future state changes or action calls. * * Note: Must be used with `wrap()` when used in an async context to preserve * reactive context. * * @example * // Wait for form validation before proceeding * const submitWhenValid = action(async () => { * while (true) { * const currentData = formData() * const error = validate(currentData) * if (!error) break // Exit loop if valid * * formData({ ...currentData, error }) // Show error * * // Wait for the next change in formData - need wrap() to preserve context * await wrap(take(formData)) * } * // Now formData is valid, proceed with submission... * }) * * @template T - The type of value expected when the promise resolves * @param target - The atom or action to wait for * @param name - Optional name for debugging purposes * @returns A promise that resolves with the next value of the atom or action * result */ declare function take(target: AtomLike | (() => Return), name?: string): Promise>; /** * Awaits the next update of the target AtomLike and maps the result. If the map * function executes synchronously without throwing, its result is returned * directly. Otherwise, a promise is returned. * * @template Return The type of the awaited value from the target. * @template Result The type of the mapped result. * @param target The AtomLike to await. * @param map A function to map the awaited value. * @param name Optional name for debugging. * @returns The mapped result or a promise that resolves with the mapped result. */ declare function take(target: AtomLike | (() => Return), map: (value: Awaited) => Result, name?: string): Result | Promise; //#endregion //#region src/methods/transaction.d.ts type Rollbacks = Array; /** * Extension result for actions that use `withTransaction`. * * Adds a `rollback` method to manually trigger rollback for the last action * call. */ interface TransactionExt { /** * Rollback action that executes all collected rollback functions from the * last call of this action. * * Each action call has its own rollback scope. Calling `rollback()` only * reverts changes from the most recent call, not all previous calls. * * @example * const counter = atom(0, 'counter').extend(withRollback()) * * const increment = action(() => { * counter.set((n) => n + 1) * }, 'increment').extend(withTransaction()) * * increment() // counter: 1 * increment.rollback() // counter: 0 * * @param {any} [error] - Optional error that triggered the rollback */ rollback: Action<[error?: any], void>; /** * Stop action that clears all collected rollback functions from the last call * of this action without executing them. * * Use this when you want to "commit" the transaction and prevent any future * rollback from reverting the changes. * * @example * const todos = atom([], 'todos').extend(withRollback()) * * const addTodo = action(async (todo: Todo) => { * todos.set((list) => [...list, todo]) // optimistic update * await wrap(api.saveTodo(todo)) * addTodo.stop() // success - commit the change, prevent rollback * }, 'addTodo').extend(withAsync(), withTransaction()) * * // On success: stop() prevents rollback from todos hooks or other code, todo stays in the list * // On failure: withTransaction() auto-rollbacks, todo is removed */ stop: Action<[], void>; } interface TransactionVariable extends Variable { /** * Extension to schedule state restoration for atoms when `rollback()` is * called within the same transaction context. * * This extension tracks state changes on atoms and registers rollback * functions that restore the previous state when the transaction's `rollback` * action is invoked. The rollback functions are executed in reverse order * (LIFO) to properly unwind nested state changes. * * **When to use:** * * - For atoms that participate in optimistic updates * - When you need automatic state restoration on transaction failure * - In combination with `withTransaction` on actions that may fail * * **How it works:** * * 1. When the atom's state changes, the previous state is captured * 2. A rollback function is registered in the current transaction * 3. If `rollback()` is called, all registered functions execute in reverse * order * 4. Changes caused by `rollback()` itself don't register new rollback functions * * @example * const counter = atom(0, 'counter').extend( * withRollback(), // Schedule state restoration for rollback() * ) * * const increment = action(() => { * counter.set((n) => n + 1) * }, 'increment').extend(withTransaction()) * * increment() // counter: 1 * increment.rollback() // counter: 0 * * @example * // Optimistic update pattern with automatic rollback * const list = atom([], 'list').extend( * withChangeHook(saveList), // Trigger save on change * withRollback(), // Restore on failure * ) * * const saveList = action(async () => { * await api.save(list()) * }, 'saveList').extend(withAsync(), withTransaction()) * * @example * // Custom rollback transformation for list state * const list = atom([], 'list').extend( * withRollback({ * onRollback: ({ beforeState, currentState, transactionState }) => { * // Remove only the items that were added in the rolled-back change * const addedItems = transactionState.filter( * (item) => !beforeState.includes(item), * ) * return currentState.filter((item) => !addedItems.includes(item)) * }, * }), * ) * * @returns Extension function to be used with `.extend()` on atoms * @see {@link withTransaction} For handling errors in actions and triggering * rollback */ withRollback(options?: { /** * Custom state transformation function called during rollback. * * Use this when the default rollback behavior (restore to `beforeState` * only if `currentState === transactionState`) doesn't fit your needs. * * @default * ({ beforeState, currentState, transactionState }) => * Object.is(currentState, transactionState) ? beforeState : currentState * @param params.beforeState - State before the change in transaction * @param params.transactionState - State after the change in transaction * @param params.currentState - Current state at the time rollback executes * @returns The state to set after rollback */ onRollback?: Rollback>; }): Ext; /** * Extension to handle errors in actions and automatically call `rollback()`. * Also adds a `rollback` method to the action for manual rollback. * * Each action call has its own rollback scope. The `action.rollback()` method * only reverts changes from the most recent call. * * **How it works:** * * - For actions with `withAsync()`: hooks into `onReject` to call `rollback()` * - For plain actions returning promises: catches rejections and calls * `rollback()` * - For synchronous errors: catches and calls `rollback()`, then re-throws * - Abort errors are ignored (they don't trigger rollback) * - Optional `shouldRollback` callback filters which errors trigger rollback * (by default all non-Abort errors trigger rollback) * * @example * const counter = atom(0, 'counter').extend(withRollback()) * * const increment = action(() => { * counter.set((n) => n + 1) * }, 'increment').extend(withTransaction()) * * increment() // counter: 1 * increment.rollback() // counter: 0 * * @example * // Optimistic update with automatic rollback on failure * const todos = atom([], 'todos').extend(withRollback()) * * const saveTodos = action(async () => { * todos.set((list) => [...list, optimisticTodo]) * await api.save(todos()) * }, 'saveTodos').extend(withAsync(), withTransaction()) * * saveTodos() // On failure, todos will rollback automatically * * @example * // Only rollback on network errors, not validation errors * const save = action(async () => { ... }, 'save').extend( * withAsync(), * withTransaction({ * shouldRollback: (error) => error instanceof NetworkError, * }), * ) * * @see {@link withRollback} For scheduling atom state restoration */ withTransaction(options?: { /** * Filter which errors should trigger rollback. When omitted, all non-Abort * errors trigger rollback. */ shouldRollback?: (error: unknown) => boolean; }): (target: Target) => TransactionExt; /** * Executes all collected rollback functions in the current transaction * context. * * This action processes the rollback queue in reverse order (LIFO - Last In, * First Out), ensuring that nested state changes are properly unwound. After * execution, the rollback queue is cleared. * * **Important:** This action looks for the transaction variable in the * current frame stack. If called outside of an action's frame context (where * `withRollback` atoms were modified), it won't find any rollbacks. Use * `action.rollback()` from actions extended with `withTransaction()` for * manual rollback from outside the action context. * * **Behavior:** * * - Only affects rollbacks registered in the current transaction context * - Executes rollbacks in reverse registration order * - Clears the rollback queue after execution * - Safe to call when no rollbacks are registered (no-op) * - Accepts an optional error parameter for logging/debugging purposes * * @example * // Rollback from within an action (works because same frame context) * const draft = atom('', 'draft').extend(withRollback()) * * const updateAndValidate = action((text: string) => { * draft.set(text) * if (text.length < 3) { * rollback() // Works: same frame context * } * }, 'updateAndValidate').extend(withTransaction()) * * @example * // Manual rollback from outside action (use action.rollback()) * const counter = atom(0, 'counter').extend(withRollback()) * * const increment = action(() => { * counter.set((n) => n + 1) * }, 'increment').extend(withTransaction()) * * increment() * increment.rollback() // Use action.rollback() for external rollback * * @param {any} [error] - Optional error that triggered the rollback (for * debugging) */ rollback: Action<[error?: any], void>; } type Rollback = ({ beforeState, currentState, transactionState }: { beforeState: State; currentState: State; transactionState: State; }) => State; /** * Default rollback strategy for `withRollback` extension. * * This function determines what state to restore when a rollback occurs. It * only restores the `beforeState` if the `currentState` hasn't changed since * the transaction started (i.e., `currentState === transactionState`). If the * state was modified after the transaction, it preserves the current state to * avoid overwriting unrelated changes. * * @param params.beforeState - State before the change in transaction * @param params.transactionState - State after the change in transaction * @param params.currentState - Current state at the time rollback executes * @returns The state to set after rollback * @see {@link reatomTransaction} To customize the default rollback for a * transaction scope * @see {@link withRollback} To customize rollback per-atom via `onRollback` * option */ declare let defaultRollback: Rollback; /** * Creates an isolated transaction context with rollback capabilities. * * Use this to create feature-specific transaction scopes. For most cases, use * the global `withRollback` and `withTransaction` exports instead. * * @example * // Create a custom transaction scope for a specific feature * const formTransaction = reatomTransaction({ name: 'form' }) * * const formData = atom({ name: '', email: '' }, 'formData').extend( * formTransaction.withRollback(), * ) * * const submitForm = action(async () => { * // ... form submission logic * }, 'submitForm').extend(withAsync(), formTransaction.withTransaction()) * * @example * // Custom default rollback strategy for all atoms in the scope * const alwaysRestoreTransaction = reatomTransaction({ * name: 'alwaysRestore', * defaultRollback: ({ beforeState }) => beforeState, // Always restore * }) * * @param options.name - Unique name for the transaction scope (used in debug) * @param options.defaultRollback - Custom rollback strategy applied to all * atoms using `withRollback()` from this transaction scope. Defaults to * {@link defaultRollback} which only restores state if it hasn't changed since * the transaction. Can be overridden per-atom via the `onRollback` option in * `withRollback()`. * @returns Transaction variable with `withRollback`, `withTransaction`, and * `rollback` methods * @see {@link defaultRollback} The default rollback strategy * @see {@link withRollback} Extension for atoms * @see {@link withTransaction} Extension for actions */ declare let reatomTransaction: ({ defaultRollback: onRollbackDefault, name }: { /** * Unique name for the transaction scope. * * Used for debugging and identifying transaction contexts. */ name: string; /** * Custom rollback strategy applied to all atoms using `withRollback()` from * this transaction scope. * * @default defaultRollback * @see {@link defaultRollback} */ defaultRollback?: Rollback; }) => TransactionVariable; /** * Global transaction variable instance. * * @see {@link reatomTransaction} To create isolated transaction contexts */ declare let transactionVar: TransactionVariable; /** @see {@link TransactionVariable.withRollback} */ declare let withRollback: (options?: { /** * Custom state transformation function called during rollback. * * Use this when the default rollback behavior (restore to `beforeState` * only if `currentState === transactionState`) doesn't fit your needs. * * @default * ({ beforeState, currentState, transactionState }) => * Object.is(currentState, transactionState) ? beforeState : currentState * @param params.beforeState - State before the change in transaction * @param params.transactionState - State after the change in transaction * @param params.currentState - Current state at the time rollback executes * @returns The state to set after rollback */ onRollback?: Rollback>; }) => Ext; /** @see {@link TransactionVariable.withTransaction} */ declare let withTransaction: (options?: { /** * Filter which errors should trigger rollback. When omitted, all non-Abort * errors trigger rollback. */ shouldRollback?: (error: unknown) => boolean; }) => (target: Target) => TransactionExt; /** @see {@link TransactionVariable.rollback} */ declare let rollback: Action<[error?: any], void>; //#endregion //#region src/methods/wrap.d.ts /** * Preserves Reatom's reactive context across async boundaries or function * calls. * * This is a CRITICAL function in Reatom that ensures proper context tracking * across asynchronous operations like Promises, setTimeout, event handlers, and * more. Without proper wrapping, atoms would lose their context after async * operations, leading to "Missed context" errors when attempting to update * state. * * Wrap handles two scenarios: * * 1. Function wrapping: Returns a new function that preserves context when called * 2. Promise wrapping: Returns a new promise that preserves context through its * chain * * @example * // Wrapping a function (e.g., an event handler) * button.addEventListener( * 'click', * wrap(() => { * counter((prev) => prev + 1) // Works, context preserved * }), * ) * * // Wrapping async operations * action(async () => { * const response = await wrap(fetch('/api/data')) * const data = await wrap(response.json()) * results(data) // Works, context preserved * }) * * @template Params - The parameter types when wrapping a function * @template Payload - The return type when wrapping a function * @template T - The promise type when wrapping a promise * @param target - The function or promise to wrap with context preservation * @param frame - The frame to use (defaults to the current top frame) * @returns A wrapped function or promise that preserves reactive context * @see {@link https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextsnapshotwrap} */ declare let wrap: { (target: (...params: Params) => Payload, frame?: Frame): (...params: Params) => Payload; (target: T, frame?: Frame): Promise>; }; //#endregion //#region src/core/atom.d.ts /** * Metadata associated with an atom instance that controls its behavior and * lifecycle. This interface is used internally by the Reatom framework and * should not be accessed directly in application code. */ interface AtomMeta { /** * Indicates whether the atom is reactive. Set to false for actions or the * context atom. */ readonly reactive: boolean; /** * Middleware chain: `[setup.computed ?? identity, ...middlewares]`. * Subsequent elements are middleware wrapping from inner to outer. DO NOT * change this array directly, use `extend` instead. */ readonly middlewares: Array; /** * Function called when the atom gains its first subscriber. `onConnect.abort` * called when the atom loses its last subscriber. */ onConnect: undefined | (Action & AbortExt); } /** * Base atom interface for other userspace implementations. This is the core * interface that all atom-like objects implement, providing the foundation for * Reatom's reactivity system. * * @template State - The type of state stored in the atom * @template Payload - The return type when the atom is called */ interface AtomLike { /** * Call the atom to either read or update its state. * * @param params - Parameters to pass to the atom * @returns The atom's payload (typically its current state) */ (...params: Params): Payload; set: unknown; /** * Extension system to add capabilities to atoms. Allows adding middleware, * methods, or other functionality to modify atom behavior. */ extend: Extend; /** * Subscribe to state changes, with the first call happening immediately. When * a subscriber is added, the callback is immediately invoked with the current * state. After that, it's called whenever the atom's state changes. * * @param cb - Callback function that receives the atom's state when it * changes * @returns An unsubscribe function that removes the subscription when called */ subscribe: (cb?: (payload: Payload) => any) => Unsubscribe; toJSON: () => unknown; /** Reference to the atom's internal metadata. */ __reatom: AtomMeta; /** @deprecated Internal flag ONLY for type inference, no runtime use */ __state?: State; } /** * Base changeable state container. * * Atom is the core primitive for storing and updating mutable state in Reatom. * It can be called to retrieve its current state or update it with a new value * or update function. * * @template State - The type of state stored in the atom */ interface Atom extends AtomLike { /** * Update the atom's state using a function that receives the previous state * * @param update - Function that takes the current state and returns a new * state * @returns The new state value */ set(update: (state: State) => State): State; /** * Set the atom's state to a new value * * @param newState - The new state value * @returns The new state value */ set(...params: Params): State; } /** * Derived state container. * * A computed atom automatically tracks dependencies and recalculates only when * those dependencies change. The calculation is performed lazily, only when the * computed value is read AND subscribed to. * * @template State - The type of derived state */ interface Computed extends AtomLike {} /** * Call stack snapshot for an atom or action execution. * * Frames represent the execution context of an atom at a specific point in a * call stack, tracking its current state, error status, and dependencies. * * @template State - The state type of the atom * @template Params - The parameter types the atom accepts * @template Payload - The return type when the atom is called * @see https://github.com/tc39/proposal-async-context */ interface Frame { /** Error that occurred during atom evaluation, or null if successful */ error: null | NonNullable; /** Current state of the atom */ state: State; 'var#abort': undefined | ReatomAbortController; /** Reference to the atom itself */ readonly atom: AtomLike; /** * Immutable list of dependencies. The first element is actualization flag and * an imperative write cause. Subsequent elements are the atom's * dependencies. */ pubs: [actualization: null | Frame, ...dependencies: Array]; /** Array of atoms that depend on this atom (subscribers). */ readonly subs: Array; /** * Run the callback in this context. DO NOT USE directly, use `wrap` instead * to preserve context correctly. * * @param fn - Function to execute in this context * @param params - Parameters to pass to the function * @returns The result of the function call */ run(fn: (...params: I) => O, ...params: I): O; /** The root frame state with all meta information */ readonly root: RootState; [key: `var#${string}`]: unknown; } /** * Helper type to extract the state type from an atom-like object. * * @template T - The atom-like type to extract the state from */ type AtomState = T extends AtomLike ? State : never; type AtomParams = T extends AtomLike ? Params : never; /** Task queue for scheduled operations. */ interface Queue extends Array {} /** * Atom's state mappings for context. * * The Store maps atoms to their frames in the current context, allowing atoms * to retrieve their state and dependencies. */ interface Store extends WeakMap { /** * Get the frame for an atom in the current context. * * @param target - The atom to get the frame for * @returns The frame for the atom, or undefined if not found */ get(target: AtomLike): undefined | Frame; /** * Set the frame for an atom in the current context. * * @param target - The atom to set the frame for * @param frame - The frame to associate with the atom * @returns This store instance */ set(target: AtomLike, frame: Frame): this; } /** * Reatom's execution context that manages reactive state. * * The context handles tracking relationships between atoms, scheduling * operations, and maintaining the execution stack during Reatom operations. */ interface RootState { /** Store that maps atoms to their frames in this context. */ store: Store; /** Frame history. */ frames: WeakMap; /** Initialization flags for init hooks. */ inits: WeakMap; /** Cache for in atom keyed memoization. */ memoKey: WeakMap; /** Queue for hook callbacks to be executed. */ hook: Queue; /** Queue for computation callbacks to be executed. */ compute: Queue; /** Queue for cleanup callbacks to be executed. */ cleanup: Queue; /** Queue for effect callbacks to be executed. */ effect: Queue; /** * Add a callback to a specific queue for later execution. * * @param cb - Callback function to schedule * @param queue - Queue to add the callback to */ pushQueue(cb: Fn, queue: 'hook' | 'compute' | 'cleanup' | 'effect'): void; /** Link to itself frame for internal use */ frame: RootFrame; } /** Special frame type for the context atom. */ interface RootFrame extends Frame {} /** * Atom interface for the context atom. Provides methods to start new isolated * contexts. */ interface ContextAtom extends AtomLike { /** * Start a new isolated context and run a callback within it. * * @param cb - Function to execute in the new context * @returns The result of the callback */ start(cb: () => T): T; /** * Start a new isolated context. * * @returns The new context frame */ start(): RootFrame; /** * Reset the context to throw away all accumulated states and related meta. * Aborts `wrap`ed effects too. Useful for tests, storybook, user logout and * so on. * * Note that Reatom has `clearStack` and `context.start` to scope the context * very strictly. `reset` is useful if you playing with the default global * context. * * @example * import { atom, context } from '@reatom/core' * import { describe, test, beforeEach, expect } from 'vitest' * * import { counter, doubled } from './my-feature' * * describe('My feature', () => { * // Useful in test cleanup when user code is not strictly scoped with `clearStack` * beforeEach(() => { * context.reset() * }) * * test('counter increments', () => { * counter.set(5) * expect(doubled()).toBe(10) * }) * * test('default counter', () => { * // State is reset between tests, so counter starts at 0 * expect(doubled()).toBe(0) * }) * }) */ reset(): void; } declare class ReatomError extends Error {} declare let EXTENSIONS: Array; declare let __GLOBAL_ATOMS: AtomLike[]; declare let STACK: Frame[]; declare function run(this: Frame, fn: (...params: I) => O, ...params: I): O; /** @private */ declare let _copy: (frame: Frame) => Frame; declare let isAtom: (value: any) => value is AtomLike; declare let isWritableAtom: (value: any) => value is Atom; declare let _mark: (frame: Frame) => void; /** * Checks if an atom has active subscriptions. * * This function determines if an atom is currently connected to any * subscribers, which indicates that the atom is being actively used somewhere * in the application. This is useful for optimizations or conditional logic * based on whether an atom's changes are being observed. * * @param anAtom - The atom to check for subscriptions * @returns `true` if the atom has subscribers, `false` otherwise */ declare let isConnected: (anAtom: AtomLike) => boolean; declare function assertFn(fn: unknown): asserts fn is Fn; declare let _trackAction: (target: Action, parentFrame: Frame) => Frame; declare let named: { (name: T): `${T}#${number}`; (name: string, suffix: string): string; (name: string | TemplateStringsArray, suffix?: string): string; }; /** * Registers a global extension that will be automatically applied to all atoms * and actions created after registration. * * This function allows you to add behavior to all Reatom entities in your * application, such as tracking, logging, analytics, or debugging capabilities. * Extensions registered with this function will be applied before any local * extensions defined on individual atoms. * * @example * import { addGlobalExtension, isAction, withCallHook } from '@reatom/core' * * // Track all action calls for analytics * addGlobalExtension((target) => { * if (isAction(target)) { * target.extend(withCallHook(console.log)) * } * return target * }) * * @param extension - Extension function that receives an atom or action and * returns it (optionally modified) */ declare let addGlobalExtension: (extension: Ext) => void; /** This MUTATES frame.pubs */ declare function _isPubsChanged(frame: Frame, pubs: Frame['pubs'], from: number): boolean; /** The hurt of atom internal logic */ declare function computedMiddleware(next: Fn, ...args: any[]): any; /** Cache checking middleware, placed in every atom's middlewares */ declare function cacheMiddleware(next: Fn, ...args: any[]): any; /** * Useful for security reasons, if you need to increase your runtime complexity. * It's important to call this function before creating any atoms. */ declare let anonymizeNames: () => void; declare let _set: (target: AtomLike, ...params: any[]) => any; declare class AtomInitState { initState: Fn; constructor(initState: Fn); } declare let createAtom: { (setup: { initState: State | (() => State); computed: (prev: State) => State; middlewares?: Fn[]; }, name?: string): Atom; (setup: { initState?: State | (() => State); computed?: (() => State) | ((state?: State) => State); middlewares?: Fn[]; }, name?: string): Atom; }; /** * Creates a mutable state container. * * The atom is the core primitive for storing and updating mutable state in * Reatom. Atoms can be called as functions to read their current value or to * update the value. * * @example * // Create with initial value * const counter = atom(0, 'counter') * * // Read current value * const value = counter() // -> 0 * * // Update with new value * counter.set(5) // Sets value to 5 * * // Update with a function * counter.set((prev) => prev + 1) // Sets value to 6 * * @template T - The type of state stored in the atom * @param createState - A function that returns the initial state, or the * initial state value directly * @param name - Optional name for the atom (useful for debugging) * @returns An atom instance containing the state */ declare let atom: { (): Atom; (createState: () => T, name?: string): Atom; (initState: T, name?: string): Atom; }; declare function computedParamsMiddleware(next: Fn, ...args: any[]): any; /** * Creates a derived state container that lazily recalculates only when read. * * Computed atoms automatically track their dependencies (other atoms or * computed values that are called during computation) and only recalculate when * those dependencies change. The computation is lazy - it only runs when the * computed value is read AND subscribed to. * * @example * const counter = atom(5, 'counter') * const doubled = computed(() => counter() * 2, 'doubledCounter') * * // Reading triggers computation only if subscribed * const value = doubled() // -> 10 * * @template State - The type of state derived by the computation * @param computed - A function that computes the derived state * @param name - Optional name for debugging purposes * @returns A computed atom instance */ declare let computed: (computed: (() => State) | ((state?: State) => State), name?: string) => Computed; /** * Checks if the provided target is a READONLY computed atom * * @param target - The atom to check * @returns Boolean */ declare let isComputed: (target: AtomLike) => boolean; /** * Core context object that manages the reactive state context in Reatom. * * The context is responsible for tracking dependencies between atoms, managing * computation stacks, and ensuring proper reactivity. It serves as the * foundation for Reatom's reactivity system and provides access to the current * context frame. * * @returns The current context frame * @throws {ReatomError} If called outside a valid context (broken async stack) */ declare let context: ContextAtom; /** * Reads the current frame for an atom from the context store. * * This internal utility function retrieves the frame associated with an atom * from the current context. It's used to access an atom's state and * dependencies without triggering reactivity or creating new dependencies. * * @private * @template State - The state type of the atom * @template Params - The parameter types the atom accepts * @template Payload - The return type when the atom is called * @param target - The atom to read the frame for * @returns The frame for the atom if it exists in the current context, or * undefined otherwise */ declare let _read: (target: AtomLike) => undefined | Frame; /** * Gets the current top frame in the Reatom context stack. * * Returns the currently active frame in the execution stack, which contains the * current atom being processed and its state. * * @returns The current top frame from the context stack * @throws {ReatomError} If the context stack is empty (missing async stack) */ declare let top: () => Frame; /** * Clears the current Reatom context stack. * * This is primarily used to force explicit context preservation via `wrap()`. * By clearing the stack, any atom operations outside of a properly wrapped * function will throw "missing async stack" errors, ensuring proper context * handling. */ declare let clearStack: () => void; /** * Light version of `wrap` that binds a function to the current reactive * context. * * Unlike the full `wrap` function, `bind` does not follow abort context, making * it more lightweight but less safe for certain async operations. Use this when * you need to preserve context but don't need the abort handling capabilities * of `wrap`. * * @template Params - The parameter types of the target function * @template Payload - The return type of the target function * @param target - The function to bind to the reactive context * @param frame - The frame to bind to (defaults to the current top frame) * @returns A function that will run in the specified context when called */ declare let bind: (target: (...params: Params) => Payload, frame?: Frame) => ((...params: Params) => Payload); /** * Mocks an atom or action for testing purposes. * * This function replaces the original behavior of an atom or action with a * custom callback function for the duration of the mock. This is useful for * isolating units of code during testing and controlling their behavior. * * @template Params - The parameter types of the target atom/action * @template Payload - The return type of the target atom/action * @param target - The atom or action to mock * @param cb - The callback function to use as the mock implementation. It * receives the parameters passed to the mocked atom/action and should return * the desired payload. * @returns A function that, when called, removes the mock and restores the * original behavior. */ declare let mock: (target: AtomLike, cb: (...params: Params) => Payload) => Unsubscribe; //#endregion //#region src/core/extend.d.ts /** * Extension function interface for modifying atoms and actions. * * Extensions are functions that take an atom/action as input and return either * the same atom/action with modified behavior or an object with additional * properties to be assigned to the atom/action. * * @template Target - The type of atom or action the extension can be applied to * @template Extension - The type that will be returned after applying the * extension */ interface Ext { (target: Target): Extension; } /** * Extension that preserves the exact type of the target atom/action. * * This specialized extension type ensures that when applied to an atom or * action, the complete original type information is preserved, including all * generic parameters. * * @template Target - The type of atom or action the extension can be applied to */ interface GenericExt { (target: T): T; } /** * Extension that assigns additional methods to an atom/action. * * This extension type is used for adding methods or properties to atoms or * actions without modifying their core behavior. * * @template Methods - Record of methods/properties to be added to the target * @template Target - The type of atom or action the extension can be applied to */ interface AssignerExt { (target: T): Methods; } /** * Helper type for merging an atom/action with a series of extensions. * * This type recursively merges a target with each extension in an array. * * @template Target - The base atom or action type * @template Extensions - Array of extension results to merge with the target */ type Merge> = Extensions extends [] ? Target : Extensions extends [infer E, ...infer Rest extends Array] ? Merge : never; /** * Method signature for the extend functionality on atoms and actions. * * This interface defines the overload signatures for the extend method, * supporting different numbers of extensions with proper type inference. * * @template This - The atom or action type being extended */ interface Extend { (extension1: Ext): Merge; (extension1: Ext, extension2: Ext, T2>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>, extension6: Ext, T6>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>, extension6: Ext, T6>, extension7: Ext, T7>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>, extension6: Ext, T6>, extension7: Ext, T7>, extension8: Ext, T8>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>, extension6: Ext, T6>, extension7: Ext, T7>, extension8: Ext, T8>, extension9: Ext, T9>): Merge; (extension1: Ext, extension2: Ext, T2>, extension3: Ext, T3>, extension4: Ext, T4>, extension5: Ext, T5>, extension6: Ext, T6>, extension7: Ext, T7>, extension8: Ext, T8>, extension9: Ext, T9>, extension10: Ext, T10>): Merge; >>(...extensions: T): { extend_ERROR: 'To many overloads (separate it to a few `extend` calls) or some extensions has incompatible types'; } & AtomLike; } /** * Applies extensions to atoms or actions. * * This is the core extension mechanism in Reatom that allows adding * functionality to atoms and actions. Extensions can add properties, methods, * or modify behavior. Extended atoms maintain their original reference * identity. * * @example * // Extending an atom with reset capability * const counter = atom(0, 'counter').extend( * withReset(0), // Adds counter.reset() method * withLogger('COUNTER'), // Adds logging middleware * ) * * @template This - The type of atom or action being extended * @param extensions - Array of extensions to apply to the atom/action * @returns The original atom/action with extensions applied */ declare function extend(this: This, ...extensions: Array): This; /** * Type representing a middleware function for atoms and actions. * * Middleware functions intercept atom/action calls, allowing for custom * behavior to be applied before or after the normal execution. They receive the * next middleware function in the chain and the parameters passed to the * atom/action. * * @template Target - The atom or action type the middleware applies to * @param next - The next middleware function in the chain or the original * atom/action handler * @param params - The parameters passed to the atom/action * @returns The state resulting from the atom/action execution */ type Middleware = (next: (...params: Target extends Atom ? OverloadParameters | [] : OverloadParameters) => AtomState, ...params: OverloadParameters) => AtomState; /** * Creates an extension that adds middleware to an atom or action. * * Middleware allows intercepting and modifying the execution flow of atoms and * actions. This is the fundamental mechanism for creating behavior extensions * in Reatom. * * @example * // Creating a logging middleware extension * const withLogger = (prefix: string) => * withMiddleware((target) => { * return (next, ...params) => { * console.log(`${prefix} [${target.name}] Before:`, params) * const result = next(...params) * console.log(`${prefix} [${target.name}] After:`, result) * return result * } * }) * * // Using the middleware * const counter = atom(0).extend(withLogger('DEBUG')) * * @template Target - The type of atom or action the middleware will be applied * to * @template Result - The resulting type after applying the middleware * @param cb - A function that receives the target and returns a middleware * function * @param place - Where to insert the middleware: "invalidation" (default), * "read", or "computed". "computed" runs inside the computed middleware so * all atoms read are reactive. * @returns An extension that applies the middleware when used with .extend() */ type MiddlewarePlace = 'invalidation' | 'read' | 'computed'; declare let withMiddleware: { (cb: (target: Target) => Middleware, place?: MiddlewarePlace): GenericExt; (cb: (target: Target) => Middleware, place?: MiddlewarePlace): Ext; }; /** * Creates an extension that allows observing state changes without modifying * them. * * This extension adds a middleware that calls the provided callback function * whenever the atom's state changes, passing the target atom, new state, and * previous state. This is useful for side effects like logging, analytics, or * debugging. * * @example * const counter = atom(0, 'counter').extend( * withTap((target, state, prevState) => { * console.log(`${target.name} changed from ${prevState} to ${state}`) * }), * ) * * @param cb - Callback function that receives the target, new state, and * previous state * @returns An extension that can be applied to atoms or actions */ declare let withTap: (cb: (target: Target, state: AtomState, prevState: AtomState) => void) => Ext; /** * Extension for customizing parameter handling in atoms and actions. * * This extension type allows transforming the parameters an atom or action * accepts, enabling custom parameter parsing, validation, or transformation. * * @template Target - The atom or action type being extended * @template Params - The new parameter types the atom/action will accept */ interface ParamsExt { (target: Target): (Target extends Action ? ActionParams extends [any] ? Action : { withParams_ERROR: 'Target has too many params'; } & Action : Target extends Atom ? Atom : AtomLike, [] | Params>) & { [K in Exclude]: Target[K] }; } /** * Extension that transforms parameters before they reach the atom or action. * Useful as the `.set` atom method can't be reassigned and changed. * * This utility lets you change how parameters are processed when an atom or * action is called, enabling custom parameter handling, validation, or * transformation. * * @example * // Convert from any unit to meters * const length = atom(0, 'length').extend( * withParams((value: number, unit: 'cm' | 'm' | 'km') => { * switch (unit) { * case 'cm': * return value / 100 * case 'm': * return value * case 'km': * return value * 1000 * default: * return value * } * }), * ) * * length(5, 'km') // Sets value to 5000 meters * * @template Target - The type of atom or action being extended * @template Params - The parameter types that will be accepted by the extended * atom/action * @param parse - Function that transforms the new parameters into what the * atom/action expects * @returns An extension that applies the parameter transformation */ declare let withParams: { (parse: (...parse: Params) => OverloadParameters[0]): ParamsExt; }; //#endregion //#region src/core/globalStore.d.ts declare const VERSION = "1001"; type ReatomGlobal = { version: string; extensions: unknown[]; } & Record; declare global { var __REATOM: ReatomGlobal | undefined; } declare function ensureReatomGlobal(): ReatomGlobal; declare function _createGlobal(name: string, init: () => T): T; //#endregion //#region src/core/queues.d.ts type QueueKind = 'hook' | 'compute' | 'cleanup' | 'effect'; /** * Schedules a function to be executed in a specific queue of the current * context. * * This is the core mechanism for scheduling reactive updates in Reatom. When an * atom's state changes, tasks are queued to be executed afterwards in the * appropriate order. If this is the first task being scheduled, a microtask is * created to process the queues asynchronously. * * @param fn - The function to schedule for execution * @param queue - The queue to add the function to ('hook', 'compute', * 'cleanup', or 'effect') */ declare let _enqueue: (fn: Fn, queue: QueueKind) => void; /** * Runs a callback as a nested batch and optionally flushes the queue after the * outermost batch completes. * * Use `shouldNotify: true` for user-facing write batches that must notify * synchronously after all nested writes finish. Leave it `false` when wrapping * reads such as computed values or effects. * * @example * import { atom, batch } from '@reatom/core' * * const count = atom(0, 'count') * * batch(() => { * count.set(1) * count.set(2) * }, true) * * @param cb - The callback to run inside the batch * @param shouldNotify - Whether to call `notify` after the outermost batch * @returns The callback result */ declare let batch: (cb: () => T, shouldNotify?: boolean) => T; /** * Processes all scheduled tasks in the current context's queues. * * This function is called automatically after tasks have been scheduled via * `enqueue`. It processes tasks in the following priority order: * * 1. Hook tasks * 2. Compute tasks * 3. Cleanup tasks * 4. Effect tasks * * The function resets priority after each task execution to ensure higher * priority tasks (which may have been added during execution) are processed * first. */ declare let notify: () => void; //#endregion //#region src/async/withAsyncStatus.types.d.ts interface AsyncStatusNeverPending { isPending: false; isFulfilled: false; isRejected: false; isSettled: false; isFirstPending: false; isEverPending: false; isEverSettled: false; isSWR: boolean; data: [State] extends [never] ? never : InitState; error: undefined; } interface AsyncStatusFirstPending { isPending: true; isFulfilled: false; isRejected: false; isSettled: false; isFirstPending: true; isEverPending: true; isEverSettled: false; isSWR: boolean; data: [State] extends [never] ? never : InitState; error: undefined; } interface AsyncStatusFirstAborted { isPending: false; isFulfilled: false; isRejected: false; isSettled: false; isFirstPending: false; isEverPending: true; isEverSettled: false; isSWR: boolean; data: [State] extends [never] ? never : InitState; error: undefined; } interface AsyncStatusAbortedPending { isPending: true; isFulfilled: false; isRejected: false; isSettled: false; isFirstPending: false; isEverPending: true; isEverSettled: boolean; isSWR: boolean; data: [State] extends [never] ? never : InitState | State; error: undefined; } interface AsyncStatusAbortedFulfill { isPending: false; isFulfilled: true; isRejected: false; isSettled: true; isFirstPending: false; isEverPending: true; isEverSettled: true; isSWR: boolean; data: [State] extends [never] ? never : State; error: undefined; } interface AsyncStatusAbortedReject { isPending: false; isFulfilled: false; isRejected: true; isSettled: true; isFirstPending: false; isEverPending: true; isEverSettled: true; isSWR: boolean; data: [State] extends [never] ? never : State; error: Err; } type AsyncStatusAbortedSettle = AsyncStatusAbortedFulfill | AsyncStatusAbortedReject; interface AsyncStatusFulfilled { isPending: false; isFulfilled: true; isRejected: false; isSettled: true; isFirstPending: false; isEverPending: true; isEverSettled: true; isSWR: boolean; data: [State] extends [never] ? never : State; error: undefined; } interface AsyncStatusRejected { isPending: false; isFulfilled: false; isRejected: true; isSettled: true; isFirstPending: false; isEverPending: true; isEverSettled: true; isSWR: boolean; data: [State] extends [never] ? never : State; error: Err; } interface AsyncStatusAnotherPending { isPending: true; isFulfilled: false; isRejected: false; isSettled: false; isFirstPending: false; isEverPending: true; isEverSettled: true; isSWR: boolean; data: [State] extends [never] ? never : State; error: undefined | Err; } type AsyncStatusPending = AsyncStatusFirstPending | AsyncStatusAbortedPending | AsyncStatusAnotherPending; type AsyncStatus = AsyncStatusNeverPending | AsyncStatusFirstAborted | AsyncStatusPending | AsyncStatusFulfilled | AsyncStatusRejected | AsyncStatusAbortedSettle; //#endregion //#region src/async/withAsyncStatus.d.ts /** * Atom that tracks the detailed status of async operations. Provides boolean * flags for current state and historical state tracking. */ interface AsyncStatusAtom extends Computed> { /** * Resets the status atom to initial state, clearing all history flags. Useful * when you want to treat the next async call as a "first" call again. */ reset: Action<[], AsyncStatusNeverPending>; } //#endregion //#region src/async/withAsync.d.ts /** * Extension interface added by {@link withAsync} to atoms or actions that return * promises. Provides utilities for tracking async state, handling errors, and * responding to async events. * * @template Params - The parameter types of the original atom or action * @template Payload - The resolved value type of the promise * @template Error - The type of errors that can be caught */ interface AsyncExt { /** * Computed atom that indicates when no async operations are pending * * @returns Boolean indicating if all operations have completed (true) or some * are still pending (false) */ ready: Computed; /** * Action that is called when the promise resolves successfully * * @param payload - The resolved value from the promise * @param params - The original parameters passed to the atom/action * @returns An object containing the payload and parameters */ onFulfill: Action<[payload: Payload, params: Params], { payload: Payload; params: Params; }>; /** * Action that is called when the promise rejects with an error * * @param error - The error thrown by the promise * @param params - The original parameters passed to the atom/action * @returns An object containing the error and parameters */ onReject: Action<[error: Error, params: Params], { error: Error; params: Params; }>; /** * Action called after either successful resolution or rejection * * @param result - Either a payload+params object or an error+params object * @returns The same result object that was passed in */ onSettle: Action<[{ payload: Payload; params: Params; } | { error: Error; params: Params; }], { payload: Payload; params: Params; } | { error: Error; params: Params; }>; /** * Computed atom tracking how many async operations are currently pending * * @returns Number of pending operations (0 when none are pending) */ pending: Computed; /** Atom containing the most recent error or undefined if no error has occurred */ error: Atom; /** * Atom that tracks the current status of async operations including lifecycle * state, timing information, and retry functionality. Must be explicitly * enabled via the `status` option in {@link withAsync} configuration. * * @throws {ReatomError} When accessed without being enabled in options */ status: AsyncStatusAtom; /** * Atom that caches the last called parameters for retry functionality. Must * be explicitly enabled via the `cacheParams` option in {@link withAsync} * configuration. * * @returns The cached parameters from the last async operation * @throws {ReatomError} When accessed without being enabled in options */ params: Atom; /** * Action that retries the last async operation. * * - If the target is an atom: re-evaluates the computed atom * - If the target is an action: calls it with the cached params * * @returns The promise from the retried async operation * @throws {ReatomError} When called on an action without enabling * `cacheParams` */ retry: Action<[], Promise>; } /** * Configuration options for the {@link withAsync} extension * * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state (default: undefined) */ type AsyncOptions = { /** * Function to transform raw errors into a specific error type * * @param error - The caught error of unknown type * @returns A properly typed error object */ parseError?: (error: unknown) => Err; /** Initial/reset value for the error atom */ emptyError?: EmptyErr; /** * When to reset the error state * * - 'onCall': Reset error when the async operation starts (default) * - 'onFulfill': Reset error only when the operation succeeds * - Null: Never automatically reset errors * * @default 'onCall' */ resetError?: null | 'onCall' | 'onFulfill'; /** * Whether to enable the `status` atom for detailed async operation tracking. * When enabled, provides access to lifecycle state, timing information, and * retry functionality through the `status` property. * * @default false */ status?: boolean; /** * Whether to enable caching of the last called parameters for the retry * functionality. When enabled, the `params` atom and `retry` action will be * available for actions. For atoms (computeds), retry works without this * option as they can be re-evaluated directly. * * @default false */ cacheParams?: boolean; }; /** * Extension that adds async state tracking to atoms or actions that return * promises. Manages pending state, errors, and provides lifecycle actions for * async operations. * * This extension preserves Reatom context across async operations, ensuring * that the async operation's results properly update Reatom state. * * @example * // Basic usage with an action: * const fetchUser = action(async (userId: string) => { * const response = await wrap(fetch(`/api/users/${userId}`)) * return await wrap(response.json()) * }, 'fetchUser').extend(withAsync()) * * // Can then access: * fetchUser.error() // → latest error if any * fetchUser.ready() // → are all operations complete? * * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state * @param options - Configuration options for error handling * @returns An extension function that can be applied to atoms or actions */ declare let withAsync: { (options?: null | AsyncOptions): (target: T) => T extends AtomLike> ? T & AsyncExt : never; }; //#endregion //#region src/async/withAsyncData.d.ts /** * Extension interface added by {@link withAsyncData} to atoms or actions that * return promises. Extends {@link AsyncExt} with data storage and abort * capabilities for managing async data fetching. * * @template Params - The parameter types of the original atom or action * @template Payload - The resolved value type of the promise * @template State - The type of the stored data * @template Error - The type of errors that can be caught */ interface AsyncDataExt extends AsyncExt, AbortExt { /** * Atom that stores the fetched data Updated automatically when the async * operation completes successfully */ data: Atom & { reset: Action<[], InitState>; }; /** Status atom that includes the data property */ status: AsyncStatusAtom; /** * Action that resets the async data atom by clearing its dependencies and * resetting the data atom to its initial state. This is useful for * invalidating cached data and forcing a re-fetch on next access. * * Note: This action does not re-trigger the async operation automatically. * Use `retry` from {@link AsyncExt} if you want to reset and immediately * re-fetch. */ reset: Action<[], void>; } /** * Configuration options for the {@link withAsyncData} extension Extends * {@link AsyncOptions} with options specific to data management * * @template State - The type of data to store * @template Params - The parameter types of the original atom or action * @template Payload - The resolved value type of the promise * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state */ interface AsyncDataOptions extends AsyncOptions { /** Initial value for the data atom */ initState?: State; /** * Function to transform the successful payload into the data state * * @param payload - The resolved value from the promise * @param params - The original parameters passed to the atom/action * @param state - The current state of the data atom * @returns The new state for the data atom */ mapPayload?: (payload: Payload, params: Params, state: State) => State; } /** * Extension that adds async data management to atoms or actions that return * promises. * * Creates a properly typed data atom that stores the results of successful * async operations. Includes all features of {@link withAsync} and * {@link withAbort} for complete async handling. * * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state * @param options - Configuration options for async data handling * @returns An extension function that can be applied to atoms or actions */ declare function withAsyncData(options?: AsyncOptions): (target: T) => T extends AtomLike> ? AsyncDataExt : never; /** * Extension that adds async data management to atoms or actions that return * promises. * * This overload uses the payload type as the state type with a specified * initial value. Useful when you know the shape of the data that will be * fetched. * * @template T - The atom or action type * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state * @param options - Configuration options including initial state and optional * payload mapper * @returns An extension function that can be applied to atoms or actions */ declare function withAsyncData(options: AsyncOptions & (T extends AtomLike> ? { initState: Payload; mapPayload?: (payload: Payload, params: Params, state: Payload) => Payload; } : never)): (target: T) => T extends AtomLike> ? AsyncDataExt : never; /** * Extension that adds async data management to atoms or actions that return * promises. * * This overload allows specifying a completely custom state type with an * initial value. The resolved payload will be merged with the state without * custom mapping. * * @template State - The custom state type * @template T - The atom or action type * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state * @param options - Configuration options with custom initial state * @returns An extension function that can be applied to atoms or actions */ declare function withAsyncData(options: AsyncOptions & { initState: State; mapPayload?: never; }): (target: T) => T extends AtomLike> ? AsyncDataExt : never; /** * Extension that adds async data management to atoms or actions that return * promises. * * This overload provides full control with a custom state type and payload * mapping function. Allows complete transformation of the payload into the * desired state format. * * @template State - The custom state type * @template T - The atom or action type * @template Err - The type of errors after parsing * @template EmptyErr - The type of the empty error state * @param options - Configuration options with custom initial state and payload * mapper * @returns An extension function that can be applied to atoms or actions */ declare function withAsyncData(options: AsyncOptions & { initState: State; mapPayload: [State] extends [infer State] ? T extends AtomLike> ? (payload: Payload, params: Params, state: State) => State : never : never; }): (target: T) => T extends AtomLike> ? AsyncDataExt : never; //#endregion //#region src/form/withBaseField.d.ts /** * Represents the focus-related state of a form field. Tracks whether the field * is currently active, has been modified, or has been interacted with. */ interface FieldFocus { /** The field is focused. */ active: boolean; /** The field state is not equal to the initial state. */ dirty: boolean; /** The field has ever gained and lost focus. */ touched: boolean; } /** * Base structure for field validation errors. Contains the error message and * optional metadata with additional error details. * * @template Meta - Type of the metadata object for additional error context * @see {@link FieldError} */ interface FieldErrorBody { /** The message of the error useful for a user. */ message: string; /** * The record with arbitrary information about the error like minimum chars, * upper bound of a number, etc. */ meta?: Rec; } /** * The source type of a field error. Built-in value is `'validation'` for errors * from the validate function, but custom string sources are also allowed for * external error sources (e.g., server errors). */ type FieldErrorSource = 'validation' | (string & {}); /** * Complete field error structure that includes the error body and its source. * Extends {@link FieldErrorBody} with information about where the error * originated. * * @template Meta - Type of the error metadata object * @see {@link FieldErrorBody} * @see {@link FieldErrorSource} */ interface FieldError extends FieldErrorBody { /** * The type of an error source. The value will be `validation` if the error * occurred due to the `validate` function. */ source: FieldErrorSource; } /** * Validation function type for field validation. Receives field metadata and * returns validation result synchronously or asynchronously. * * @template State - The field state type * @template Value - The value type passed to validation (can differ from State * via `getValue`) * @param meta - Object containing current field state, value, focus status, and * validation state * @returns Validation result or a promise resolving to it * @see {@link FieldValidateOptionResult} * @see {@link FieldFocus} * @see {@link FieldValidation} */ type FieldValidateOption = (meta: { state: State; value: Value; focus: FieldFocus; validation: FieldValidation; }) => FieldValidateOptionResult | Promise>; /** * Possible return types from a validation function. Supports simple error * strings, arrays of errors, {@link FieldErrorBody} objects, or a * {@link https://github.com/standard-schema/standard-schema | Standard Schema} * for declarative validation. * * @template State - The field state type for Standard Schema validation * @see {@link FieldErrorBody} * @see {@link FieldValidateOption} */ type FieldValidateOptionResult = string | string[] | FieldErrorBody | FieldErrorBody[] | StandardSchemaV1 | void | undefined; /** * Represents the current validation state of a field. Contains the computed * error message, trigger status, and async validation promise. * * @see {@link FieldError} * @see {@link ValidationAtom} */ interface FieldValidation { /** Message of the first validation error, computed from errors atom */ error: undefined | string; /** The validation actuality status. */ triggered: boolean; /** The field async validation status. */ validating: undefined | Promise<{ errors: FieldError[]; }>; } /** * Atom interface for managing field focus state. Provides actions for * programmatically focusing and blurring the field. * * @see {@link FieldFocus} * @see {@link BaseFieldExt.focus} */ interface FocusAtom extends AtomLike { /** Action for handling field focus. */ in: Action<[], FieldFocus>; /** Action for handling field blur. */ out: Action<[], FieldFocus>; } /** * Atom interface for managing field validation state. Provides actions to * trigger validation, access errors, and clear errors by source. * * @see {@link FieldValidation} * @see {@link FieldError} * @see {@link BaseFieldExt.validation} */ interface ValidationAtom extends AtomLike { /** Action to trigger field validation. */ trigger: Action<[], FieldValidation> & AbortExt; /** Full list of all errors related to the field */ errors: ArrayAtom; /** Action to clear all errors by passed sources. */ clearErrors: Action<[...sources: FieldErrorSource[]], FieldValidation>; } /** * Reference interface for the DOM element associated with a field. Used for * programmatic focus management. */ interface FieldElementRef { focus: (options?: { preventScroll?: boolean; }) => void; } /** * Marker interface for atoms extended with field behavior. Used for type * narrowing via {@link isFieldAtom}. * * @template State - The field state type * @see {@link isFieldAtom} */ interface FieldLikeAtom extends Atom { __reatomField: true; } /** * Configuration options for the {@link withBaseField} extension. Defines * validation behavior, focus handling, and state normalization. * * @template State - The field state type * @template Value - The value type for validation (defaults to State) * @template InitStateParams - Parameters for reset action (defaults to * `[initState: State]`) * @template NormalizedState - Normalized state type for comparison (defaults to * State) * @see {@link withBaseField} * @see {@link BaseFieldExt} */ interface BaseFieldExtOptions { /** * Optional callback to get value for validation. By default returns the field * state. */ getValue?: (state: State) => Value; /** * Optional callback to normalize the state before pass it to callbacks such * as `validate` or `isDirty`. By default returns the field state. */ getNormalizedState?: (state: State) => NormalizedState; /** * The callback used to determine whether the state has changed (dirty check). * By default, it utilizes `isDeepEqual` from reatom/utils comparing states. */ isDirty?: (newState: NormalizedState, prevState: NormalizedState) => boolean; /** The callback to validate the field. */ validate?: FieldValidateOption, Value> | StandardSchemaV1>; /** * Defines if the field is disabled by default. * * @default false */ disabled?: boolean; /** Defines a default element reference associated with the field. */ elementRef?: FieldElementRef; /** * Defines the reset behavior of the validation state during async validation. * * @default false */ keepErrorDuringValidating?: boolean; /** * Defines the reset behavior of the validation state on field change. Useful * if the validation is triggered on blur or submit only. * * @default !validateOnChange */ keepErrorOnChange?: boolean; /** * Defines if the validation should be triggered with every field change. * * @default false */ validateOnChange?: boolean; /** * Defines if the validation should be triggered on the field blur. * * @default false */ validateOnBlur?: boolean; /** * Defines if the validation should be triggered when the field is connected * (binded to UI/being a part of reactive subscription). * * @default false */ validateOnConnect?: boolean; /** * Optional custom initState atom. If provided, its setter params will be used * for the reset action. */ initStateAtom: Atom; } /** * Extension interface added to atoms by {@link withBaseField}. Provides focus * management, validation, reset functionality, and runtime options. * * @template State - The field state type * @template InitStateParams - Parameters for the reset action * @see {@link withBaseField} * @see {@link BaseFieldExtOptions} */ interface BaseFieldExt { /** Atom of an object with all related focus statuses. */ focus: FocusAtom; /** The initial state of the atom. */ initState: Atom; /** Action to reset the state, the validation, and the focus. */ reset: Action<[] | InitStateParams, void>; /** Atom of an object with all related validation statuses. */ validation: ValidationAtom; /** Atom that defines if the field is disabled */ disabled: BooleanAtom; /** Atom with the reference to the field element. */ elementRef: Atom; options: RecordAtom<{ /** * Defines the reset behavior of the validation state during async * validation. * * @default false */ keepErrorDuringValidating: boolean | undefined; /** * Defines the reset behavior of the validation state on field change. * Useful if the validation is triggered on blur or submit only. * * @default !validateOnChange */ keepErrorOnChange: boolean | undefined; /** * Defines if the validation should be triggered with every field change. * * @default false */ validateOnChange: boolean | undefined; /** * Defines if the validation should be triggered on the field blur. * * @default false */ validateOnBlur: boolean | undefined; /** * Defines if the validation should be triggered when the field is connected * (binded to UI/being a part of reactive subscription). * * @default false */ validateOnConnect: boolean | undefined; shouldValidate: boolean | undefined; }>; __reatomField: true; } declare const fieldInitFocus: FieldFocus; declare const fieldInitValidation: FieldValidation; declare const fieldInitValidationLess: FieldValidation; /** * Atom extension that adds form field behavior to any atom. This is the * foundational extension used by higher-level primitives like `reatomField` and * `reatomFieldArray`. * * Adds focus tracking, validation with sync/async support, dirty checking, * reset functionality, and configurable validation triggers. * * @template Target - The target atom type to extend * @template Value - The value type for validation * @template InitStateParams - Parameters for the reset action * @template NormalizedState - Normalized state type for dirty comparison * @param options - Configuration options for field behavior * @returns An assigner extension that adds {@link BaseFieldExt} properties to * the atom * @see {@link BaseFieldExtOptions} * @see {@link BaseFieldExt} */ declare const withBaseField: , InitStateParams extends unknown[] = [initState: AtomState], NormalizedState = AtomState>(options: BaseFieldExtOptions, Value, InitStateParams, NormalizedState>) => AssignerExt, InitStateParams>, Target>; /** * Type guard to check if a value is a field atom extended with * {@link withBaseField}. * * @param thing - The value to check * @returns `true` if the value is a {@link FieldLikeAtom}, `false` otherwise * @see {@link FieldLikeAtom} */ declare const isFieldAtom: (thing: any) => thing is FieldLikeAtom; //#endregion //#region src/form/reatomField.d.ts interface FieldExt extends BaseFieldExt { /** * Action for handling field changes, accepts the "value" parameter and * applies it to `toState` option. */ change: Action<[Value], Value>; /** Writable atom with the "value" data, computed by the `fromState` option */ value: Atom; } interface FieldExtOptions extends Omit, 'isDirty' | 'initStateAtom' | 'getValue' | 'getNormalizedState'> { /** * The callback to filter "value" changes (from the 'change' action). It * should return 'false' to skip the update. By default, it always returns * `true`. */ filter?: (newValue: Value, prevValue: Value) => boolean; /** * The callback used to determine whether the "value" has changed. By default, * it utilizes `isDeepEqual` from reatom/utils. */ isDirty?: (newValue: Value, prevValue: Value) => boolean; } /** * Extension of FieldExtOptions that adds state/value transformation callbacks. * Use when the internal state and the user-facing value need different types. * * @example * const priceField = reatomField(100.5, { * fromState: (state) => state.toFixed(2), * toState: (value) => parseFloat(value), * }) */ interface TransformableFieldExtOptions extends FieldExtOptions { /** * The callback to compute the "value" data from the "state" data. By default, * it returns the "state" data without any transformations. */ fromState?: (state: State, self: FieldAtom) => Value; /** * The callback to transform the "state" data from the "value" data from the * `change` action. By default, it returns the "value" data without any * transformations. * * It's also possible to abort the computation and left the state unchaged by * throwing abort error inside the callback * * @example * const numberField = reatomField(0, { * fromState: (state) => state.toString(), * toState: (value: string) => { * const parsed = Number(value) * return isNaN(parsed) ? throwAbort() : parsed * }, * }) */ toState?: (value: Value, self: FieldAtom) => State; } /** * Extends an atom with field capabilities including change handling, focus * tracking, validation, and dirty state management. Useful for enriching smart * atoms with fields capabilities. * * @example * const optionField = reatomEnum(['one', 'two']).extend(withField()) * * optionField.setOne() * optionField() // 'one' * optionField.focus().dirty // true after first change * * @example * // With state/value transformation * const priceField = atom(100).extend( * withField({ * fromState: (state) => state.toString(), * toState: (value) => parseFloat(value), * }), * ) */ declare function withField(options?: FieldExtOptions, AtomState>): (anAtom: T) => T & FieldExt, AtomState>; declare function withField, Value = State>(options?: TransformableFieldExtOptions): (anAtom: T) => T & FieldExt; declare function withField(options?: FieldExtOptions): (anAtom: T) => T & FieldExt; /** Options for creating a field atom via `reatomField`. */ interface FieldOptions extends FieldExtOptions { /** The name of the field and all related atoms and actions. */ name?: string; } /** * Options for creating a field atom with state/value transformation via * `reatomField`. */ interface TransformableFieldOptions extends TransformableFieldExtOptions { /** The name of the field and all related atoms and actions. */ name?: string; } /** * Atom representing a form field with built-in support for change handling, * focus tracking, validation, and dirty state. * * @template State - The internal state type stored in the atom. * @template Value - The user-facing value type (defaults to State). */ interface FieldAtom extends Atom, FieldExt {} declare function reatomField(initState: State, name?: string): FieldAtom; declare function reatomField(initState: State, options: TransformableFieldOptions): FieldAtom; //#endregion //#region src/primitives/reatomArray.d.ts interface ArrayAtom extends Atom> { push: Action<[...items: T[]], number>; pop: Action<[], T | undefined>; shift: Action<[], T | undefined>; unshift: Action<[...items: T[]], number>; } /** * Creates an atom for ordered collections and adds immutable wrappers around * the array operations you usually need in UI state. * * @remarks * This is a good fit for queues, recent items, and any state where order * matters but node-level reordering is not the main feature. * @example * // Track a toast queue * const toasts = reatomArray([], 'toasts') * * toasts.push('Build finished') * toasts.push('New comment') * toasts.shift() * * toasts() // ['New comment'] */ declare const reatomArray: (initState?: T[], name?: string) => ArrayAtom; //#endregion //#region src/primitives/reatomBoolean.d.ts interface BooleanAtom extends Atom { toggle: Action<[], boolean>; setTrue: Action<[], true>; setFalse: Action<[], false>; reset: Action<[], boolean>; } /** * Creates a boolean atom with the most common state transitions already wired * in. * * @remarks * Useful for modal visibility, loading switches, feature flags, and other * binary UI state. * @example * // Control a dialog visibility flag * const deleteDialogOpen = reatomBoolean(false, 'deleteDialogOpen') * * deleteDialogOpen.setTrue() * deleteDialogOpen.toggle() * deleteDialogOpen.reset() * * deleteDialogOpen() // false */ declare const reatomBoolean: (init?: boolean, name?: string) => BooleanAtom; //#endregion //#region src/primitives/reatomEnum.d.ts type EnumFormat = 'camelCase' | 'snake_case'; type EnumVariantSetters = { [Variant in T as Format extends 'camelCase' ? `set${Capitalize}` : Format extends 'snake_case' ? `set_${Variant}` : never]: Action<[], Variant> }; type EnumAtom = Atom & EnumVariantSetters & { reset: Action<[], T>; enum: { [K in T]: K }; }; type EnumAtomOptions = { name?: string; format?: Format; initState?: T; }; /** * Creates a string atom limited to a fixed set of variants and augments it with * enum-specific helpers. * * @remarks * Treat `reatomEnum` as the default way to model enums in Reatom apps. It keeps * the reactive value, runtime validation, generated setter actions, and a * stable `myEnum.enum` object in one place. * * Capabilities: * * - Infers a string union from a readonly variants array. * - Rejects invalid values at runtime. * - Generates setter actions like `setOpen()` or `set_open()`. * - Exposes `reset()` to return to the configured initial variant. * - Exposes `myEnum.enum` so UI code, comparisons, and integrations can reuse the * same canonical values without repeating raw strings. * * By default the first variant becomes the initial state. Setter names use * `camelCase`, or `snake_case` when requested. * @example * // Use it as the default enum model and reuse `myEnum.enum` values * const ticketStatus = reatomEnum( * ['new', 'inProgress', 'resolved'], * 'ticketStatus', * ) * * ticketStatus.set(ticketStatus.enum.inProgress) * * if (ticketStatus() === ticketStatus.enum.inProgress) { * ticketStatus.setResolved() * } * * Object.values(ticketStatus.enum) * // ['new', 'inProgress', 'resolved'] * * @example * // Match backend-style names with `snake_case` setters * const deliveryState = reatomEnum( * ['not_started', 'in_progress', 'done'], * { * name: 'deliveryState', * format: 'snake_case', * initState: 'not_started', * }, * ) * * deliveryState.set_in_progress() * deliveryState.reset() * * deliveryState() // 'not_started' */ declare const reatomEnum: (variants: ReadonlyArray, options?: string | EnumAtomOptions) => (ActionsExt> extends infer T_1 ? T_1 extends ActionsExt> ? T_1 extends AtomLike ? T_1 : Atom & ActionsExt<{ reset: () => T; }> & T_1 : never : never) & { enum: { [k: string]: T; }; }; //#endregion //#region src/primitives/reatomNumber.d.ts interface NumberAtom extends Atom { increment: Action<[by?: number], number>; decrement: Action<[by?: number], number>; random: Action<[min?: number, max?: number], number>; reset: Action<[], number>; } /** * Creates a number atom with counter-style helpers for incrementing, * decrementing, resetting, and generating a random value. * * @remarks * Handy for pagination, retry counters, wizard steps, and other numeric UI * state that changes through user actions. * @example * // Track retry attempts for a flaky request * const retryCount = reatomNumber(0, 'retryCount') * * retryCount.increment() * retryCount.increment() * retryCount.decrement() * * retryCount() // 1 */ declare const reatomNumber: (initState?: number, name?: string) => NumberAtom; //#endregion //#region src/primitives/reatomRecord.d.ts interface RecordAtom extends Atom { merge: Action<[slice: Partial], T>; omit: Action, T>; reset: Action, T>; } /** * Creates an object atom with helpers for shallow updates, key removal, and * resetting to the initial snapshot. * * @remarks * This works well for filter panels, drafts, and settings objects where you * usually patch a few fields at a time. * @example * // Edit a product filter draft * const filters = reatomRecord( * { query: '', onlyInStock: false, sort: 'popular' }, * 'filters', * ) * * filters.merge({ query: 'keyboard', onlyInStock: true }) * filters.omit('sort') * filters.reset('query') * * filters() // { query: '', onlyInStock: true } */ declare const reatomRecord: (initState: Exclude, name?: string) => RecordAtom; //#endregion //#region src/primitives/reatomSet.d.ts type StateInit = Set | ConstructorParameters>[0]; interface SetAtom extends Atom, [newState: StateInit]> { add: Action<[el: T], Set>; delete: Action<[el: T], Set>; toggle: Action<[el: T], Set>; clear: Action<[], Set>; reset: Action<[], Set>; size: Computed; } /** * Creates a set atom for unique selections and membership checks. * * @remarks * This is a natural choice for selected ids, expanded panels, pinned items, and * feature switches that should never contain duplicates. * @example * // Store selected table rows * const selectedOrderIds = reatomSet([], 'selectedOrderIds') * * selectedOrderIds.add('ord-1') * selectedOrderIds.toggle('ord-2') * selectedOrderIds.toggle('ord-1') * * [...selectedOrderIds()] // ['ord-2'] */ declare const reatomSet: (initState?: StateInit, name?: string) => SetAtom; //#endregion //#region src/primitives/reatomString.d.ts type StringAtom = Atom & { reset: Action<[], T>; }; /** * Creates a string atom with a `reset` action that restores the initial value. * * @remarks * Useful for search inputs, drafts, route params, and other text state that * should be easy to clear back to its starting point. * @example * // Keep a search query draft * const searchQuery = reatomString('', 'searchQuery') * * searchQuery.set('reatom linked list') * searchQuery.reset() * * searchQuery() // '' */ declare const reatomString: { (init?: string, name?: string): StringAtom; (init: T, name?: string): StringAtom; }; //#endregion //#region src/form/reatomFieldsAtomize.d.ts /** * Union of all valid types that can be used as initial state for field * atomization. Includes: * * - Primitives: `string`, `number`, `boolean`, `null`, `undefined`, `symbol`, * `bigint` * - Built-in objects: `Date`, `File` * - Already created field atoms: {@link FieldAtom} * - Deprecated field options object: {@link FieldSetFieldOptions} * - Nested records of fields: {@link FieldsAtomizeInitStateRecord} * * @see {@link reatomFieldsAtomize} for usage */ type FieldsAtomizeInitState = string | number | boolean | null | undefined | File | symbol | bigint | Date | FieldAtom | FieldSetFieldOptions | FieldsAtomizeInitStateRecord; /** * A record type representing a nested structure of fields. Each key maps to * either: * * - A single field value ({@link FieldsAtomizeInitState}) * - An existing field-like atom ({@link FieldLikeAtom}) * - An array for creating a {@link FieldArrayAtom} * * @example * const initState: FieldsAtomizeInitStateRecord = { * name: '', * age: 0, * address: { * street: '', * city: '', * }, * tags: ['default'], * } */ type FieldsAtomizeInitStateRecord = { [fieldKey: string]: FieldsAtomizeInitState | FieldLikeAtom | Array; }; /** * Conditional type that maps an initial state structure to its atomized * equivalent. Transforms primitives and nested records into their corresponding * field atoms: * * - {@link FieldLikeAtom} → passed through unchanged (it also includes * reatomFieldArray instances) * - `Date` | `File` → `FieldAtom` * - `boolean` → `FieldAtom` * - `Array` → `FieldArrayAtom` * - `{ initState: T }` (deprecated) → `FieldAtom` * - Nested record → recursively atomized record * - Other primitives → `FieldAtom` * * @example * type Input = { name: string; tags: string[] } * type Output = FieldsAtomize * // { name: FieldAtom; tags: FieldArrayAtom } * * @template Element - The initial state type to atomize */ type FieldsAtomize = [Element] extends [FieldLikeAtom] ? Element : [Element] extends [Date | File] ? FieldAtom : [Element] extends [boolean] ? FieldAtom : [Element] extends [Array] ? Item extends FieldsAtomizeInitState ? FieldArrayAtom : never : [Element] extends [TransformableFieldExtOptions & { initState: infer State; }] ? Element extends TransformableFieldExtOptions ? FieldAtomFromDeprecatedFieldOptions : Element extends TransformableFieldExtOptions ? FieldAtomFromDeprecatedFieldOptions : { initState: State; } extends Element ? FieldAtomFromDeprecatedFieldOptions : never : [Element] extends [FieldsAtomizeInitStateRecord] ? { [FieldKey in keyof Element]: FieldsAtomize } : FieldAtom; /** * Action that is called when a new field is created inside a * {@link FieldArrayAtom}. Used to hook into field creation for custom setup * (e.g., applying form-level validation options). * * @see {@link FieldsAtomizeModel.experimental_onFieldCreated} */ type OnFieldCreatedAction = Action<[field: FieldAtom], FieldAtom>; /** * Return type of {@link reatomFieldsAtomize}. Contains the atomized fields tree * and an optional hook for field array element creation. * * @template InitState - The initial state type that was atomized */ type FieldsAtomizeModel = { /** * The atomized fields tree. Structure mirrors the input `initState`, but all * values are converted to their corresponding field atoms. */ fields: FieldsAtomize; /** * Action called whenever a new field is created inside any nested * {@link FieldArrayAtom}. Only present if the `initState` contains arrays or * field arrays. Used by {@link reatomForm} to apply form-level validation * options to dynamically created fields. */ experimental_onFieldCreated?: OnFieldCreatedAction; }; /** @deprecated Will be removed in next major release */ interface FieldSetFieldOptions extends TransformableFieldExtOptions { initState: State; } /** * @deprecated This field was initialized with field options object literal that * considered as a deprecated initialization method. Please use `reatomField` * instead */ type FieldAtomFromDeprecatedFieldOptions = FieldAtom; //#endregion //#region src/form/reatomFieldArray.d.ts type FieldArrayLLNode = LLNode>; type FieldArrayState = LinkedList>; /** * Configuration options for {@link reatomFieldArray}. Extends * {@link BaseFieldExtOptions} with array-specific settings. * * @example * // Validation on change * const emails = reatomFieldArray([''], { * validateOnChange: true, * validate: z.array(z.string().email()), * }) * * @example * // Validation on blur with error preservation * const tags = reatomFieldArray(['tag1'], { * validateOnBlur: true, * keepErrorOnChange: true, * validate: ({ value }) => * value.length >= 2 || 'At least 2 tags required', * }) * * @example * // Custom element creation with validation * const contacts = reatomFieldArray(['alice@example.com'], { * create: (email) => ({ email, verified: false }), * validate: z.array(z.any()).min(1, 'At least one contact required'), * }) * * @template Param - The type of parameters used to create new elements * @template Node - The field structure of each element */ type FieldArrayOptions = Omit, FieldArrayLLNode[], [initState: FieldArrayInitState[]], FieldArrayLLNode[]>, 'getValue' | 'getNormalizedState' | 'initStateAtom'> & { /** * Factory function to transform input parameters into field element * structure. If not provided, the parameter is used directly as the element. * * @example * const todos = reatomFieldArray([], { * create: (text: string) => ({ * text, * completed: false, * createdAt: new Date(), * }), * }) * todos.create('Buy milk') * * @example * // Using `name` to create properly named extended fields * const permissions = reatomFieldArray([], { * create: (resource: string, name) => ({ * resource, * access: reatomEnum( * ['read', 'write', 'admin'], * `${name}.access`, * ).extend(withField()), * }), * }) * * @param param - The input parameter passed to `create()` method * @param name - Auto-generated debug name for the element (e.g., * `"fieldArray.item"`) * @returns The field structure for the new element */ create?: (param: Param, name: string) => Node; /** Debug name for the atom */ name?: string; }; type FieldArrayInitState = { [K in keyof T]: [T[K]] extends FieldArrayAtom ? Param[] : FieldArrayInitState }; /** * Reactive atom for managing dynamic arrays of form fields. Combines * {@link LinkedListAtom} with {@link BaseFieldExt} to provide efficient list * operations (add, remove, reorder) alongside form state tracking (dirty, * validation, reset). * * @template Param - The type of parameters used to create new field elements * @template Node - The structure of each field element (must extend * {@link FieldsAtomizeInitState}) */ type FieldArrayAtom = LinkedListAtom<[FieldArrayInitState], FieldsAtomize> & BaseFieldExt, [initState: FieldArrayInitState[]]> & { experimental_onFieldCreated: OnFieldCreatedAction; }; /** * Extracts the type of a single element from a {@link FieldArrayAtom}. * * @example * const usersArray = reatomFieldArray([{ name: 'Alice', age: 30 }]) * type UserItem = FieldArrayItem * // UserItem = { name: FieldAtom, age: FieldAtom } * * @template T - The {@link FieldArrayAtom} type to extract the item from */ type FieldArrayItem = T extends FieldArrayAtom ? AtomState[number] : never; /** * Type guard to check if an atom is a {@link FieldArrayAtom}. * * @example * if (isFieldArrayAtom(field)) { * field.create({ name: '', age: 0 }) * } * * @param atom - The atom to check * @returns `true` if the atom is a {@link FieldArrayAtom}, `false` otherwise */ declare const isFieldArrayAtom: (atom: any) => atom is FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} from an array of initial values with * heterogeneous types. Each element's type is inferred and preserved, allowing * mixed-type arrays. * * @example * const mixedArray = reatomFieldArray([ * { type: 'text', value: 'hello' }, * { type: 'number', value: 42 }, * ]) * * @param initState - Array of initial values to populate the field array * @param name - Optional debug name for the atom * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(initState: Params extends FieldsAtomizeInitState[] ? Params : never, name?: string): FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} from an array of initial values with a * uniform type. * * @example * const usersArray = reatomFieldArray( * [ * { name: 'Alice', age: 30 }, * { name: 'Bob', age: 25 }, * ], * 'usersArray', * ) * usersArray.create({ name: '', age: 0 }) * * @param initState - Array of initial values with the same type * @param name - Optional debug name for the atom * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(initState: Param[], name?: string): FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} with a factory function for custom element * creation. Use this when you need to transform input parameters into a * different field structure. * * @example * const todosArray = reatomFieldArray( * (text: string) => ({ text, completed: false, createdAt: new Date() }), * 'todosArray', * ) * todosArray.create('Buy milk') * * @example * // Using `name` to create properly named extended fields * const permissions = reatomFieldArray([], { * create: (resource: string, name) => ({ * resource, * access: reatomEnum( * ['read', 'write', 'admin'], * `${name}.access`, * ).extend(withField()), * }), * }) * * @param create - Factory function that receives a parameter and returns the * field structure * @param name - Optional debug name for the atom * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(create: (param: Param, name: string) => Node, name?: string): FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} using an options object. * * @deprecated Use `reatomFieldArray(initState, options)` or * `reatomFieldArray(create, name)` overloads instead * @param options - Configuration object with `create` factory and optional * `initState` * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(options: { create: (param: Param, name: string) => Node; initState?: Param[]; name?: string; }): FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} from heterogeneous initial values with * additional options. Provides full control over field creation, validation, * and dirty state tracking. * * @example * const itemsArray = reatomFieldArray([{ sku: 'A1', quantity: 2 }], { * create: (item) => ({ ...item, validated: false }), * validate: ({ state }) => * !state.length ? 'At least one item required' : undefined, * }) * * @param initState - Array of initial values with heterogeneous types * @param options - Configuration options including custom `create` factory and * validation * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(initState: Params extends FieldsAtomizeInitState[] ? Params : never, options: FieldArrayOptions): FieldArrayAtom; /** * Creates a {@link FieldArrayAtom} from uniform initial values with additional * options. Allows custom field creation via `options.create` to transform * initial values into a different structure. * * @example * const contactsArray = reatomFieldArray( * ['alice@example.com', 'bob@example.com'], * { * create: (email) => ({ email, verified: false }), * validate: ({ state }) => * state.length > 10 ? 'Too many contacts' : undefined, * }, * ) * * @param initState - Array of initial values with uniform type * @param options - Configuration options including custom `create` factory and * validation * @returns A {@link FieldArrayAtom} managing the array of fields */ declare function reatomFieldArray(initState: Param[], options: FieldArrayOptions): FieldArrayAtom; /** @deprecated Use reatomFieldArray instead */ declare const experimental_fieldArray: typeof reatomFieldArray; /** @deprecated Renamed. Use FieldArrayItem instead */ type ArrayFieldItem = FieldArrayItem; //#endregion //#region src/form/reatomFieldSet.d.ts /** Field validation error with a reference to the field where it occurred. */ interface FieldSetFieldError extends FieldError { field: FieldAtom; } /** * Aggregated validation state of a fieldset, computed from all nested fields. * Disabled fields are excluded from validation computations. */ interface FieldSetValidation { /** The list of field validation errors. */ errors: FieldSetFieldError[]; /** True if ALL fields in the fieldset have been triggered. */ triggered: boolean; /** * Promise resolving to all async validation errors, or undefined if no async * validations are running. */ validating: undefined | Promise<{ errors: FieldSetFieldError[]; }>; } type DeepPartial = { [K in keyof T]?: T[K] extends Skip ? T[K] : T[K] extends Rec ? DeepPartial : T[K] }; /** Initial state structure for creating a fieldset. */ type FieldSetInitState = FieldsAtomizeInitStateRecord; /** * Deatomized (plain object) state of the fieldset, derived from all field * values. */ type FieldSetState = Deatomize>; /** * Partial state for init/reset operations, allowing partial updates to field * values. */ type FieldSetPartialState = DeepPartial, Array>; /** * Fieldset atom without validation capabilities. Groups related fields and * manages them as a single unit with aggregated focus state. */ interface ValidationlessFieldSetAtom extends Computed>, FieldsAtomizeModel { /** Computed list of all the fields from the fields tree */ fieldsList: Computed; /** Computed list of all the field arrays from the fields tree */ fieldArraysList: Computed; /** * Atom with the state of the fieldset, computed from all the fields in * `fieldsList` * * @deprecated Use target atom instead */ fieldsState: Computed>; /** * Atom with focus state of the fieldset, computed from all the fields in * `fieldsList` */ focus: Computed; /** Action to set initial values for each field or field array in the fieldset */ init: Action<[initState: FieldSetPartialState], void>; /** Action to reset the state, the value, the validation, and the focus states. */ reset: Action<[initState?: FieldSetPartialState], void>; } /** * Fieldset atom with full validation support. Aggregates validation state from * all nested fields, can be used as a lens over form fields. */ interface FieldSetAtom extends ValidationlessFieldSetAtom { /** * Atom with validation state of the fieldset, computed from all the fields in * `fieldsList` */ validation: Computed & { /** Action to trigger fieldset validation. */trigger: Action<[], FieldSetValidation> & AbortExt; }; } /** * Creates a fieldset that groups related fields and manages them as a single * unit. * * **Use cases:** * * - **Reusable field groups** — create compound fields like `addressFieldSet` to * reuse across forms * - **Lenses over form** — split a large form into logical sections (e.g., wizard * steps) with independent validation/focus tracking * - **Aggregated state** — track combined `focus`, `validation`, and values of * multiple fields * * Provides `fieldsList`/`fieldArraysList` for iteration, `init`/`reset` for * bulk operations. The fieldset itself is a computed atom of all field values. * * @example * // Reusable field group * const reatomAddressFieldSet = (name: string) => * reatomFieldSet( * { * street: '', * city: '', * zip: '', * }, * name, * ) * * const shippingFieldSet = reatomAddressFieldSet('order.shipping') * const billingFieldSet = reatomAddressFieldSet('order.billing') * * const form = reatomForm( * { shipping: shippingFieldSet.fields, billing: billingFieldSet.fields }, * 'order', * ) * * @example * // Lens over form for wizard steps * const form = reatomForm( * { * name: '', * email: '', * address: '', * phone: '', * }, * 'registration', * ).extend((form) => ({ * step1: reatomFieldSet( * { name: form.fields.name, email: form.fields.email }, * `${form.name}.step1`, * ), * step2: reatomFieldSet( * { address: form.fields.address, phone: form.fields.phone }, * `${form.name}.step2`, * ), * })) * * // Each step has independent validation.triggered and focus states * * @param initState - Initial state structure or factory function `(name) => * state` for scoped naming * @param name - Debug name for the fieldset * @see {@link https://reatom.dev/handbook/forms/concepts/form/|Form documentation} * @see {@link https://reatom.dev/handbook/forms/concepts/fieldset/|Fieldset documentation} */ declare const reatomFieldSet: (initState: InitState | ((name: string) => InitState), name?: string) => FieldSetAtom; /** @deprecated Renamed. Use FieldSetInitState instead */ type FormInitState = FieldSetInitState; /** @deprecated Renamed. Use FieldSetState instead */ type FormState = FieldSetState; /** @deprecated Renamed. Use FieldSetPartialState instead */ type FormPartialState = FieldSetPartialState; /** @deprecated Renamed. Use ValidationlessFieldSetAtom instead */ type ValidationlessFieldSet = ValidationlessFieldSetAtom; /** @deprecated Renamed. Use FieldSetAtom instead */ type FieldSet = FieldSetAtom; //#endregion //#region src/form/reatomForm.d.ts /** * Type for the form's submit action with async data extensions. * * Provides access to `submit.data` for the last successful result and * `submit.error` for the last error. * * @example * const form = reatomForm( * { email: '' }, * { * onSubmit: async (state, skipDebounce: boolean) => { * if (!skipDebounce) await wrap(sleep(300)) * return { success: true } * }, * }, * ) * * const result = await wrap(form.submit(true)) * console.log(form.submit.data()) // { success: true } * * @template Params - Parameters passed to the submit action * @template Return - Return type of the onSubmit callback */ type SubmitAction = Action> & AsyncDataExt; /** * Form atom interface extending {@link ValidationlessFieldSetAtom} with * validation, submit handling, and submitted state tracking. * * Form provides: * * - Aggregated `validation` state from all nested fields * - `submit` async action with validation and schema support * - `submitted` state tracking * - Inherits all fieldset features: `fields`, `focus`, `reset`, `fieldsList`, * etc. * * @template InitState - Initial state structure for form fields * @template SchemaState - Output type from schema validation (undefined if no * schema) * @template SubmitReturn - Return type of onSubmit callback * @template SubmitParams - Additional parameters for submit action * @see {@link reatomForm} for creation * @see {@link https://reatom.dev/handbook/forms/concepts/form/|Form documentation} * @see {@link https://reatom.dev/handbook/forms/concepts/fieldset/|Fieldset documentation} */ interface FormAtom extends ValidationlessFieldSetAtom { /** * Atom with validation state of the form, computed from all the fields in * `fieldsList` */ validation: Computed & { /** Action to trigger form validation. */trigger: Action<[], Promise : SchemaState>> & AsyncExt<[], any, Error | undefined> & AbortExt; } & (undefined extends SchemaState ? {} : { triggerSchemaValidation: Action<[], StandardSchemaV1.Result | Promise>> & AbortExt; }); /** * Submit async handler. It checks the validation of all the fields in * `fieldsList`, calls the form's `validate` options handler, and then the * `onSubmit` options handler. * * @see {@link https://reatom.dev/handbook/async/#basic-async-actions|Async actions documentation} */ submit: SubmitAction; /** Atom with submitted state of the form */ submitted: Atom; } /** * Base options shared between schema and non-schema form variants. * * These options define form-level defaults that propagate to all fields unless * overridden at the field level. * * @see {@link FormOptionsWithSchema} * @see {@link FormOptionsWithoutSchema} */ interface BaseFormOptions { name?: string; /** * Should reset the state after success submit? * * @default false */ resetOnSubmit?: boolean; /** * Defines the default reset behavior of the validation state during async * validation for all fields. * * @default false */ keepErrorDuringValidating?: boolean; /** * Defines the default reset behavior of the validation state on field change * for all fields. Useful if the validation is triggered on blur or submit * only. * * @default !validateOnChange */ keepErrorOnChange?: boolean; /** * Defines if the validation should be triggered with every field change by * default for all fields. * * @default false */ validateOnChange?: boolean; /** * Defines if the validation should be triggered on the field connect by * default for all fields. * * @default false */ validateOnConnect?: boolean; /** * Defines if the validation should be triggered on the field blur by default * for all fields. * * @default false */ validateOnBlur?: boolean; } /** * Form options when using a Standard Schema for validation. * * When a schema is provided, the `onSubmit` callback receives the validated and * transformed output type from the schema, not the raw field values. * * @example * const form = reatomForm( * { email: '', age: 0 }, * { * schema: z.object({ * email: z.string().email(), * age: z.number().min(18, 'Must be 18+'), * }), * onSubmit: (state) => { * // state is typed as { email: string; age: number } * console.log(state.email, state.age) * }, * }, * ) * * @template State - The output type from schema validation * @template SubmitReturn - Return type of onSubmit callback * @template SubmitParams - Additional parameters for submit action * @see {@link https://standardschema.dev|Standard Schema documentation} */ interface FormOptionsWithSchema extends BaseFormOptions { /** The callback to process valid form data, typed according to the schema */ onSubmit?: (state: State, ...params: SubmitParams) => SubmitReturn | Promise; /** * The callback to validate form fields before submit, typed according to the * schema */ validateBeforeSubmit?: (state: State) => any; /** * The schema which supports StandardSchemaV1 specification to validate form * fields. */ schema: StandardSchemaV1; } /** * Form options without schema validation. * * The `onSubmit` callback receives the raw field values typed according to the * form's initial state structure. * * @example * const form = reatomForm( * { email: '', age: 0 }, * { * onSubmit: (state) => { * // state is typed as { email: string; age: number } * sendToServer(state) * }, * validateBeforeSubmit: (state) => { * if (!state.email.includes('@')) throw new Error('Invalid email') * }, * }, * ) * * @template InitState - Initial state structure for form fields * @template SubmitReturn - Return type of onSubmit callback * @template SubmitParams - Additional parameters for submit action */ interface FormOptionsWithoutSchema extends BaseFormOptions { /** * The callback to process valid form data, typed according to the raw form * state */ onSubmit?: (state: FieldSetState, ...params: SubmitParams) => SubmitReturn | Promise; /** * The callback to validate form fields before submit, typed according to the * raw form state * * @deprecated Renamed to `validateBeforeSubmit` */ validate?: (state: FieldSetState) => any; /** * The callback to validate form fields before submit, typed according to the * raw form state */ validateBeforeSubmit?: (state: FieldSetState) => any; /** Schema is explicitly disallowed or undefined in this variant */ schema?: undefined; } /** * Resolves a field atom by its path within a form's field set. Useful for * mapping backend validation errors to the corresponding form fields, * especially when the error format follows the {@link StandardSchemaV1.Issue} * interface. * * Recursively traverses nested fields and field arrays to find the target * field. Path segments that are `symbol` values are not supported and will * cause the function to return `null`. * * @example * for (const error of response.errors) { * const field = resolveFieldByPath(error.path, registerForm.fields) * if (field) { * field.validation.errors.unshift({ * source: 'submission', * message: error.message, * }) * } * } * * @param path - The path segments from a {@link StandardSchemaV1.Issue}. Each * segment can be a string, number, or an object with a `key` property. * @param fields - The form's field set to search in (e.g. `form.fields`). * @returns The resolved {@link FieldAtom} or {@link FieldArrayAtom}, or `null` if * the path is empty, contains a `symbol` segment, or no matching field is * found. */ declare const resolveFieldByPath: (path: StandardSchemaV1.Issue["path"], fields: FieldsAtomize) => FieldAtom | FieldArrayAtom | null; /** * Creates a reactive form with validation, submit handling, and field * management. * * `reatomForm` is a wrapper over {@link reatomFieldSet} that adds: * * - Submit action with validation flow * - Standard Schema validation support (Zod, Valibot, ArkType, etc.) * - Form-level validation via `validateBeforeSubmit` * - Default field options propagation * * ## Field Initialization * * Fields can be initialized with: * * - Primitive values (creates `reatomField` automatically) * - `reatomField` instances (for custom options) * - `reatomFieldArray` instances (for dynamic lists) * * ## Submit Flow * * When `submit` is called: * * 1. All field validations are triggered * 2. Schema validation runs (if defined) * 3. `validateBeforeSubmit` callback runs (if defined) * 4. `onSubmit` callback runs with validated state * 5. `submitted` atom becomes `true` * * @example * // Basic form with schema validation * import { z } from 'zod' * * const form = reatomForm( * { email: '', age: 0 }, * { * schema: z.object({ * email: z.string().email(), * age: z.number().min(18, 'Must be 18+'), * }), * onSubmit: async (state) => { * await api.register(state) * }, * }, * ) * * // Access fields * form.fields.email.change('user@example.com') * form.fields.age.change(25) * * // Submit with error handling * await wrap(form.submit()).catch(noop) * if (form.submit.error()) console.log('Submit failed') * * @example * // Form with field-level validation * const form = reatomForm({ * email: reatomField('', { * validate: ({ value }) => { * if (!value.includes('@')) return 'Invalid email' * }, * validateOnChange: true, * }), * password: reatomField('', { * validate: async ({ value }) => { * if (value.length < 8) throw new Error('Too short') * }, * }), * }) * * @example * // Form with dynamic field arrays * const form = reatomForm({ * name: '', * items: reatomFieldArray({ * initState: ['initial'], * create: (param) => reatomField(param), * }), * }) * * form.fields.items.create('new item') * form.fields.items.clear() * * @example * // Submit with custom params and return type * const form = reatomForm( * { email: '' }, * { * onSubmit: async (state, skipDebounce: boolean) => { * return { state, skipDebounce } * }, * }, * ) * * const result = await wrap(form.submit(true)) * // result: { state: { email: '' }, skipDebounce: true } * * @param initState - Initial form state or factory function * @param options - Form options or name string * @returns Form atom with fields, validation, submit, and focus management * @see {@link https://reatom.dev/handbook/forms/concepts/form/|Form documentation} * @see {@link https://reatom.dev/handbook/forms/concepts/fieldset/|Fieldset documentation} */ declare function reatomForm(initState: InitState | ((name: string) => InitState), optionsWithSchema: FormOptionsWithSchema): FormAtom; declare function reatomForm(initState: InitState | ((name: string) => InitState), options?: FormOptionsWithoutSchema): FormAtom; declare function reatomForm(initState: InitState | ((name: string) => InitState), name?: string): FormAtom; /** @deprecated Renamed. Use FormAtom instead */ type Form = FormAtom; //#endregion //#region src/persist/web-storage/broadcastChannel.d.ts /** * Web storage persist interface that extends the base persist functionality * with a storage atom for managing the underlying storage mechanism. */ interface WithPersistWebStorage$1 extends WithPersist { /** Atom that holds the current storage instance */ storageAtom: Atom; } /** * Message format for BroadcastChannel communication between tabs. * * Supports two message types: * * - `push`: Broadcasts data changes to other tabs * - `pull`: Requests current data from other tabs */ type BroadcastMessage = { /** Push message containing updated data */_type: 'push'; /** Storage key for the data */ key: string; /** The persist record data, or null for deletions */ rec: PersistRecord | null; } | { /** Pull message requesting current data */_type: 'pull'; /** Storage key to request data for */ key: string; }; /** * Creates a BroadcastChannel-based persistence adapter for cross-tab * synchronization. * * Uses the BroadcastChannel API to synchronize atom state across multiple * browser tabs or workers. Provides real-time synchronization without server * involvement. Data is stored in memory and shared via message passing. * * @example * // Basic usage with automatic channel * const counterAtom = atom(0, 'counterAtom').extend( * withBroadcastChannel('shared-counter') * ) * * // Custom channel for specific use case * const gameChannel = new BroadcastChannel('game-state') * const gameStateAtom = atom({}, 'gameStateAtom').extend( * reatomPersistBroadcastChannel(gameChannel)('game-data') * ) * * // Multiple atoms sharing the same channel * const chatChannel = new BroadcastChannel('chat-app') * const messagesAtom = atom([], 'messagesAtom').extend( * reatomPersistBroadcastChannel(chatChannel)('messages') * ) * const usersAtom = atom([], 'usersAtom').extend( * reatomPersistBroadcastChannel(chatChannel)('users') * ) * * **Features:** * - Real-time cross-tab synchronization * - Memory-based storage with broadcast updates * - Pull-based data request system for late-joining tabs * - Graceful error handling for closed channels * - No server or persistent storage required * * **Use Cases:** * - Live collaborative features * - Cross-tab state synchronization * - Real-time notifications * - Shared application state * * @param channel - BroadcastChannel instance for cross-tab communication * @returns Persist adapter with cross-tab synchronization capabilities * @see {@link withBroadcastChannel} for default channel with automatic fallback * @see {@link BroadcastMessage} for message format details */ declare const reatomPersistBroadcastChannel: (channel: BroadcastChannel) => WithPersistWebStorage$1; declare const withBroadcastChannel: WithPersistWebStorage$1; //#endregion //#region src/persist/web-storage/cookie.d.ts /** * Web storage persist interface that extends the base persist functionality * with a storage atom for managing the underlying storage mechanism. */ interface WithPersistCookie extends WithPersist {} /** * Configuration options for HTTP cookies following standard cookie attributes. * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie */ interface CookieAttributes { /** Maximum age of the cookie in seconds. Takes precedence over `expires` */ maxAge?: number; /** Expiration date of the cookie. Ignored if `maxAge` is provided */ expires?: Date; /** Path where the cookie is valid. Defaults to current path */ path?: string; /** Domain where the cookie is valid. Defaults to current domain */ domain?: string; /** Whether the cookie should only be sent over HTTPS */ secure?: boolean; /** Controls when the cookie is sent with cross-site requests */ sameSite?: 'strict' | 'lax' | 'none'; /** * @deprecated Default `document.cookie` has no ability to subscribe to * changes. Use withCookieStore instead. */ subscribe?: never; } declare const withCookie: WithPersistCookie; //#endregion //#region src/persist/web-storage/cookieStore.d.ts /** * Web storage persist interface that extends the base persist functionality * with cookie store specific options. */ interface WithPersistCookieStore extends WithPersist {} /** * Configuration options for Cookie Store API following standard cookie * attributes. * * @see https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API */ interface CookieStoreOptions { /** Domain where the cookie is valid. Defaults to current domain */ domain?: string; /** Expiration date of the cookie as timestamp in milliseconds */ expires?: number; /** Path where the cookie is valid. Defaults to '/' */ path?: string; /** Controls when the cookie is sent with cross-site requests */ sameSite?: 'strict' | 'lax' | 'none'; } declare const withCookieStore: WithPersistCookieStore; //#endregion //#region src/persist/web-storage/indexedDb.d.ts /** * Web storage persist interface that extends the base persist functionality * with a storage atom for managing the underlying storage mechanism. */ interface WithPersistWebStorage extends WithPersist { /** Atom that holds the current storage instance */ storageAtom: Atom; } /** * Creates an IndexedDB-based persistence adapter with cross-tab * synchronization. * * Provides persistent storage using IndexedDB with real-time synchronization * across browser tabs via BroadcastChannel. Uses idb-keyval as an optional * dependency for simplified IndexedDB operations. Automatically falls back to * memory storage if IndexedDB or idb-keyval is unavailable. * * @example * // Custom IndexedDB with specific database name * const userDataChannel = new BroadcastChannel('user-data-sync') * const withUserDb = reatomPersistIndexedDb('user-db', userDataChannel) * const profileAtom = atom({}, 'profileAtom').extend( * withUserDb('user-profile') * ) * * // Application state with persistent storage * const appStateChannel = new BroadcastChannel('app-state') * const withAppDb = reatomPersistIndexedDb('app-state-db', appStateChannel) * const settingsAtom = atom({}, 'settingsAtom').extend( * withAppDb('app-settings') * ) * * // Large data sets that exceed localStorage limits * const dataChannel = new BroadcastChannel('large-data') * const withLargeDataDb = reatomPersistIndexedDb('large-data-db', dataChannel) * const cacheAtom = atom(new Map(), 'cacheAtom').extend( * withLargeDataDb('api-cache') * ) * * **Features:** * - Large storage capacity (hundreds of MB to GB depending on browser) * - Persistent storage that survives browser restarts * - Cross-tab synchronization via BroadcastChannel * - Asynchronous operations for better performance * - Automatic fallback to memory storage when unavailable * - Memory cache for immediate read access * * **Requirements:** * - idb-keyval package as peerDependency (optional, auto-detected) * - IndexedDB support in the browser * - BroadcastChannel support for cross-tab sync * * **Use Cases:** * - Large application data that exceeds localStorage limits * - Offline-capable applications with persistent storage * - Complex data structures and large datasets * - Applications requiring robust storage with transactions * * @param dbName - Name of the IndexedDB database to use * @param channel - BroadcastChannel for cross-tab synchronization * @returns Persist adapter with IndexedDB storage and cross-tab sync * @see {@link withIndexedDb} for default IndexedDB with automatic fallback * @see {@link withLocalStorage} for simpler persistent storage with size limits * @see {@link BroadcastMessage} for synchronization message format */ declare const reatomPersistIndexedDb: (dbName: string, channel: BroadcastChannel) => WithPersistWebStorage; declare const withIndexedDb: WithPersistWebStorage; //#endregion //#region src/persist/web-storage/localStorage.d.ts /** * Creates a Web Storage API persistence adapter for Reatom atoms. * * Works with any object that implements the Storage interface (localStorage, * sessionStorage, or custom storage implementations). Provides automatic JSON * serialization, memory caching, and cross-tab synchronization via storage * events. * * @example * // Using localStorage * const withMyLocalStorage = reatomPersistWebStorage('myApp', localStorage) * const settingsAtom = atom({}, 'settingsAtom').extend( * withMyLocalStorage('user-settings') * ) * * // Using sessionStorage * const withMySessionStorage = reatomPersistWebStorage('session', sessionStorage) * const tempDataAtom = atom(null, 'tempDataAtom').extend( * withMySessionStorage('temp-data') * ) * * // Custom storage implementation * const customStorage = { * getItem: (key) => myDatabase.get(key), * setItem: (key, value) => myDatabase.set(key, value), * removeItem: (key) => myDatabase.delete(key) * } * const withCustomStorage = reatomPersistWebStorage('db', customStorage) * * **Features:** * - Memory cache for performance optimization * - Cross-tab synchronization via storage events (for localStorage) * - Automatic expiration handling * - Graceful error handling for storage quota limits * - JSON serialization with fallback handling * * @param name - Unique identifier for this persist instance * @param storage - Storage object implementing the Web Storage API interface * @returns Persist adapter with memory cache and storage event synchronization * @see {@link withLocalStorage} for localStorage with automatic fallback * @see {@link withSessionStorage} for sessionStorage with automatic fallback */ declare const reatomPersistWebStorage: (name: string, storage: Storage) => WithPersist; declare const withLocalStorage: WithPersist; declare const withSessionStorage: WithPersist; //#endregion //#region src/reatomAbstractRender.d.ts /** * Interface representing an abstract renderer for connecting Reatom with other * reactive systems. Provides methods to render content with given props and * manage the lifecycle through mounting. * * @template Props - The type of props/parameters that the renderer accepts * @template Result - The type of result produced by the render operation */ interface AbstractRender { /** * Renders content using the provided props * * @param {Props} props - The properties used for rendering * @returns {{ result: Result }} - Object containing the render result */ render: (props: Props) => { result: Result; }; /** * Mounts the renderer, setting up subscriptions and event handling * * @returns {Unsubscribe} - Function to unmount and clean up resources */ mount: () => Unsubscribe; } /** * Creates a low-level renderer that connects Reatom with other reactive * systems. This function decorates computed rendering to prevent extra or * outdated rerenders, allowing a user render function to run only in the * context of the adapted reactive system. * * The renderer maintains proper reactivity by coordinating state updates * between Reatom's atom/computed system and the target rendering system. * * @example * // Creating a React renderer * const reactRenderer = reatomAbstractRender({ * frame, * render: (props) => React.createElement(Component, props), * rerender: ({ result }) => setElement(result), * name: 'ReactRenderer', * }) * * // Usage * const unmount = reactRenderer.mount() * reactRenderer.render({ prop1: 'value1' }) * * // Later cleanup * unmount() * * @template Props - The type of props/parameters that the renderer accepts * @template Result - The type of result produced by the render operation * @param {Object} options - Configuration options for the abstract renderer * @param {Frame} options.frame - The Reatom frame/context in which the * rendering occurs * @param {function} options.render - Function that renders content with the * given props * @param {function} options.rerender - Function called when a rerender is * needed * @param {function} [options.mount] - Optional function called when mounting * the renderer * @param {string} options.name - Name identifier for debugging purposes * @returns {AbstractRender} An object with render and mount * methods */ declare let reatomAbstractRender: ({ frame, render: adapterRender, rerender, name, abortOnUnmount }: { frame: Frame; render: (props: Props) => Result; rerender: (param: { result: Exclude; }) => any; name: string; abortOnUnmount: boolean; }) => AbstractRender; //#endregion //#region src/routing/route.types.d.ts type MaybeVoid = {} extends T ? T | void : T; /** * Extracts parameter types from a route path pattern string. * * Extracts parameter names from path patterns like `:userId`, `:postId?`, etc. * and creates a type mapping parameter names to their types. * * @example * type Params = PathParams<'users/:userId/posts/:postId?'> * // Params = { userId: string; postId?: string } * * @example * type Params = PathParams<':id'> * // Params = { id: string } */ type PathParams = Path extends `:${infer Param}/${infer Rest}` ? { [key in Param]: string } & PathParams : Path extends `:${infer MaybeOptionalParam}` ? MaybeOptionalParam extends `${infer OptionalParam}?` ? { [key in OptionalParam]?: string } : { [key in MaybeOptionalParam]: string } : Path extends `${string}/${infer Rest}` ? PathParams : {}; type PathKeys = Record, any>; /** * Type representing a rendered route component/child. * * Redeclare this type in your framework module to enable type-safe route * rendering. This allows you to use framework-specific types (like JSX.Element, * VNode, TemplateResult) as route children. * * @example * // For React/Preact * declare module '@reatom/core' { * interface RouteChild extends JSX.Element {} * } * * @example * // For Vue * declare module '@reatom/core' { * interface RouteChild extends VNode {} * } * * @example * // For Lit * declare module '@reatom/core' { * interface RouteChild extends TemplateResult {} * } */ interface RouteChild {} /** * Configuration options for creating a route. * * Routes can be created with just a path string, or with a full configuration * object that includes validation schemas, data loaders, and render functions. * * @example * // Simple path-only route * const route = reatomRoute('users/:userId') * * @example * // Route with validation and loader * const route = reatomRoute({ * path: 'users/:userId', * params: z.object({ * userId: z.string().regex(/^\d+$/).transform(Number), * }), * search: z.object({ tab: z.enum(['posts', 'comments']).optional() }), * async loader(params) { * return fetch(`/api/users/${params.userId}`).then((r) => r.json()) * }, * }) * * @example * // Search-only route (no path, preserves current pathname) * const dialogRoute = reatomRoute({ * search: z.object({ dialog: z.enum(['login', 'signup']).optional() }), * }) */ interface RouteOptions = PathParams, SearchInput extends Partial> = {}, ParamsOutput extends Rec = ParamsInput, SearchOutput extends Rec = SearchInput, LoaderParams = Plain, Payload = LoaderParams> { /** * Path pattern string. Use `:paramName` for required parameters and * `:paramName?` for optional parameters. * * @example * 'users/:userId' * * @example * 'posts/:postId?' * * @example * 'api/products/:productId/settings' */ path?: Path; /** * Schema to validate and transform path parameters. * * Accepts one of: * * - **Standard Schema** (Zod, Valibot, etc.) — one-directional validation. * `go()` accepts raw string params, the schema parses them on URL read. * - **Function** `(params) => result | null` — custom validator, return `null` * to unmatch the route. * - **{@link Codec}** `{ decode, encode }` — bidirectional transform. `go()` * accepts typed (Output) params, `encode` writes URL strings, `decode` * reads them back. Decode errors cause unmatch. * * @example * // Standard Schema * params: z.object({ * userId: z.string().regex(/^\d+$/).transform(Number), * }) * * @example * // Codec — go() accepts numbers, encode converts to strings * params: { * decode: (input) => ({ id: Number(input.id) }), * encode: (output) => ({ id: String(output.id) }), * } */ params?: StandardSchemaV1 | ((params: ParamsInput) => null | ParamsOutput) | Codec; /** * Schema to validate and transform search/query parameters. * * Accepts one of: * * - **Standard Schema** (Zod, Valibot, etc.) — one-directional validation. * `go()` accepts raw string params, the schema parses them on URL read. * - **{@link Codec}** `{ decode, encode }` — bidirectional transform. `go()` * accepts typed (Output) params, `encode` writes URL strings, `decode` * reads them back. Decode errors cause unmatch. * * Note: All search parameters should be optional in the schema. * * @example * // Standard Schema * search: z.object({ * sort: z.enum(['asc', 'desc']).optional(), * page: z.string().transform(Number).default('1'), * }) * * @example * // Codec — go() accepts numbers, encode converts to strings * search: { * decode: (input) => ({ page: Number(input.page) }), * encode: (output) => ({ page: String(output.page) }), * } */ search?: StandardSchemaV1 | Codec; /** * Async function that loads data when the route becomes active. * * Receives validated parameters (path + search params combined). * Automatically aborted when navigating away from the route. * * @example * async loader({ userId, tab }) { * const user = await fetch(`/api/users/${userId}`).then(r => r.json()) * return user * } */ loader?: (params: LoaderParams) => Promise; /** * Function that renders the route component. Receives the whole route object * with non-nullable state and all route properties (outlet, loader, etc.). * * This enables framework-agnostic component composition where routes define * their own components that are automatically composed hierarchically. * * @example * render(self) { * // self() returns params (non-nullable when render is called) * // self.outlet() returns active child route components * // self.loader for data loading state * return html`
*
My App
*
${self.outlet().map(child => child)}
*
` * } */ render?: (options: Computed> & RouteExt) => RouteChild; /** * When `true`, the route acts as a **layout** — its `render` fires on any * match (partial or exact) and wraps children through `outlet()`. * * When `false` (default), the route acts as a **feature/leaf** — `render` * only fires on exact URL matches. When a child route is active, `render` * returns `null` and children propagate through the outlet chain to the * nearest layout ancestor. * * @default false * @see RouteExt.exact */ layout?: boolean; /** * @deprecated Use `layout` instead (with inverted logic: `exactRender: true` * = `layout: false`). */ exactRender?: boolean; } /** * Bidirectional transformer for route parameters. * * Unlike one-directional Standard Schema transforms, a Codec defines both * directions: raw URL strings to typed values (`decode`) and back (`encode`). * * When `decode` throws, the route is treated as unmatched (returns `null`). * Navigation tries `encode` first; if it throws on a Standard Schema (e.g. Zod * one-way `.transform()`), validation is used for path segments and search * keeps the `go()` argument keys. On a plain codec object, `encode` errors * propagate. * * @example * // Inline codec for base64-encoded JSON in a path segment * reatomRoute({ * path: 'data/:payload', * params: { * decode: (input) => ({ * payload: JSON.parse(atob(input.payload)), * }), * encode: (output) => ({ * payload: btoa(JSON.stringify(output.payload)), * }), * }, * }) * * @example * reatomRoute({ * path: 'items/:id', * params: z.object({ id: z.stringbool() }), * }) */ type Codec = { decode: (input: Input) => Output; encode: (output: Output) => Input; }; type TrimPath = Path extends `//${infer Path}` ? TrimPath<`/${Path}`> : Path; type NestedParamsOutput = Plain; interface RouteMixin = PathParams, GoParams = Params> { /** * Create a sub-route by appending a path pattern to the current route. * * @example * const usersRoute = reatomRoute('users') // Creates /users route * const userRoute = usersRoute.reatomRoute(':userId') // Creates /users/:userId route * * @param path The sub-path pattern to append (e.g., 'users', ':userId', * 'posts/:postId?') * @returns A new RouteAtom for the combined path pattern */ reatomRoute(path: SubPath, name?: string): RouteAtom<`${Path}/${SubPath}`, Plain>, {}, {}, Plain>, {}, PathParams, {}>; /** * Create a sub-route with **{@link Codec}** for both params and search. * * `go()` and `path()` accept the codec's **Output** types — `encode` writes * URL-safe strings automatically. * * @example * const route = parentRoute.reatomRoute({ * path: 'items/:id', * params: { * decode: (input) => ({ id: Number(input.id) }), * encode: (output) => ({ id: String(output.id) }), * }, * search: { * decode: (input) => ({ page: Number(input.page) }), * encode: (output) => ({ page: String(output.page) }), * }, * }) * route.go({ id: 42, page: 3 }) */ reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain & SubSearchOutput>, Payload = LoaderParams>(options: RouteOptions & { params: Codec; search: Codec; }, name?: string): RouteAtom, Plain>, Plain, Payload, Plain, Plain, Plain, Plain>; /** Create a sub-route with a **params {@link Codec}**. */ reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain & SubSearchOutput>, Payload = LoaderParams>(options: RouteOptions & { params: Codec; }, name?: string): RouteAtom, Plain>, Plain, Payload, Plain, Plain, Plain, Plain>; /** Create a sub-route with a **search {@link Codec}**. */ reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain, Payload = LoaderParams>(options: RouteOptions & { search: Codec; }, name?: string): RouteAtom, Plain, Plain, Payload, Plain, Plain, Plain, Plain>; /** * Create a sub-route with validation schemas for parameters and search * params. * * @example * import { z } from 'zod' * * const userRoute = reatomRoute({ * path: 'user/:id', * params: z.object({ id: z.number() }), * search: z.object({ sort: z.enum(['asc', 'desc']).optional() }), * }) * * userRoute.go({ id: 123, tab: 'profile' }) */ reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain & SubSearchOutput>, Payload = LoaderParams>(options: RouteOptions & { params: StandardSchemaV1; }, name?: string): RouteAtom, Plain>, Plain, Payload, Plain, Plain, Plain, Plain>; reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain, Payload = LoaderParams>(options: RouteOptions & { params: (params: Params & SubParamsInput) => null | SubParamsOutput; }, name?: string): RouteAtom, Plain, Plain, Payload, Plain, Plain, Plain, Plain>; reatomRoute = PathParams, SubSearchInput extends Partial> = {}, SubParamsOutput extends Rec = SubParamsInput, SubSearchOutput extends Rec = SubSearchInput, LoaderParams = Plain, Payload = LoaderParams>(options: RouteOptions, name?: string): RouteAtom, Plain, Plain, Payload, Plain, Plain, Plain, Plain>; } /** * Route loader interface describing async data loading capabilities, mostly * crafted from `withAsyncData` extension, see `loader` property of a route for * examples. */ interface RouteLoader extends Computed>, AsyncDataExt<[Params], Payload, Payload, undefined, Error | undefined> {} /** Route navigation: `route.go(params)` and `route.go.relative(...)`. */ interface RouteGo extends Action<[params: MaybeVoid, replace?: boolean], URL> { relative: RouteGoRelative; } /** * Relative navigation: `route.go.relative(params)` merges current parent params * then calls `go`. Accepts only this route's own path/search args (no parent * keys). */ interface RouteGoRelative extends Action<[params?: MaybeVoid, replace?: boolean], URL> {} /** Route extension interface for route computed atom. */ interface RouteExt = PathParams, Search extends Rec = {}, Payload = Plain, GoParams = Params, GoSearch = Search, RelativeGoParams = GoParams, RelativeGoSearch = GoSearch> extends RouteMixin { /** * Navigate to this route with the given parameters. * * Updates the browser URL and triggers route matching. For search-only * routes, preserves the current pathname and only updates search parameters. * * @example * userRoute.go({ userId: '123' }) * // Navigates to /users/123 * * @example * searchRoute.go({ q: 'reatom', page: 2 }, true) * // Navigates to /search?q=reatom&page=2 and replaces history entry * * @example * homeRoute.go() // Navigate without parameters * // Navigates to / * * @param params - Route parameters (path + search). Can be omitted if route * has no required parameters. * @param replace - If `true`, replaces current history entry instead of * creating a new one. Defaults to `false`. * @returns The new URL object */ go: RouteGo; /** * Async loader for fetching route data. * * Automatically executes when the route becomes active. Extended with * `withAsyncData` extension, which provides loading state, error handling, * and retry functionality, automatically rerun (and abort prev run) on params * change, or just abort when navigating away. * * @example * const ready = userRoute.loader.ready() * const user = userRoute.loader.data() * const error = userRoute.loader.error() * userRoute.loader.retry() */ loader: RouteLoader, Payload>; /** * Computed atom indicating if the current URL exactly matches this route. * * Returns `true` only when the URL is an exact match (not a partial match). * Useful for conditional rendering that should only appear on the exact * route. * * @example * // At URL: /users/123 * usersRoute.exact() // false (partial match) * userRoute.exact() // true (exact match) * * @example * // Only show component on exact route * {userRoute.exact() && } */ exact: Computed; layout: boolean; /** * Computed atom indicating if the current URL matches this route (partial or * exact). * * Returns `true` when the route matches, `false` otherwise. More permissive * than `exact()` - returns true for both exact and partial matches. * * Helpful to track the route active state, and to create a route model with * memoization. * * Used under the hood of the `outlet` computed. * * @example * // At URL: /users/123/edit * usersRoute.match() // true (partial match) * userRoute.match() // true (partial match) * userEditRoute.match() // true (exact match) */ match: Computed; /** * The path pattern string for this route. * * Helpful for matching links or other route-related logic. * * @example * '/users/:userId' * * @example * '/posts/:postId?' */ pattern: Path; /** * Builds a URL path string for this route without navigating. * * Useful for creating links or programmatically constructing URLs. Includes * search parameters if the route has a search schema. * * @example * userRoute.path({ userId: '123' }) * // Returns: '/users/123' * * @example * searchRoute.path({ q: 'reatom', page: 2 }) * // Returns: '/search?q=reatom&page=2' * * @example * // Use in links * View User * * @param params - Route parameters (path + search). Can be omitted if route * has no required parameters. * @returns The URL path string (including search params if applicable) */ path: (params: MaybeVoid) => string; /** * Registry of all child routes created from this route. * * Routes are automatically registered here when created via `.reatomRoute()`. * Useful for accessing all child routes or implementing global route logic. * * @example * const layoutRoute = reatomRoute('dashboard') * const usersRoute = layoutRoute.reatomRoute('users') * const postsRoute = layoutRoute.reatomRoute('posts') * * // Access all child routes * layoutRoute.routes // { 'dashboard/users': usersRoute, 'dashboard/posts': postsRoute } */ routes: Rec; /** * Computed atom returning an array of all active child route components. * * Contains the rendered output from all child routes that are currently * matched. Used in parent route `render` functions to compose child * components. * * @example * const layoutRoute = reatomRoute({ * render(self) { * return html`
*
${self.outlet().map((child) => child)}
*
` * }, * }) */ outlet: Computed; /** * Computed atom returning the rendered component for this route, or `null`. * * Returns the result of the route's `render` function when the route matches, * `null` otherwise. Used to render route components in a component tree. * * @example * const App = reatomComponent(() => { * return layoutRoute.render() // Returns the rendered component or null * }) */ render: Computed; parent: RouteAtom | null; cachedParams: Atom; } /** * A route atom that matches URLs and provides navigation, loading, and * rendering. * * Routes are computed atoms that return route parameters when matched, or * `null` when not matched. They also provide navigation actions, data loading, * and component rendering capabilities. * * Routes can be created with `reatomRoute()` and nested using `.reatomRoute()`. * * @example * // Create a route * const userRoute = reatomRoute('users/:userId') * * // Use as computed atom * const params = userRoute() // { userId: '123' } or null * * // Navigate * userRoute.go({ userId: '456' }) * * // Create nested route * const userEditRoute = userRoute.reatomRoute('edit') * // Full path: /users/:userId/edit * * @example * // Route with validation and loader * const userRoute = reatomRoute({ * path: 'users/:userId', * params: z.object({ userId: z.string().transform(Number) }), * async loader({ userId }) { * return fetch(`/api/users/${userId}`).then((r) => r.json()) * }, * }) */ interface RouteAtom = PathParams, SearchOutput extends Rec = {}, Payload = Plain, GoParams = ParamsOutput, GoSearch = SearchOutput, RelativeGoParams = GoParams, RelativeGoSearch = GoSearch> extends Computed>, RouteExt {} //#endregion //#region src/routing/route.d.ts /** * Creates a new route atom with the given path pattern or configuration. * * Routes automatically sync with the browser URL and provide type-safe * navigation, parameter validation, data loading, and component rendering. * * @example * // Simple path route * const homeRoute = reatomRoute('') * const aboutRoute = reatomRoute('about') * const userRoute = reatomRoute('users/:userId') * * @example * // Route with validation schemas * import { z } from 'zod' * * const userRoute = reatomRoute({ * path: 'users/:userId', * params: z.object({ * userId: z.string().regex(/^\d+$/).transform(Number), * }), * search: z.object({ * tab: z.enum(['posts', 'comments']).optional(), * }), * }) * * userRoute() // null * userRoute.go({ userId: '123', tab: 'posts' }) * // URL: /users/123?tab=posts * userRoute() // { userId: 123, tab: 'posts' } * * @example * // Route with loader * const userRoute = reatomRoute({ * path: 'users/:userId', * async loader({ userId }) { * const user = await fetch(`/api/users/${userId}`).then((r) => * r.json(), * ) * return user * }, * }) * * @example * // Search-only route (preserves pathname) * const dialogRoute = reatomRoute({ * search: z.object({ * dialog: z.enum(['login', 'signup']).optional(), * }), * }) * * @example * // Route with component rendering * const layoutRoute = reatomRoute({ * render(self) { * return html`
*
My App
*
${self.outlet().map((child) => child)}
*
` * }, * }) * * @param pathOrOptions - Either a path pattern string or a route configuration * object * @param name - Optional name for the route atom (for debugging) * @returns A new RouteAtom instance */ declare let reatomRoute: RouteMixin<"">["reatomRoute"]; declare const is404: Computed; declare const isSomeLoaderPending: Computed; //#endregion //#region src/routing/searchParams.d.ts /** Interface for the search parameters atom. */ interface SearchParamsAtom extends Computed> { /** * Set a search parameter. * * @param key Parameter name * @param value Parameter value * @param replace Whether to replace the current history entry */ set: Action<[key: string, value: string, replace?: boolean], void>; /** * Delete a search parameter. * * @param key Parameter name to delete * @param replace Whether to replace the current history entry */ del: Action<[key: string, replace?: boolean], void>; /** * Create an atom that synchronizes with a specific search parameter. * * @param key Parameter name * @param parse Function to parse parameter string value to desired type */ lens(key: string, parse?: (value?: string) => T): Atom; /** * Create an atom that synchronizes with a specific search parameter using * advanced options. * * @param key Parameter name * @param options Configuration options for the lens * @param options.parse Optional function to parse the parameter string value * into the desired type * @param options.serialize Optional function to serialize the value back into * a string * @param options.replace Optional boolean to specify if history entries * should be replaced (default: false) * @param options.path Optional path to limit the scope of synchronization to * specific URL paths * @param options.name Optional name of the created atom */ lens(key: string, options: { parse?: (value?: string) => T; serialize?: (value: T) => undefined | string; replace?: boolean; path?: string; name?: string; }): Atom; } declare const searchParamsAtom: SearchParamsAtom; /** * Create an atom that synchronizes with a URL search parameter. * * @param key The parameter name to synchronize with * @param parse Function to parse string value to desired type */ declare function withSearchParams(key: string, parse?: (value?: string) => T): >(target: Target) => Target; /** * Create an atom that synchronizes with a URL search parameter. * * @param key Parameter name * @param options Configuration options for the lens * @param options.parse Optional function to parse the parameter string value * into the desired type * @param options.serialize Optional function to serialize the value back into a * string * @param options.replace Optional boolean to specify if history entries should * be replaced (default: false) * @param options.path Optional path to limit the scope of synchronization to * specific URL paths * @param options.name Optional name of the created atom */ declare function withSearchParams(key: string, options: { parse?: (value?: string) => T; serialize?: (value: T) => undefined | string; replace?: boolean; path?: string; }): >(target: Target) => Target; //#endregion //#region src/web/fetch.d.ts type UrlSearchParamsInit = ConstructorParameters[0]; interface FetchRequestInit extends RequestInit { url?: string | URL; origin?: string; transport?: typeof globalThis.fetch; getInit?: (...params: Params) => { searchParams?: UrlSearchParamsInit; body?: Record | Array | BodyInit; }; getResult?: (response: Response) => Result | Promise; } declare let FetchRequest: { new (init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): { init: Required>; clone(): /*elided*/any; extends(init: FetchRequestInit): /*elided*/any; fetch(...params: P_9): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_8): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_7): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_6): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_5): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_4): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_3): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_2): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P_1): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: P): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; fetch(...params: Params): Promise; readonly cache: RequestCache; readonly credentials: RequestCredentials; readonly destination: RequestDestination; readonly headers: Headers; readonly integrity: string; readonly keepalive: boolean; readonly method: string; readonly mode: RequestMode; readonly redirect: RequestRedirect; readonly referrer: string; readonly referrerPolicy: ReferrerPolicy; readonly signal: AbortSignal; readonly url: string; readonly body: ReadableStream> | null; readonly bodyUsed: boolean; arrayBuffer(): Promise; blob(): Promise; bytes(): Promise>; formData(): Promise; json(): Promise; text(): Promise; }; defaults: { origin: string; transport: typeof fetch; method: string; headers: { Accept: string; }; getResult(response: Response): Promise; getInit: () => {}; }; }; //#endregion //#region src/web/onEvent.d.ts type EventOfCallback = NonNullable extends ((this: unknown, ...params: infer Params) => unknown) ? Params[0] : NonNullable extends ((...params: infer Params) => unknown) ? Params[0] : never; type EventOfTarget = Target extends Record<`on${Type}`, infer Callback> ? EventOfCallback : Target extends Record<'onEvent', (type: Type, cb: infer Callback) => unknown> ? EventOfCallback : never; /** * Integrates external event sources (DOM elements, WebSockets, etc.) with * Reatom's reactive system and abort context. * * Can be used in two ways: * * 1. **As a Promise** (without callback): Returns a promise that resolves when the * event fires once. Use with `await wrap(onEvent(...))` in actions to wait * for events while respecting abort contexts. * 2. **As a Subscription** (with callback): Registers a callback that fires on * each event occurrence. Returns an unsubscribe function for cleanup. * * When used within an action with abort context, `onEvent` automatically cleans * up listeners when the action is aborted or when a component unmounts, * preventing memory leaks and stale event handlers. * * @example * import { action, onEvent, wrap } from '@reatom/core' * * const handleUserAction = action(async () => { * const button = document.getElementById('confirmButton') * * const clickEvent = await wrap(onEvent(button, 'click')) * console.log(clickEvent.clientX, clickEvent.clientY) * * processUserConfirmation() * }, 'handleUserAction').extend(withAbort()) * * @example * import { atom, effect, onEvent } from '@reatom/core' * * const activeVideoAtom = atom(null, 'activeVideo') * const videoStatsAtom = atom({ plays: 0, pauses: 0 }, 'videoStats') * * effect(() => { * const videoElement = activeVideoAtom() * if (!videoElement) return * * // the listener will be cleared automatically, when the new videoElement is set * onEvent(videoElement, 'play', () => { * videoStatsAtom.set((stats) => ({ ...stats, plays: stats.plays + 1 })) * }) * onEvent(videoElement, 'pause', () => { * videoStatsAtom.set((stats) => ({ * ...stats, * pauses: stats.pauses + 1, * })) * }) * }) * * @param target - The event target (DOM element, WebSocket, etc.) * @param type - The event type to listen for (e.g., 'click', 'message') * @param cb - Optional callback function. If omitted, returns a Promise * @param options - Optional event listener options (capture, passive, etc.) * @returns A Promise resolving to the event (if no callback), or an unsubscribe * function (if callback provided) * @note Uses `abortVar.subscribe()` internally to connect the event listener * lifecycle to Reatom's abort context. The listener is automatically removed when * the associated AbortController signals abortion, which happens when the parent * action is aborted, a component unmounts, or when `withAbort()` cancels a * previous execution (`effect` do it automatically). */ declare const onEvent: { ? Type : string)>(target: Target, type: Type): Promise>; (target: EventTarget, type: string): Promise; ? Type : string)>(target: Target, type: Type, cb: (value: EventOfTarget) => any, options?: AddEventListenerOptions): Unsubscribe; (target: EventTarget, type: string, cb: (value: Event) => any, options?: AddEventListenerOptions): Unsubscribe; }; //#endregion //#region src/web/onLineAtom.d.ts type OnlineAtom = Atom & { /** Time stamp of transition to online mode. */offlineAtAtom: Atom; /** Time stamp of transition to offline mode. */ onlineAtAtom: Atom; }; declare let onLineAtom: OnlineAtom; //#endregion //#region src/web/rAF.d.ts declare let rAF: Atom<{ timestamp: number; delta: number; }, [newState: { timestamp: number; delta: number; }]>; //#endregion //#region src/web/reatomMediaQuery.d.ts /** * Creates a reactive atom that tracks a CSS media query state. * * The atom automatically updates when the media query match state changes, * providing a reactive way to respond to viewport changes, dark mode * preferences, and other media features. * * @example * const isMobile = reatomMediaQuery('(max-width: 767px)') * const isPrint = reatomMediaQuery('print') * * @example * const isDarkModeMedia = reatomMediaQuery('(prefers-color-scheme: dark)') * * const themeAtom = reatomEnum( * ['light', 'dark', 'system'], * 'themeAtom', * ).extend( * withComputed((state) => { * if (state === 'system') return isDarkModeMedia() ? 'dark' : 'light' * return state * }), * withLocalStorage('theme'), * withChangeHook((state) => { * if (state === 'system') { * document.body.classList.remove('light', 'dark') * } else { * document.body.classList.toggle('dark', state === 'dark') * } * }), * ) * * @param query - A CSS media query string (e.g., '(min-width: 768px)', * '(prefers-color-scheme: dark)') * @returns An atom that holds the current match state as a boolean */ declare let reatomMediaQuery: (query: string) => Atom & { mediaQueryList: Atom, [newState: Pick]>; }; //#endregion //#region src/web/reatomWebSocket.d.ts type WebSocketReadyState = 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED'; interface WebSocketMessage { data: T; timestamp: number; type: 'message' | 'error'; } interface WebSocketAtom extends Atom>> { /** Current connection state */ readyState: Atom; /** Current WebSocket instance (null if not connected) */ socket: Atom; /** Connection URL */ url: Atom; /** Connection protocols */ protocols: Atom>; /** Auto-reconnect enabled */ autoReconnect: Atom; /** Reconnect attempts count */ reconnectAttempts: Atom; /** Last error */ error: Atom; /** Connection established timestamp */ connectedAt: Atom; /** Connection closed timestamp */ closedAt: Atom; /** Whether currently connected */ isConnected: Atom; /** Whether currently connecting */ isConnecting: Atom; /** Latest message */ latestMessage: Atom | null>; /** Connect to WebSocket */ connect: Action<[], Promise>; /** Disconnect from WebSocket */ disconnect: Action<[code?: number, reason?: string], void>; /** Send message */ send: Action<[data: string | ArrayBuffer | Blob | ArrayBufferView], void>; /** Send JSON message */ sendJson: Action<[data: any], void>; /** Clear message history */ clearMessages: Action<[], void>; /** Clear errors */ clearError: Action<[], void>; /** Force reconnect */ reconnect: Action<[], Promise>; } interface WebSocketOptions { /** WebSocket URL */ url: string; /** WebSocket protocols */ protocols?: Array; /** Auto-reconnect on connection loss */ autoReconnect?: boolean; /** Reconnect delay in milliseconds */ reconnectDelay?: number; /** Maximum reconnect attempts (0 for infinite) */ maxReconnectAttempts?: number; /** Maximum number of messages to keep in history */ maxMessages?: number; /** Message parser function */ messageParser?: (data: any) => any; /** Debug name for the WebSocket instance */ name?: string; } declare const experimental_reatomWebSocket: (options: WebSocketOptions | string) => WebSocketAtom; //#endregion //#region src/web/url.d.ts /** URL atom interface that extends the base Atom type. */ interface UrlAtom extends Atom { /** * Update the URL atom with a new URL. * * @param url New URL to set * @param replace Whether to replace the current history entry */ set(url: URL, replace?: boolean): URL; /** * Update the URL with a function that receives the current URL. * * @param update Function that takes current URL and returns new URL * @param replace Whether to replace the current history entry */ set(update: (url: URL) => URL, replace?: boolean): URL; /** * Navigate to a new path. * * @param path The path to navigate to * @param replace Whether to replace the current history entry */ go: (path: string, replace?: boolean) => URL; /** * Whether to intercept link clicks for SPA navigation. * * @default true */ catchLinks: Atom; /** * This initialize DOM subscriptions and returns the current URL. To prevent * this action calling (in server on other environments without DOM), just * call `urlAtom` with your custom URL before it will be reded in other * places. */ init: Action<[], URL> & AbortExt; /** * Synchronization callback to push URL state updates to the `history`. * Replace with `noop` to disable syncing. */ sync: Atom<(url: URL, replace?: boolean) => void>; /** * For integrations use: put the new URL from the the source of truth to * `urlAtom`, without syncing it back (calling callback in `sync` Atom). * * @param url The URL from the source * @param replace Whether to replace the current history entry */ syncFromSource: Action<[url: URL, replace?: boolean], URL>; routes: Rec; pattern: '/'; } declare let urlAtom: UrlAtom; //#endregion export { AbortError, AbortExt, AbortSubscription, AbortVariable, AbstractRender, Action, ActionCall, ActionState, ActionsExt, ArrayAtom, ArrayFieldItem, Assign, AssignerExt, AsyncAtom, AsyncDataExt, AsyncDataOptions, AsyncExt, AsyncOptions, AsyncVariableOptions, Atom, AtomInitState, AtomLike, AtomMeta, AtomParams, AtomState, BaseFieldExt, BaseFieldExtOptions, BaseFormOptions, BooleanAtom, type BroadcastMessage, CacheAtom, CacheMapRecord, CacheRecord, CacheVarState, Codec, Computed, Constructor, ContextAtom, ControlledPromise, type CookieAttributes, type CookieStoreOptions, Deatomize, DeepPartial, DynamicSubscriptionExt, EXTENSIONS, Effect, EnumAtom, EnumAtomOptions, EnumFormat, EventOfTarget, Ext, Extend, Falsy, FetchRequest, FetchRequestInit, FieldArrayAtom, FieldArrayItem, FieldArrayLLNode, FieldArrayOptions, FieldArrayState, FieldAtom, FieldElementRef, FieldError, FieldErrorBody, FieldErrorSource, FieldExt, FieldExtOptions, FieldFocus, FieldLikeAtom, FieldOptions, FieldSet, FieldSetAtom, FieldSetFieldError, FieldSetInitState, FieldSetPartialState, FieldSetState, FieldSetValidation, FieldValidateOption, FieldValidateOptionResult, FieldValidation, Fn, FocusAtom, Form, FormAtom, FormInitState, FormOptionsWithSchema, FormOptionsWithoutSchema, FormPartialState, FormState, Frame, FunctionSource, GAction, GenericExt, LLNode, LL_NEXT, LL_PREV, LinkedList, LinkedListAtom, LinkedListDerivedAtom, LinkedListDerivedState, LinkedListLikeAtom, LinkedListSymbols, MAX_SAFE_TIMEOUT, MapAtom, MaybeUnsubscribe, Merge, Middleware, MiddlewarePlace, Newable, NumberAtom, OmitValues, OmitValuesKeys, OverloadParameters, Overloads, ParamsExt, PathKeys, PathParams, PersistCache, PersistRecord, PersistStorage, PersistStorageCacheOption, PickValues, PickValuesKeys, Plain, Queue, QueueKind, ReatomAbortController, ReatomError, ReatomGlobal, Rec, RecordAtom, Rollback, Rollbacks, RootFrame, RootState, RouteAtom, RouteChild, RouteExt, RouteGo, RouteGoRelative, RouteLoader, RouteMixin, RouteOptions, STACK, SUSPENSE, SearchParamsAtom, SetAtom, Shallow, Store, StringAtom, SubmitAction, SuspenseExt, SuspenseRecord, SyncPersistStorage, TransactionExt, TransformableFieldExtOptions, TransformableFieldOptions, TrimPath, UndefinedToOptional, Unsubscribe, UrlAtom, UrlSearchParamsInit, VERSION, ValidationAtom, ValidationlessFieldSet, ValidationlessFieldSetAtom, Values, Variable, WebSocketAtom, WebSocketMessage, WebSocketOptions, WebSocketReadyState, WithCacheOptions, WithPersist, WithPersistOptions, WithRequiredPersistOptions, __GLOBAL_ATOMS, _copy, _createGlobal, _enqueue, _isPubsChanged, _mark, _read, _set, _trackAction, abortVar, action, addCallHook, addChangeHook, addErrorHook, addGlobalExtension, anonymizeNames, assert, assertFn, assertPersistRecord, assign, atom, batch, bind, cacheMiddleware, cacheVar, clearStack, computed, computedMiddleware, computedParamsMiddleware, concatTree, connectLogger, context, createAtom, createMemStorage, deatomize, defaultRollback, effect, ensureReatomGlobal, entries, experimental_fieldArray, experimental_reatomWebSocket, extend, fieldInitFocus, fieldInitValidation, fieldInitValidationLess, framePromise, fromEntries, getCalls, getSerial, getStackTrace, identity, ifChanged, is404, isAbort, isAction, isAtom, isBrowser, isCausedBy, isChanged, isComputed, isConnected, isDeepEqual, isFieldArrayAtom, isFieldAtom, isInit, isLinkedListAtom, isObject, isPersistRecord, isRec, isShallowEqual, isSkip, isSomeLoaderPending, isWritableAtom, jsonClone, keys, log, memo, memoKey, merge, mock, mockRandom, named, nonNullable, noop, notify, omit, onEvent, onLineAtom, peek, pick, rAF, race, random, reatomAbstractRender, reatomArray, reatomBoolean, reatomEnum, reatomField, reatomFieldArray, reatomFieldSet, reatomForm, reatomLens, reatomLinkedList, reatomMap, reatomMediaQuery, reatomNumber, reatomObservable, reatomPersist, reatomPersistBroadcastChannel, reatomPersistIndexedDb, reatomPersistWebStorage, reatomRecord, reatomRoute, reatomSet, reatomString, reatomTransaction, removeItem, reset, resolveFieldByPath, retryComputed, rollback, run, schedule, searchParamsAtom, setTimeout$1 as setTimeout, settled, sleep, suspense, take, throwAbort, throwIfAborted, toAbortError, toStringKey, top, transactionVar, urlAtom, variable, withAbort, withActionMiddleware, withActions, withAsync, withAsyncData, withBaseField, withBroadcastChannel, withCache, withCallHook, withChangeHook, withComputed, withConnectHook, withCookie, withCookieStore, withDisconnectHook, withDynamicSubscription, withErrorHook, withField, withIndexedDb, withInit, withInitHook, withLocalStorage, withMemo, withMiddleware, withObservable, withParams, withResolvers, withRollback, withSearchParams, withSessionStorage, withSuspense, withSuspenseInit, withSuspenseRetry, withTap, withToJson, withTransaction, wrap }; //# sourceMappingURL=index.d.ts.map