/** * Process-local invalidation for connecting writes to dependent reads. * * This module does not cache values itself. It lets callers register handlers * for keys, invalidate those keys, wrap successful mutations so they invalidate * keys, and expose effects as queues or streams that rerun when matching keys * change. The service can also batch invalidations so handlers run after the * batch completes. * * @stability unstable * @since 4.0.0 */ import * as Context from "../Context.ts"; import * as Effect from "../Effect.ts"; import * as Layer from "../Layer.ts"; import * as Queue from "../Queue.ts"; import type { ReadonlyRecord } from "../Record.ts"; import * as Scope from "../Scope.ts"; import * as Stream from "../Stream.ts"; /** * Brand type for `Reactivity`. * * @stability unstable * @category type IDs * @since 4.0.0 */ export type TypeId = "~effect/reactivity/Reactivity"; /** * Brand for `Reactivity` implementations. * * @stability unstable * @category type IDs * @since 4.0.0 */ export declare const TypeId: TypeId; /** * Registry of reactivity keys and the ID type each key accepts. * * **Details** * * The registry is empty by default, and every key name and ID is accepted. * Once an application declares keys through module augmentation, the public * reactivity APIs (`Reactivity.mutation`, `Reactivity.query`, * `Reactivity.stream`, `Reactivity.invalidate`, `Atom`, `AtomHttpApi`, * `AtomRpc`, `SqlClient.reactive` and `EventLog.groupReactivity`) only accept * declared key names, and record IDs must match the declared ID type. Declare * a key as `never` if it is only used in array form. * * **Gotchas** * * Only applications should augment this interface, never libraries. The * augmentation applies to the whole program, so a library declaring keys would * switch every consumer to strict keys. * * Methods on the `Reactivity` service still accept any key, for code that only * knows its keys at runtime. * * **Example** (Declaring reactivity keys) * * ```ts import.meta.vitest * import { Effect } from "effect" * import { Reactivity } from "effect/reactivity" * * declare module "effect/reactivity/Reactivity" { * interface Keys { * readonly users: number * readonly events: never * } * } * * // Invalidates the `users` query with ID 1 and every `events` query * const program = Effect.succeed("saved").pipe( * Reactivity.mutation({ users: [1] }), * Effect.andThen(Reactivity.invalidate(["events"])) * ) * ``` * * @stability unstable * @category models * @since 4.0.0 */ export interface Keys { } /** * Keys accepted by the public reactivity APIs. * * **Details** * * With no keys declared in {@link Keys}, any array of keys or record of key IDs * is accepted. Once keys are declared, only declared key names and their ID * types are accepted. * * @stability unstable * @category models * @since 4.0.0 */ export type KeysInput = [keyof Keys] extends [never] ? ReadonlyArray | ReadonlyRecord> : ReadonlyArray | { readonly [K in keyof Keys]?: ReadonlyArray; }; /** * Registers handlers and reruns queries when their keys are invalidated. * * @stability unstable * @category models * @since 4.0.0 */ export interface Reactivity { readonly [TypeId]: TypeId; readonly invalidateUnsafe: (keys: ReadonlyArray | ReadonlyRecord>) => void; readonly registerUnsafe: (keys: ReadonlyArray | ReadonlyRecord>, handler: () => void) => () => void; readonly invalidate: (keys: ReadonlyArray | ReadonlyRecord>) => Effect.Effect; readonly mutation: (keys: ReadonlyArray | ReadonlyRecord>, effect: Effect.Effect) => Effect.Effect; readonly query: (keys: ReadonlyArray | ReadonlyRecord>, effect: Effect.Effect) => Effect.Effect, never, R | Scope.Scope>; readonly stream: (keys: ReadonlyArray | ReadonlyRecord>, effect: Effect.Effect) => Stream.Stream>; readonly withBatch: (effect: Effect.Effect) => Effect.Effect; } /** * Service key for reactive invalidation. * * @stability unstable * @category services * @since 4.0.0 */ export declare const Reactivity: Context.Service; /** * Creates an in-memory `Reactivity` service. * * **Details** * * The service tracks handlers by hashed keys and runs the registered handlers when * matching keys are invalidated. * * @stability unstable * @category constructors * @since 4.0.0 */ export declare const make: Effect.Effect; /** * Wraps an effect so the supplied keys are invalidated after the effect succeeds. * * **Gotchas** * * If the effect fails, the keys are not invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ export declare const mutation: { /** * Wraps an effect so the supplied keys are invalidated after the effect succeeds. * * **Gotchas** * * If the effect fails, the keys are not invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ (keys: KeysInput): (effect: Effect.Effect) => Effect.Effect; /** * Wraps an effect so the supplied keys are invalidated after the effect succeeds. * * **Gotchas** * * If the effect fails, the keys are not invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ (effect: Effect.Effect, keys: KeysInput): Effect.Effect; }; /** * Runs an effect as a query tied to the supplied invalidation keys. * * **Details** * * The returned queue receives the initial result and each later result after the * keys are invalidated. The registration is removed when the current scope closes. * * @stability unstable * @category accessors * @since 4.0.0 */ export declare const query: { /** * Runs an effect as a query tied to the supplied invalidation keys. * * **Details** * * The returned queue receives the initial result and each later result after the * keys are invalidated. The registration is removed when the current scope closes. * * @stability unstable * @category accessors * @since 4.0.0 */ (keys: KeysInput): (effect: Effect.Effect) => Effect.Effect, never, R | Scope.Scope | Reactivity>; /** * Runs an effect as a query tied to the supplied invalidation keys. * * **Details** * * The returned queue receives the initial result and each later result after the * keys are invalidated. The registration is removed when the current scope closes. * * @stability unstable * @category accessors * @since 4.0.0 */ (effect: Effect.Effect, keys: KeysInput): Effect.Effect, never, R | Scope.Scope | Reactivity>; }; /** * Runs an effect as a stream of query results tied to the supplied invalidation * keys. * * **Details** * * The effect runs initially and reruns whenever the keys are invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ export declare const stream: { /** * Runs an effect as a stream of query results tied to the supplied invalidation * keys. * * **Details** * * The effect runs initially and reruns whenever the keys are invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ (keys: KeysInput): (effect: Effect.Effect) => Stream.Stream | Reactivity>; /** * Runs an effect as a stream of query results tied to the supplied invalidation * keys. * * **Details** * * The effect runs initially and reruns whenever the keys are invalidated. * * @stability unstable * @category accessors * @since 4.0.0 */ (effect: Effect.Effect, keys: KeysInput): Stream.Stream | Reactivity>; }; /** * Invalidates the supplied keys through the `Reactivity` service. * * **Details** * * Registered queries for matching keys are rerun immediately, or collected until * the enclosing reactivity batch completes. * * @stability unstable * @category accessors * @since 4.0.0 */ export declare const invalidate: (keys: KeysInput) => Effect.Effect; /** * The default layer that provides an in-memory `Reactivity` service. * * @stability unstable * @category layers * @since 4.0.0 */ export declare const layer: Layer.Layer; //# sourceMappingURL=Reactivity.d.ts.map