raf-effect-atom 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,232 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
+ import { hydrated } from "./Hydration.mjs";
3
+ import { isDevelopment } from "./internal/development.mjs";
4
+ import { keyOf, take } from "./internal/leases.mjs";
5
+ import { isRequestRegistry } from "./RequestRegistry.mjs";
6
+ import * as Atom from "effect/reactivity/Atom";
7
+ import * as Predicate from "effect/Predicate";
8
+ import * as Cause from "effect/Cause";
9
+ import * as Context from "effect/Context";
10
+ import * as Duration from "effect/Duration";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Option from "effect/Option";
13
+ import * as AsyncResult from "effect/reactivity/AsyncResult";
14
+ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
15
+ // src/Loader.ts
16
+ /**
17
+ * Starts atoms from route loaders, before anything renders, so nothing
18
+ * waterfalls.
19
+ *
20
+ * Each verb starts an `AsyncResult` atom in the registry and takes a lease
21
+ * on it, so the registry's idle TTL can't evict it before the route renders
22
+ * and `useAtomResult` takes it over:
23
+ *
24
+ * | Verb | Starts the atom | Waits | Has a value already |
25
+ * | ---------- | ------------------------------- | ----------------------------- | --------------------- |
26
+ * | `prefetch` | if it isn't in the registry | never | leaves it alone |
27
+ * | `ensure` | if it isn't in the registry | only while it's `Initial` | returns it at once |
28
+ * | `fetch` | if it isn't, or refreshes it | until the new result settles | refreshes, then waits |
29
+ *
30
+ * Typed failures don't reject: `ensure` and `fetch` return the settled
31
+ * `AsyncResult`, so a loader can redirect on a tag and otherwise let a
32
+ * boundary render the failure. Only defects and interruptions reject.
33
+ *
34
+ * The verbs are Effects that need the `AtomRegistry`; `make` gives the same
35
+ * verbs as Promises over one registry, for loaders that are async functions.
36
+ *
37
+ * @stability unstable
38
+ * @since 0.1.0
39
+ */
40
+ var Loader_exports = /* @__PURE__ */ __exportAll({
41
+ LeaseTTL: () => LeaseTTL,
42
+ ensure: () => ensure,
43
+ fetch: () => fetch,
44
+ make: () => make,
45
+ prefetch: () => prefetch
46
+ });
47
+ /**
48
+ * How long a loader's lease keeps an atom mounted when no component takes it
49
+ * over. Default 30 seconds.
50
+ *
51
+ * **Details**
52
+ *
53
+ * A lease ends when `useAtomResult` mounts the atom, or when this time has
54
+ * passed, after which the registry's idle TTL applies as usual. On a request
55
+ * registry, leases last until the registry is disposed.
56
+ *
57
+ * @stability unstable
58
+ * @category references
59
+ * @since 0.1.0
60
+ */
61
+ const LeaseTTL = Context.Reference("raf-effect-atom/Loader/LeaseTTL", { defaultValue: () => Duration.seconds(30) });
62
+ const start = Effect.fnUntraced(function* (atom) {
63
+ const registry = yield* AtomRegistry.AtomRegistry;
64
+ const request = isRequestRegistry(registry);
65
+ if (request && !Atom.isSerializable(atom) && (yield* isDevelopment)) return yield* Effect.die(/* @__PURE__ */ new Error(`raf-effect-atom: a loader started ${String(atom)}, which isn't serializable, so the browser would request it again. Give it a serialization key, such as AtomRpc's serializationKey option.`));
66
+ const ttl = request ? void 0 : Duration.toMillis(yield* LeaseTTL);
67
+ const target = hydrated(atom);
68
+ const key = keyOf(target);
69
+ const existed = registry.getNodes().has(key) || Predicate.isString(key) && registry.preloadedSerializable.has(key);
70
+ take(registry, target, ttl);
71
+ return {
72
+ existed,
73
+ registry,
74
+ request,
75
+ target
76
+ };
77
+ });
78
+ const isSettled = (result) => AsyncResult.isNotInitial(result) && !result.waiting;
79
+ const settled = (registry, atom, isDone) => Effect.callback((resume) => {
80
+ const current = registry.get(atom);
81
+ if (isDone(current)) {
82
+ resume(Effect.succeed(current));
83
+ return;
84
+ }
85
+ const cancel = registry.subscribe(atom, (value) => {
86
+ if (isDone(value)) {
87
+ cancel();
88
+ resume(Effect.succeed(value));
89
+ }
90
+ });
91
+ return Effect.sync(cancel);
92
+ }).pipe(Effect.flatMap(rejectDefects));
93
+ const rejectDefects = (result) => {
94
+ if (AsyncResult.isFailure(result) && Option.isNone(Cause.findErrorOption(result.cause))) {
95
+ const defects = result.cause;
96
+ return Effect.failCause(defects);
97
+ }
98
+ return Effect.succeed(result);
99
+ };
100
+ /**
101
+ * Starts an atom without waiting for it.
102
+ *
103
+ * **When to use**
104
+ *
105
+ * Use for data the route needs but its loader doesn't: it streams in while
106
+ * the route renders.
107
+ *
108
+ * **Details**
109
+ *
110
+ * Starts the atom if it isn't in the registry, and leaves it alone if it is.
111
+ * Takes a lease either way.
112
+ *
113
+ * **Example**
114
+ *
115
+ * ```ts
116
+ * import { Effect } from "effect"
117
+ * import { Loader } from "raf-effect-atom"
118
+ *
119
+ * const program = Loader.prefetch(comments(1))
120
+ * ```
121
+ *
122
+ * @stability unstable
123
+ * @category verbs
124
+ * @since 0.1.0
125
+ */
126
+ const prefetch = Effect.fnUntraced(function* (atom) {
127
+ yield* start(atom);
128
+ });
129
+ /**
130
+ * Starts an atom and returns its settled result, waiting only while it has
131
+ * none.
132
+ *
133
+ * **When to use**
134
+ *
135
+ * Use when the loader needs the result, such as to redirect on a tag, or
136
+ * when the route shouldn't render without it.
137
+ *
138
+ * **Details**
139
+ *
140
+ * An atom with a result returns it at once, without refetching. On a request
141
+ * registry, it also waits out a refresh in flight, so the server never
142
+ * renders a result that's about to change. A typed failure is returned as
143
+ * the result; a defect or an interruption fails the Effect.
144
+ *
145
+ * **Example**
146
+ *
147
+ * ```ts
148
+ * import { Effect } from "effect"
149
+ * import { AsyncResult } from "effect/reactivity"
150
+ * import { Loader } from "raf-effect-atom"
151
+ *
152
+ * const program = Effect.gen(function* () {
153
+ * const result = yield* Loader.ensure(issue(1))
154
+ * return AsyncResult.isSuccess(result) ? result.value.title : "missing"
155
+ * })
156
+ * ```
157
+ *
158
+ * @stability unstable
159
+ * @category verbs
160
+ * @since 0.1.0
161
+ */
162
+ const ensure = Effect.fnUntraced(function* (atom) {
163
+ const started = yield* start(atom);
164
+ return yield* settled(started.registry, started.target, started.request ? isSettled : AsyncResult.isNotInitial);
165
+ });
166
+ /**
167
+ * Starts an atom, or refreshes it if it has a result, and returns the new
168
+ * settled result.
169
+ *
170
+ * **When to use**
171
+ *
172
+ * Use when the loader must not see a result from before it ran, such as
173
+ * after a mutation.
174
+ *
175
+ * **Details**
176
+ *
177
+ * Waits until the result settles and isn't refreshing. A typed failure is
178
+ * returned as the result; a defect or an interruption fails the Effect.
179
+ *
180
+ * @stability unstable
181
+ * @category verbs
182
+ * @since 0.1.0
183
+ */
184
+ const fetch = Effect.fnUntraced(function* (atom) {
185
+ const started = yield* start(atom);
186
+ const { registry, target } = started;
187
+ if (started.existed && isSettled(registry.get(target))) {
188
+ const node = registry.getNodes().get(keyOf(target));
189
+ registry.refresh(node?.atom ?? target);
190
+ }
191
+ return yield* settled(registry, target, isSettled);
192
+ });
193
+ /**
194
+ * Creates the Promise verbs over one registry.
195
+ *
196
+ * **When to use**
197
+ *
198
+ * Use in a framework integration, in loaders that are async functions, or
199
+ * in an event handler that starts an atom before the state change that
200
+ * renders its reader, for state that can't be in the URL, such as a
201
+ * search-as-you-type query. In Effect code, use
202
+ * the verbs directly with the `AtomRegistry` provided.
203
+ *
204
+ * **Example**
205
+ *
206
+ * ```ts
207
+ * import { Loader, RequestRegistry } from "raf-effect-atom"
208
+ *
209
+ * const loader = Loader.make(RequestRegistry.make())
210
+ * loader.prefetch(comments(1))
211
+ * const result = await loader.ensure(issue(1))
212
+ * ```
213
+ *
214
+ * @stability unstable
215
+ * @category constructors
216
+ * @since 0.1.0
217
+ */
218
+ const make = (registry, options) => {
219
+ const leaseTTL = options?.leaseTTL === void 0 ? void 0 : Duration.fromInputUnsafe(options.leaseTTL);
220
+ const provide = (effect) => {
221
+ const provided = Effect.provideService(effect, AtomRegistry.AtomRegistry, registry);
222
+ return leaseTTL === void 0 ? provided : Effect.provideService(provided, LeaseTTL, leaseTTL);
223
+ };
224
+ return {
225
+ ensure: (atom) => Effect.runPromise(provide(ensure(atom))),
226
+ fetch: (atom) => Effect.runPromise(provide(fetch(atom))),
227
+ prefetch: (atom) => {
228
+ Effect.runSync(provide(prefetch(atom)));
229
+ }
230
+ };
231
+ };
232
+ export { LeaseTTL, Loader_exports, ensure, fetch, make, prefetch };
@@ -0,0 +1,66 @@
1
+ import { SettledResult } from "./Loader.mjs";
2
+ import { HydrateAtoms } from "./NextClient.mjs";
3
+ import { RegistryProvider } from "./RegistryProvider.mjs";
4
+ import * as Atom from "effect/reactivity/Atom";
5
+ import * as EffectHydration from "effect/reactivity/Hydration";
6
+ import * as AsyncResult from "effect/reactivity/AsyncResult";
7
+ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
8
+ /**
9
+ * Returns the request registry of the server render in progress.
10
+ *
11
+ * **Details**
12
+ *
13
+ * Made once per request through React's `cache`, and disposed through
14
+ * `cacheSignal` when React finishes the render, after the last streamed
15
+ * result has been sent.
16
+ *
17
+ * **Gotchas**
18
+ *
19
+ * Only server components share it: outside a server component render,
20
+ * `cache` doesn't cache, so each call makes a new registry.
21
+ *
22
+ * @stability unstable
23
+ * @category registry
24
+ * @since 0.1.0
25
+ */
26
+ export declare const getRegistry: () => AtomRegistry.AtomRegistry;
27
+ /**
28
+ * `Loader.prefetch` on the request's registry: starts an atom, to stream it.
29
+ *
30
+ * @stability unstable
31
+ * @category verbs
32
+ * @since 0.1.0
33
+ */
34
+ export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => void;
35
+ /**
36
+ * `Loader.ensure` on the request's registry: starts an atom and returns its
37
+ * settled result.
38
+ *
39
+ * @stability unstable
40
+ * @category verbs
41
+ * @since 0.1.0
42
+ */
43
+ export declare const ensure: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
44
+ /**
45
+ * `Loader.fetch` on the request's registry: starts or refreshes an atom and
46
+ * returns the new settled result.
47
+ *
48
+ * @stability unstable
49
+ * @category verbs
50
+ * @since 0.1.0
51
+ */
52
+ export declare const fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
53
+ /**
54
+ * `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
55
+ *
56
+ * **Gotchas**
57
+ *
58
+ * Includes the atoms started so far, so call it after the server component's
59
+ * verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
60
+ *
61
+ * @stability unstable
62
+ * @category dehydration
63
+ * @since 0.1.0
64
+ */
65
+ export declare const dehydrate: () => Array<EffectHydration.DehydratedAtom>;
66
+ export { HydrateAtoms, RegistryProvider };
package/dist/Next.mjs ADDED
@@ -0,0 +1,63 @@
1
+ import { dehydrate as dehydrate$1, ensure as ensure$1, fetch as fetch$1, getRegistry as getRegistry$1, prefetch as prefetch$1 } from "./internal/next.mjs";
2
+ import { HydrateAtoms } from "./NextClient.mjs";
3
+ import { RegistryProvider } from "./RegistryProvider.mjs";
4
+ // src/Next.ts
5
+ /**
6
+ * Returns the request registry of the server render in progress.
7
+ *
8
+ * **Details**
9
+ *
10
+ * Made once per request through React's `cache`, and disposed through
11
+ * `cacheSignal` when React finishes the render, after the last streamed
12
+ * result has been sent.
13
+ *
14
+ * **Gotchas**
15
+ *
16
+ * Only server components share it: outside a server component render,
17
+ * `cache` doesn't cache, so each call makes a new registry.
18
+ *
19
+ * @stability unstable
20
+ * @category registry
21
+ * @since 0.1.0
22
+ */
23
+ const getRegistry = getRegistry$1;
24
+ /**
25
+ * `Loader.prefetch` on the request's registry: starts an atom, to stream it.
26
+ *
27
+ * @stability unstable
28
+ * @category verbs
29
+ * @since 0.1.0
30
+ */
31
+ const prefetch = prefetch$1;
32
+ /**
33
+ * `Loader.ensure` on the request's registry: starts an atom and returns its
34
+ * settled result.
35
+ *
36
+ * @stability unstable
37
+ * @category verbs
38
+ * @since 0.1.0
39
+ */
40
+ const ensure = ensure$1;
41
+ /**
42
+ * `Loader.fetch` on the request's registry: starts or refreshes an atom and
43
+ * returns the new settled result.
44
+ *
45
+ * @stability unstable
46
+ * @category verbs
47
+ * @since 0.1.0
48
+ */
49
+ const fetch = fetch$1;
50
+ /**
51
+ * `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
52
+ *
53
+ * **Gotchas**
54
+ *
55
+ * Includes the atoms started so far, so call it after the server component's
56
+ * verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
57
+ *
58
+ * @stability unstable
59
+ * @category dehydration
60
+ * @since 0.1.0
61
+ */
62
+ const dehydrate = dehydrate$1;
63
+ export { HydrateAtoms, RegistryProvider, dehydrate, ensure, fetch, getRegistry, prefetch };
@@ -0,0 +1,33 @@
1
+ import { HydrationBoundaryProps } from "./ReactHydration.mjs";
2
+ import * as React from "react";
3
+ /**
4
+ * Hydrates the state a server component dehydrated with `dehydrate()`,
5
+ * streamed results included.
6
+ *
7
+ * **Details**
8
+ *
9
+ * React serializes the state's promises with the server component's
10
+ * payload, so a result still loading streams in when it settles, and
11
+ * `useAtomResult` waits for it instead of requesting it again.
12
+ *
13
+ * **Example**
14
+ *
15
+ * ```tsx
16
+ * import { dehydrate, ensure, HydrateAtoms } from "raf-effect-atom/next"
17
+ *
18
+ * export default async function IssuePage(props: { params: Promise<{ id: string }> }) {
19
+ * const id = Number((await props.params).id)
20
+ * await ensure(issue(id))
21
+ * return (
22
+ * <HydrateAtoms state={dehydrate()}>
23
+ * <Issue id={id} />
24
+ * </HydrateAtoms>
25
+ * )
26
+ * }
27
+ * ```
28
+ *
29
+ * @stability unstable
30
+ * @category components
31
+ * @since 0.1.0
32
+ */
33
+ export declare const HydrateAtoms: (props: HydrationBoundaryProps) => React.ReactNode;
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { HydrationBoundary } from "./ReactHydration.mjs";
3
+ import { jsx } from "react/jsx-runtime";
4
+ // src/NextClient.tsx
5
+ /**
6
+ * The client components of `raf-effect-atom/next`.
7
+ *
8
+ * @stability unstable
9
+ * @since 0.1.0
10
+ */
11
+ /**
12
+ * Hydrates the state a server component dehydrated with `dehydrate()`,
13
+ * streamed results included.
14
+ *
15
+ * **Details**
16
+ *
17
+ * React serializes the state's promises with the server component's
18
+ * payload, so a result still loading streams in when it settles, and
19
+ * `useAtomResult` waits for it instead of requesting it again.
20
+ *
21
+ * **Example**
22
+ *
23
+ * ```tsx
24
+ * import { dehydrate, ensure, HydrateAtoms } from "raf-effect-atom/next"
25
+ *
26
+ * export default async function IssuePage(props: { params: Promise<{ id: string }> }) {
27
+ * const id = Number((await props.params).id)
28
+ * await ensure(issue(id))
29
+ * return (
30
+ * <HydrateAtoms state={dehydrate()}>
31
+ * <Issue id={id} />
32
+ * </HydrateAtoms>
33
+ * )
34
+ * }
35
+ * ```
36
+ *
37
+ * @stability unstable
38
+ * @category components
39
+ * @since 0.1.0
40
+ */
41
+ const HydrateAtoms = (props) => /* @__PURE__ */ jsx(HydrationBoundary, {
42
+ state: props.state,
43
+ children: props.children
44
+ });
45
+ export { HydrateAtoms };
@@ -0,0 +1,52 @@
1
+ import * as Hydration from "effect/reactivity/Hydration";
2
+ import * as React from "react";
3
+ /**
4
+ * Props for `HydrationBoundary`.
5
+ *
6
+ * @stability unstable
7
+ * @category models
8
+ * @since 0.1.0
9
+ */
10
+ export interface HydrationBoundaryProps {
11
+ readonly children?: React.ReactNode | undefined;
12
+ /** The state `Hydration.dehydrate` returned on the server. */
13
+ readonly state?: Iterable<Hydration.DehydratedAtom> | undefined;
14
+ }
15
+ /**
16
+ * Hydrates the state a server registry dehydrated, streamed results
17
+ * included.
18
+ *
19
+ * **When to use**
20
+ *
21
+ * Use where the server's state reaches the React tree as a prop, such as
22
+ * React Server Components props or a React Router loader's data. A router
23
+ * that hydrates before rendering calls `Hydration.hydrate` instead.
24
+ *
25
+ * **Details**
26
+ *
27
+ * Settled values go to `@effect/atom-react`'s `HydrationBoundary`, which
28
+ * hydrates new atoms during render and existing ones after commit. Each
29
+ * streamed result is held until it arrives, so `useAtomResult` waits for it
30
+ * instead of requesting it again.
31
+ *
32
+ * During server rendering, when `state` is the array `dehydrate` returned,
33
+ * as React Router passes a loader's data to the server render, the children
34
+ * read the registry it came from instead of a copy. The loaders' atoms are
35
+ * there, so an `effect-atom-boundary` boundary sees their failures before
36
+ * its children read them and renders its handler on the server.
37
+ *
38
+ * **Example**
39
+ *
40
+ * ```tsx
41
+ * import { HydrationBoundary } from "raf-effect-atom"
42
+ *
43
+ * <HydrationBoundary state={loaderData.atoms}>
44
+ * <IssuePage id={id} />
45
+ * </HydrationBoundary>
46
+ * ```
47
+ *
48
+ * @stability unstable
49
+ * @category components
50
+ * @since 0.1.0
51
+ */
52
+ export declare const HydrationBoundary: (props: HydrationBoundaryProps) => React.ReactNode;
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { split } from "./internal/pending.mjs";
3
+ import { sourceOf } from "./internal/sources.mjs";
4
+ import { isServer } from "./internal/registry.mjs";
5
+ import { HydrationBoundary, RegistryContext } from "@effect/atom-react";
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ // src/ReactHydration.tsx
9
+ /**
10
+ * Applies a server registry's dehydrated state to the nearest
11
+ * `RegistryContext`, while rendering.
12
+ *
13
+ * @stability unstable
14
+ * @since 0.1.0
15
+ */
16
+ /**
17
+ * Hydrates the state a server registry dehydrated, streamed results
18
+ * included.
19
+ *
20
+ * **When to use**
21
+ *
22
+ * Use where the server's state reaches the React tree as a prop, such as
23
+ * React Server Components props or a React Router loader's data. A router
24
+ * that hydrates before rendering calls `Hydration.hydrate` instead.
25
+ *
26
+ * **Details**
27
+ *
28
+ * Settled values go to `@effect/atom-react`'s `HydrationBoundary`, which
29
+ * hydrates new atoms during render and existing ones after commit. Each
30
+ * streamed result is held until it arrives, so `useAtomResult` waits for it
31
+ * instead of requesting it again.
32
+ *
33
+ * During server rendering, when `state` is the array `dehydrate` returned,
34
+ * as React Router passes a loader's data to the server render, the children
35
+ * read the registry it came from instead of a copy. The loaders' atoms are
36
+ * there, so an `effect-atom-boundary` boundary sees their failures before
37
+ * its children read them and renders its handler on the server.
38
+ *
39
+ * **Example**
40
+ *
41
+ * ```tsx
42
+ * import { HydrationBoundary } from "raf-effect-atom"
43
+ *
44
+ * <HydrationBoundary state={loaderData.atoms}>
45
+ * <IssuePage id={id} />
46
+ * </HydrationBoundary>
47
+ * ```
48
+ *
49
+ * @stability unstable
50
+ * @category components
51
+ * @since 0.1.0
52
+ */
53
+ const HydrationBoundary$1 = (props) => {
54
+ const context = React.useContext(RegistryContext);
55
+ const state = props.state;
56
+ const source = isServer() ? sourceOf(state) : void 0;
57
+ const registry = source ?? context;
58
+ const settled = React.useMemo(() => state === void 0 || source !== void 0 ? void 0 : split(registry, state), [
59
+ registry,
60
+ source,
61
+ state
62
+ ]);
63
+ return /* @__PURE__ */ jsx(RegistryContext.Provider, {
64
+ value: registry,
65
+ children: /* @__PURE__ */ jsx(HydrationBoundary, {
66
+ state: settled,
67
+ children: props.children
68
+ })
69
+ });
70
+ };
71
+ export { HydrationBoundary$1 as HydrationBoundary };
@@ -0,0 +1,63 @@
1
+ import { Loader } from "./Loader.mjs";
2
+ import { RegistryProvider } from "./RegistryProvider.mjs";
3
+ import * as EffectHydration from "effect/reactivity/Hydration";
4
+ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
5
+ /**
6
+ * One request's registry, with the loader verbs over it.
7
+ *
8
+ * @stability unstable
9
+ * @category models
10
+ * @since 0.1.0
11
+ */
12
+ export interface RequestAtoms extends Loader {
13
+ /** `Hydration.dehydrate` on the request's registry, for loader data. */
14
+ readonly dehydrate: () => Array<EffectHydration.DehydratedAtom>;
15
+ readonly registry: AtomRegistry.AtomRegistry;
16
+ }
17
+ /**
18
+ * The router context `atomsMiddleware` sets: what `react-router`'s
19
+ * `createContext<RequestAtoms>()` returns.
20
+ *
21
+ * @stability unstable
22
+ * @category models
23
+ * @since 0.1.0
24
+ */
25
+ export interface AtomsContext {
26
+ readonly defaultValue?: RequestAtoms | undefined;
27
+ }
28
+ /**
29
+ * The parts of React Router's middleware arguments `atomsMiddleware` uses.
30
+ *
31
+ * @stability unstable
32
+ * @category models
33
+ * @since 0.1.0
34
+ */
35
+ export interface MiddlewareArgs {
36
+ readonly context: {
37
+ readonly set: (context: AtomsContext, value: RequestAtoms) => void;
38
+ };
39
+ }
40
+ /**
41
+ * Creates a root middleware that gives each server request its own
42
+ * registry, under the given router context.
43
+ *
44
+ * **Details**
45
+ *
46
+ * The registry is disposed once the response's body has been sent, or the
47
+ * client has gone: loader data streams its pending promises after the
48
+ * middleware returns, so the atoms behind them must keep running until
49
+ * then. When `next` doesn't return a `Response`, as Data Mode's
50
+ * `query` can, the registry is left to be collected with the request.
51
+ *
52
+ * **Gotchas**
53
+ *
54
+ * It's server middleware: export it as the root route's `middleware`, not
55
+ * `clientMiddleware`. In the browser, the root's `RegistryProvider` holds
56
+ * the registry.
57
+ *
58
+ * @stability unstable
59
+ * @category integrations
60
+ * @since 0.1.0
61
+ */
62
+ export declare const atomsMiddleware: (context: AtomsContext) => <Result>(args: MiddlewareArgs, next: () => Promise<Result>) => Promise<Result>;
63
+ export { RegistryProvider };