import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import { ReactNode } from "react"; import * as Equal from "effect/Equal"; import * as Context from "effect/Context"; import * as Scope from "effect/Scope"; //#region src/domain/protocol.d.ts /** * The one unavoidable `any` in the framework. The heterogeneous yield protocol * must accept an Effect of *any* error and requirement variance — there is no * other way to express "some Effect" as a generic constraint, which is why * Effect's own `Effect.gen` is typed exactly this way. Precise `E` and `R` are * recovered below through conditional inference, so this never leaks to users. */ type AnyEffect = Effect.Effect; /** Brand identifying a lifted React hook instruction. */ declare const HookTypeId: unique symbol; type HookTypeId = typeof HookTypeId; /** * A React hook result lifted into the `yield*` channel. The hook itself has * already executed (synchronously, during render) by the time the value is * wrapped — `hook(useState(0))` calls `useState` inline. Wrapping it only makes * the result yieldable, so a component body reads as one uniform stream of * `yield*`s whether the value comes from Effect or from React. */ interface Hook { readonly [HookTypeId]: true; readonly value: A; [Symbol.iterator](): Iterator, A>; } /** * Lift an already-evaluated React hook result into the effract yield channel. * * ```ts * const [tab, setTab] = yield* hook(useState('overview')); * const ref = yield* hook(useRef(null)); * ``` * * Because the component body runs synchronously inside React's render pass, the * wrapped hook call obeys the Rules of Hooks: same order on every render. */ declare const hook: (value: A) => Hook; /** Type guard: is this yielded instruction a lifted hook? */ declare const isHook: (u: unknown) => u is Hook; /** Brand identifying a suspensable instruction (a `suspend`/`query`). */ declare const SuspensableTypeId: unique symbol; type SuspensableTypeId = typeof SuspensableTypeId; /** * The fourth kind of yieldable: a *suspensable* — a component's declared * asynchronous dependency. Unlike a raw `yield* effect` (which the interpreter * may still suspend on, but silently), yielding a suspensable both suspends for * the value *and* contributes a {@link Suspends} obligation to the REC's type, * so the loading state must be handled somewhere (`.suspense(...)`, or the * `mount` boundary) before the tree compiles. Its `effect` carries the `E` and * `R` channels, which bubble as a yielded effect's do — so retries, timeouts and * cancellation are just Effect combinators on `effect`, and its failures are * catchable with `.catch`. `key` (compared by value) drives refetch; `undefined` * means load-once. Both {@link suspend} and {@link query} produce this. */ interface Suspensable { readonly [SuspensableTypeId]: true; readonly effect: Effect.Effect; readonly key: unknown; /** Invalidation tags — `invalidate(tag)` re-runs every query carrying it. */ readonly tags?: ReadonlyArray; /** * How long (ms) a settled value stays *fresh*. Within it, a read serves the * cached value with no refetch. Past it, the read still serves the cached value * immediately but triggers a background revalidation (stale-while-revalidate). * `0` (the default) means always-fresh-once: no automatic revalidation. */ readonly staleTime?: number; /** * When true, this effect is run against a **component-lifetime Scope** the * interpreter creates on first need and closes on unmount — so an * `acquireRelease` resource yielded here has its finalizer run exactly once when * the component goes away. Set by {@link scoped}. */ readonly scoped?: boolean; [Symbol.iterator](): Iterator, A>; } /** Options for {@link query}: invalidation `tags` and a `staleTime` (ms). */ interface QueryOptions { readonly tags?: ReadonlyArray; readonly staleTime?: number; } /** * The suspensable primitive: run `effect`, suspend the render until it settles * (through React's `use`), and return its value — declaring a loading obligation * the type system makes you handle. Load-once: it runs a single time per * component instance and position, deduped across every render attempt (including * the pre-commit retries React makes when a component suspends before it first * commits), and its in-flight fiber is interrupted when the component unmounts. * * It is the building block {@link query} is made of — reach for `suspend` to * opt an effect into Suspense without query's keyed-refetch semantics, or to * build your own async abstractions on top. * * ```ts * const config = yield* suspend(loadConfig()); // load-once * const feed = yield* suspend(load.pipe(Effect.timeout('2s'))); // policies via Effect * ``` */ declare const suspend: (effect: Effect.Effect) => Suspensable; declare const query: ((effect: Effect.Effect, key?: unknown, options?: QueryOptions) => Suspensable) & { enabled: (effect: Effect.Effect, key: unknown, enabled: boolean, options?: QueryOptions) => Suspensable, E, R>; }; /** * Yield a **scoped resource** whose finalizer runs when the component unmounts. * The effect may `Effect.acquireRelease` (or otherwise require a `Scope`); effract * creates one `Scope` per component instance on first need and closes it on * unmount (StrictMode-safe), so the resource is acquired once and released exactly * once. The `Scope` is provided here, so it does **not** bubble to `mount` — only * the effect's other requirements do. Like `suspend`, it carries the loading * obligation `S` (acquisition may be async). * * ```ts * const socket = yield* scoped( * Effect.acquireRelease(openSocket(url), (s) => Effect.sync(() => s.close())), * ); * ``` */ declare const scoped: (effect: Effect.Effect) => Suspensable>; /** Type guard: is this yielded instruction a suspensable (`suspend`/`query`)? */ declare const isSuspensable: (u: unknown) => u is Suspensable; /** Brand identifying a reactive atom instruction. */ declare const AtomTypeId: unique symbol; type AtomTypeId = typeof AtomTypeId; /** * The fifth kind of yieldable: a *reactive atom read*. Reactive state lives in * the Effect world — an atom, usually held by a service. Yielding one reads its * current value *and* subscribes the component, so it re-renders precisely when * that atom changes: `const n = yield* count`. It carries no `E`/`R`/`S` — a * read is synchronous, needs nothing, and cannot fail — but it does carry the * render channel: `V`, the volatility obligation ({@link Volatile}) of a * high-frequency source, and `L`, the label literal naming what a subscribed * component re-renders on. Derived atoms * (`derive(...)`) are `ReadableAtom`s too, so they read and yield identically. * The concrete atom is built in the React binding; the domain only names the * contract — a value you can read, subscribe to, and `yield*`. */ interface ReadableAtom { readonly [AtomTypeId]: true; /** The current value — read imperatively (in an event handler or a method). */ readonly value: A; /** Subscribe to changes; returns an unsubscribe. Backs the in-render read. */ subscribe(listener: () => void): () => void; /** * Derive a new read-only atom from *this one's* value — the ergonomic, * single-source form of `derive`. The callback receives the value directly (no * `$`), and the result recomputes when this atom changes; chain it freely. * For a value computed from *several* atoms, reach for the explicit-sources * `derive([a, b], ([x, y]) => …)`. * The result inherits this atom's `V` and `L` — a derive of a volatile atom * stays volatile, and attribution keeps pointing at the source label. * * ```ts * const count = items.derive((list) => list.length); * ``` */ derive(f: (value: A) => B): ReadableAtom; [Symbol.iterator](): Iterator, A>; } /** A writable reactive atom — a {@link ReadableAtom} you can also `set`/`update`. */ interface Atom extends ReadableAtom { set(value: A): void; update(update: (previous: A) => A): void; } /** Type guard: is this yielded instruction a reactive atom read? */ declare const isAtom: (u: unknown) => u is ReadableAtom; /** * The phantom marker of an *unhandled loading obligation*. A body that yields a * {@link Suspensable} (or places a child that still carries one) has this in its * `S` channel; `.suspense(fallback)` — or the `mount` boundary — discharges it * back to `never`. It never exists at runtime; it exists only so the type system * can insist a loading state is handled somewhere between component and root. The * branded field is nominal — it makes `Suspends` distinct from `never` and from * any ordinary type, so the discharge checks are exact. Loading is a single * catch-all obligation (not a union like the tagged error channel): a pending * effect has no tag, so one `.suspense` discharges the whole subtree beneath it. */ interface Suspends { readonly ['@tmonier/effract/loading']: true; } /** * The phantom marker of an *unhandled volatility obligation*. A body that reads * a high-frequency atom (one born volatile, e.g. from `atom.fromStream`) — or * places a child that still carries one — has this in its `V` channel: the * subscription re-renders the component on every emission, so `mount` refuses * the tree until the read is deferred (`defer(atom)`) or the component * deliberately acknowledges the heat (`.hot()`), discharging it back to * `never`. It never exists at runtime; it exists only so the type system can * insist a hot subscription is scheduled somewhere between component and root. * The branded field is nominal — it makes `Volatile` distinct from `never` and * from any ordinary type, so the discharge checks are exact. */ interface Volatile { readonly ['@tmonier/effract/volatile']: true; } /** Everything a body may `yield*`: an Effect, a hook, a placement, a query, or an atom read. */ type Yieldable = Effect.Effect | Hook | RecPlacement | Suspensable | ReadableAtom; /** The generator a React Effect Component body produces. */ type RecGenerator = Generator | RecPlacement | Suspensable | ReadableAtom, A, unknown>; /** A component body: props in, a generator of yields ending in a rendered `A`. */ type RecBody = (props: Props) => RecGenerator; /** * The API a `.catch` fallback receives alongside the error: a `retry` that * re-attempts the component's body (re-mounting under a boundary, or re-rendering * inline), so a fallback can offer a retry button beyond the automatic * atom-watch reset. */ interface CatchApi { readonly retry: () => void; } /** * Runtime dispatch table for `.catch`: an error `_tag` maps to the node to * render in that error's place, given the error and a {@link CatchApi}. * Renderer-agnostic in `A` — the domain never learns that a node is a React * element; it only carries the mapping so both the client interpreter and the * server driver can honour it. The typed, exhaustive shape users write * (`CatchHandlers`) narrows to this at the `.catch` boundary. */ type CatchDispatch = Readonly A>>; /** * A stable handle to a component's body — the identity a placement points at. * The client keys its per-descriptor React component on this object (so a child * keeps a stable React type across re-renders); the server drives its `body` * directly. Deliberately renderer-agnostic: it names *what* to run, not how. */ interface RecHandle { readonly body: (props: any) => RecGenerator; readonly displayName: string; /** * Typed-error fallbacks for this REC, if it was `.catch`-wrapped: a failure * from one of *its own* `yield*`ed effects whose `_tag` is present renders the * mapped node instead of propagating. Absent for a plain REC. */ readonly catchHandlers?: CatchDispatch; /** * The explicit last-resort fallback for this REC, if it was * `.catchDefect`-wrapped: a failure `.catch` did not handle — a defect, an * untagged failure, an unnamed tag — renders this node instead of propagating. * Tag handlers always win; in dev an absorbed defect is surfaced through the * devtools seam so the catch-all is never silent (#57). Absent for a plain REC, * where such failures propagate to the nearest React error boundary. */ readonly defectHandler?: (defect: unknown, api: CatchApi) => A; /** * The loading fallback for this REC, if it was `.suspense`-wrapped: the client * places it in a real `` boundary so a yielded {@link Suspensable}'s * pending state renders this node. Renderer-agnostic in `A`; absent otherwise. */ readonly suspenseFallback?: A; /** * The acknowledged-volatile marker for this REC, if it was `.hot()`-wrapped: * the author deliberately accepted that this subtree re-renders at the source * frequency of its volatile subscriptions. Purely informational at render time * (the discharge itself is type-level) — the dev render ledger reads it to * report hot subtrees, so the acknowledgment is never silent. Absent for a * plain REC. */ readonly hotAcknowledged?: boolean; /** * The explicit-memoization marker for this REC, if it was `.memo()`-wrapped: * the client wraps its React component in `React.memo` with a *bounded*, * value-aware props comparator (`Object.is` per key, or the `Equal` trait * when both sides implement it). The comparator's soundness is proved at the * `.memo()` call site — the method only type-checks when every prop is a * primitive or an `Equal` implementor — so the binding never deep-compares a * plain structure. Absent for a plain REC, which re-renders with its parent * exactly like any React component. */ readonly memoized?: true; } /** Brand identifying a child-REC placement instruction. */ declare const PlacementTypeId: unique symbol; type PlacementTypeId = typeof PlacementTypeId; /** * The third kind of yieldable, alongside Effects and Hooks: the placement of a * *child* REC into a parent's tree (`yield* Child` / `yield* Child.with(p)`). * * A placement carries only data — the child's stable `rec` handle and its * `props` — never a bound React element. That is what lets one `rec(...)` value * be shared across runtimes: the client turns a placement into a real React * child fiber, the server drives the child's body inline. The phantom `R` makes * the child's Effect requirements flow up through `yield*` to `mount`/`serve`, * exactly as a yielded service's requirements do. */ interface RecPlacement { readonly [PlacementTypeId]: true; readonly rec: RecHandle; readonly props: object; /** * Phantom carrier for the requirements this placement contributes upward. * Covariant (an output position) so a concrete placement — e.g. one needing * `Stats` — widens to `RecPlacement<_, unknown>` in a body's yield union, just * as `Effect<_, _, Stats>` widens to `AnyEffect`. Never set at runtime. */ readonly _requirements?: R; /** * Phantom carrier for the child's unhandled loading obligation `S`. Covariant, * like `_requirements`, so a placed child that still suspends bubbles its * {@link Suspends} up to the parent's `S` — until an ancestor `.suspense`s it. * Never set at runtime. */ readonly _suspends?: S; /** * Phantom carrier for the child's unhandled volatility obligation `V`. * Covariant, like `_suspends`, so a placed child that still reads a volatile * atom bubbles its {@link Volatile} up to the parent's `V` — until an ancestor * defers the read or goes `.hot()`. Never set at runtime. */ readonly _volatile?: V; [Symbol.iterator](): Iterator, A>; } declare const placement: (rec: RecHandle, props: object) => RecPlacement; /** Type guard: is this yielded instruction a child-REC placement? */ declare const isPlacement: (u: unknown) => u is RecPlacement; /** * Distribute over the yield union and keep only its Effect members. Hooks are * not Effects, so they drop away — leaving just what carries `E` and `R`. */ type EffectsOnly = Eff extends AnyEffect ? Eff : never; /** * Re-express each yielded placement as an effect carrying only its child's * requirements, so a placed child's `R` joins the parent's the same way a * yielded service's does — one child, its whole subtree's services bubble up. */ type PlacementsAsEffects = Eff extends RecPlacement ? Effect.Effect : never; /** * Re-express each yielded suspensable as an effect carrying its `E` and `R`, so * a suspensable's errors and requirements join the body's exactly as a raw * effect's do. */ type SuspensablesAsEffects = Eff extends Suspensable ? Effect.Effect : never; /** * Recover the Effect requirement channel `R` from everything a body yields — * services, effects, placed child RECs, and suspensables. A body that needs both * `A` and `B` requires `A & B`, which is exactly the intersection TypeScript * infers from the contravariant requirement slot. */ type RequirementsOf = [EffectsOnly | PlacementsAsEffects | SuspensablesAsEffects] extends [Effect.Effect] ? R : never; /** Recover the Effect error channel `E` (a union — any yielded effect or suspensable may fail). */ type ErrorsOf = [EffectsOnly | SuspensablesAsEffects] extends [Effect.Effect] ? E : never; /** * Recover the loading obligation `S`. A yielded {@link Suspensable} contributes * {@link Suspends}; a placed child contributes whatever `S` it still carries. * The union is `Suspends` if *anything* below is unhandled, and `never` once it * all is — the exact condition `mount` (and `.suspense`) check. */ type SuspendsOf = Eff extends Suspensable ? Suspends : Eff extends RecPlacement ? S : never; /** * Recover the volatility obligation `V`. A yielded volatile atom read * contributes {@link Volatile}; a placed child contributes whatever `V` it * still carries. The union is `Volatile` if *anything* below is undischarged, * and `never` once it all is — the exact condition `mount` (and * `defer`/`.hot()`) check. */ type VolatilityOf = Eff extends ReadableAtom ? V : Eff extends RecPlacement ? V2 : never; /** * Recover the subscription labels `L` — the union of label literals whose * atoms a body reads, which is exactly the set of writes that can re-render * it. Placements deliberately contribute `never`: a child re-renders on its * own subscriptions without re-rendering its parent, so a child's labels do * not bubble. Backs the public `RendersOn` introspection. */ type SubscribesOf = Eff extends ReadableAtom ? L : never; //#endregion //#region src/infrastructure/rec-core.d.ts /** Brand identifying a React Effect Component. */ declare const RecTypeId: unique symbol; type RecTypeId = typeof RecTypeId; /** A tagged error — the shape `.catch` dispatches on (`Data.TaggedError`, …). */ type Tagged = { readonly _tag: string; }; /** The non-tagged remainder of an error channel — errors `.catch` cannot name. */ type UntaggedErrors = Exclude; /** * The exhaustive handler map for a REC's error channel: one fallback per error * `_tag`, each receiving exactly that error. Omitting a tag the body can fail * with is a compile error (a missing property); an unknown tag is rejected as an * excess property. A REC that cannot fail with a tagged error takes `{}`. */ type CatchHandlers = { readonly [Tag in Extract['_tag']]: (error: Extract, api: CatchApi) => A }; /** Any yieldable a REC body may produce — the constraint `rec` infers `Eff` against. */ type AnyYield = AnyEffect | Hook | RecPlacement | Suspensable | ReadableAtom; interface RecCore extends RecHandle { readonly [RecTypeId]: true; /** Place this REC with props: `yield* Child.with({ ... })`. */ with(props: P): RecPlacement; /** * Render a typed fallback for each error this REC's body can fail with. The * handler map is exhaustive over the error channel `E` and checked at compile * time, so you cannot forget a tag or invent one. Each failure — synchronous * or async — renders its mapped node in place of the component; defects and * any non-tagged errors are left to the nearest React error boundary. * * ```tsx * const Profile = rec(function* () { * const user = yield* query(fetchUser(id), id); // E = NotFound | Unauthorized * return ; * }).catch({ * NotFound: () => , * Unauthorized: () => , * }); * ``` * * Returns a REC whose error channel keeps only the non-tagged remainder * (usually `never`); the loading obligation `S` is untouched. It catches *this* * REC's own `yield*`ed failures; a child REC handles its own (wrap it too). * * The fallback renders in place of the component and **recovers on its own**: * effract watches the atoms the body read (a `query`'s key inputs among them) * and re-runs the REC when one changes, so navigating to an input that no longer * fails brings the component back. The order of the body's `yield*`s does not * matter — a failure part-way through is handled wherever the failing yield sits. */ catch(handlers: CatchHandlers): REC, R, S, V, L>; /** * Opt into a **last-resort fallback** for everything `.catch` cannot name: a * defect (a thrown error, an `Effect.die`), a non-tagged failure, or a tag the * handler map did not list at runtime. Without it those always propagate to * the nearest React error boundary — that default is unchanged; this is the * explicit opt-out for a component that must stay standing no matter what * (a widget in a dashboard, a third-party island). * * ```tsx * const Widget = rec(function* () { * const data = yield* query(load, key); // may die on a bug, not just fail * return ; * }) * .catch({ NotFound: () => }) // typed failures first * .catchDefect((defect, { retry }) => ( // the unnameable remainder * * )); * ``` * * Deliberately not silent: tag handlers always win, the handler receives the * original thrown value untouched, and in development every absorbed defect is * reported through the devtools seam (`kind: 'defect:handled'`) with the * pretty-printed `Cause` — so a swallowed bug is still visible while you build. * Recovery matches `.catch`: the fallback re-mounts when a read atom changes, * and `retry` does so on demand. Returns a REC whose error channel is fully * discharged (`E = never`). */ catchDefect(handler: (defect: unknown, api: CatchApi) => ReactNode): REC; /** * Handle this REC's loading state. A REC that `yield*`s a `suspend`/`query` * carries a loading obligation `S`; `.suspense(fallback)` discharges it by * placing the REC in a real `` boundary, so while it is pending the * `fallback` renders in its place. * * ```tsx * const Page = Profile.suspense(); // Page: REC<…, never> — obligation met * ``` * * Returns a REC with `S` back to `never`. One `.suspense` discharges the whole * subtree beneath it (React Suspense catches every descendant that suspends), * so a single boundary — at any ancestor, or at `mount` via `{ loading }` — * satisfies the obligation the type system otherwise bubbles all the way up. */ suspense(fallback: ReactNode): REC; /** * Acknowledge this REC's volatility — the `.catchDefect` of scheduling. A body * that reads a volatile atom (one born from a high-frequency source) carries a * {@link VolatileNotHandled} obligation `V`, because that subscription * re-renders the component at the source's own frequency. `.hot()` is the * deliberate acknowledgment that this subtree is *meant* to run that hot — * a ticker cell, a live chart leaf — and discharges `V` back to `never`. * * ```tsx * const Ticker = rec(function* () { * const p = yield* price; // price: volatile — V = Volatile * return {p}; * }).hot(); // V discharged; keep the leaf small * ``` * * Deliberately not silent: in development the render ledger reports every * `.hot()` subtree and its render frequency, so an acknowledged hot spot stays * visible while you build — exactly how `.catchDefect` reports every absorbed * defect. Prefer `defer(atom)` at the read when the UI can lag a frame; reach * for `.hot()` only where source-frequency rendering is the point. */ hot(): REC; /** * Memoize this REC's placement — **explicit and type-guided**, never * automatic. The returned REC's client component is wrapped in `React.memo` * with a *bounded* comparator: per prop, `Object.is`, or `Equal.equals` when * both sides implement the `Equal` trait. Nothing ever deep-compares a plain * structure — which is exactly why `.memo()` is compile-gated: it only * returns a REC when every prop is **value-comparable** (a primitive, or an * `Equal.Equal` implementor), and otherwise returns * {@link MemoRequiresComparableProps} naming the offending prop(s). Hold * functions in a service; give structured data an `Equal` implementation. * * ```tsx * const Row = rec(function* (props: { id: string; count: number }) { * return
  • {props.id}: {props.count}
  • ; * }); * const MemoRow = Row.memo(); // ✓ all props value-comparable * // a parent re-render with value-equal props no longer re-runs Row's body * ``` * * Apply it once, at declaration (like `.catch` / `.hot()`): a `.memo()` call * inside a render body would mint a fresh component type every render and * defeat the bailout. A props-free REC qualifies trivially (there is nothing * to compare) and skips parent-driven re-renders entirely — its own atom * subscriptions still re-render it. Reach for `.memo()` when the dev render * ledger attributes re-renders to `props` whose values did not change. */ memo(): [NonComparableProps

    ] extends [never] ? REC : MemoRequiresComparableProps>; } interface RecBareYield { /** Place this REC without props: `yield* Child`. */ [Symbol.iterator](): Iterator, ReactNode>; } /** * A React Effect Component. Yieldable (so `R` and `S` propagate), never a JSX * element type — `` is a compile error by design. Props-free RECs can be * yielded directly (`yield* Child`); RECs with props use `yield* Child.with(p)`. * `E` carries the tagged failures its body can raise (`.catch` discharges them); * `S` carries an unhandled loading obligation (`.suspense` discharges it); * `V` carries an unhandled volatility obligation (`defer` at the read, or * `.hot()`, discharges it); `L` carries the labels of the atoms the tree * subscribes to — the set of writes that can re-render it (see * {@link RendersOn}). `V` and `L` default so existing annotations stay valid. */ type REC = RecCore & ([Record] extends [P] ? RecBareYield : unknown); /** * The labels a component can re-render on — the union of label literals of * every atom its tree subscribes to. The introspection half of the render * channel: lock it in a type test and a new subscription (a new reason to * re-render) becomes a compile-time diff, reviewable like any other. * * ```ts * type _lock = RendersOn; // 'stats' | 'filter' * ``` */ type RendersOn = C extends RecCore ? L : never; /** * Define a React Effect Component. The body is a generator that may `yield*` * Effect services and effects, `yield* hook(...)` for React hooks, `yield* * suspend(...)` / `query(...)` for async data, and `yield* Child` / `yield* Child.with(props)` to * place other RECs. * * The returned descriptor is server-safe: the same `mount(...)` renders a * hook-free body on the server, and the very same value mounts on the client. * Only a body that itself imports client-only APIs (React hooks) makes its * *module* client-only — the `rec` wrapper never does. */ declare function rec>(body: () => Generator): REC, RequirementsOf, SuspendsOf, VolatilityOf, SubscribesOf>; declare function rec(body: (props: Props) => Generator): REC, RequirementsOf, SuspendsOf, VolatilityOf, SubscribesOf>; /** A type error naming the services a runtime is missing for a REC's tree. */ type MissingServices = readonly ['effract: runtime is missing', Missing]; /** A type error demanding a loading fallback for a tree that can still suspend. */ type LoadingNotHandled = readonly ['effract: loading not handled — add .suspense(fallback), or mount(layer, root, { loading })']; /** A type error demanding a scheduling decision for a tree that still reads a volatile atom. */ type VolatileNotHandled = readonly ['effract: volatile subscription not handled — defer(atom) the read, or mark the component .hot()']; /** * The prop keys of `P` whose values `.memo()`'s bounded comparator cannot * compare by value — anything that is neither a primitive nor an `Equal.Equal` * implementor (a function, a plain object or array, a JSX node). `never` when * every prop is value-comparable, which is exactly when `.memo()` compiles. */ type NonComparableProps

    = { [K in keyof P]-?: P[K] extends string | number | boolean | bigint | symbol | null | undefined ? never : P[K] extends Equal.Equal ? never : K }[keyof P]; /** A type error naming the props whose values `.memo()` cannot soundly compare. */ type MemoRequiresComparableProps = readonly ['effract: .memo() requires value-comparable props — hold functions in a service and give structured data an Equal implementation; offending prop(s):', K]; /** * A no-service tree's requirement infers as `unknown` (Effect's requirement * channel is contravariant, so `never` widens). Normalise that to `never` so a * runtime-free tree mounts/serves under any layer. */ type Effective = [unknown] extends [R] ? never : R; //#endregion //#region src/infrastructure/query-cache.d.ts /** What the cache can do — the shape `yield* QueryCache` resolves to. */ interface QueryCacheApi { /** * Refetch every query carrying an `Equal`-equal tag. An active query (something * is reading it) revalidates in the background — its readers keep showing the * current value, then update; an inactive one is dropped so its next read * fetches afresh. Returns how many queries matched. */ invalidate(tag: unknown): number; /** * Refetch every query whose key is `Equal`-equal to `key` — a failed or * completed query re-runs without a key change or a remount (a retry button, * pull-to-refresh, post-mutation refresh). Returns how many queries matched. */ refetch(key: unknown): number; } declare const QueryCache_base: Context.ServiceClass; /** * The service Tag. Provided automatically by `mount`/`renderToStream` when you * pass a `Layer` — your services may simply `yield* QueryCache`. An *injected* * `ManagedRuntime` is built outside effract, so it must carry the cache itself: * build with the `Layer` form if your services use it. */ declare class QueryCache extends QueryCache_base {} //#endregion export { Suspensable as A, query as B, RecBody as C, RequirementsOf as D, RecPlacement as E, isAtom as F, suspend as H, isHook as I, isPlacement as L, Volatile as M, Yieldable as N, Suspends as O, hook as P, isSuspensable as R, ReadableAtom as S, RecHandle as T, scoped as V, ErrorsOf as _, MemoRequiresComparableProps as a, PlacementTypeId as b, RecTypeId as c, rec as d, AnyEffect as f, CatchDispatch as g, CatchApi as h, LoadingNotHandled as i, SuspensableTypeId as j, SuspendsOf as k, RendersOn as l, AtomTypeId as m, CatchHandlers as n, MissingServices as o, Atom as p, Effective as r, REC as s, QueryCache as t, VolatileNotHandled as u, Hook as v, RecGenerator as w, QueryOptions as x, HookTypeId as y, placement as z };