raf-effect-atom 0.2.3 → 0.2.5
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.
- package/CHANGELOG.md +21 -5
- package/dist/Hooks.mjs +1 -11
- package/dist/Loader.d.mts +18 -4
- package/dist/Loader.mjs +28 -12
- package/dist/RequestRegistry.d.mts +28 -2
- package/dist/RequestRegistry.mjs +11 -2
- package/dist/TanStackRouter.d.mts +8 -1
- package/dist/TanStackRouter.mjs +6 -0
- package/dist/Waterfalls.d.mts +3 -6
- package/dist/Waterfalls.mjs +5 -8
- package/dist/internal/handles.mjs +12 -3
- package/dist/internal/registry.mjs +5 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.5](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.4...raf-effect-atom%400.2.5) (2026-10-23)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **raf-effect-atom:** start a derived atom's source from the loader verbs, following initialValueTarget ([00a9760](https://github.com/KATT/raf-effect-atom/commit/00a97602068cabf085fa9cfe41e88bf853b6af32))
|
|
8
|
+
|
|
9
|
+
## [0.2.4](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.3...raf-effect-atom%400.2.4) (2026-10-23)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- **raf-effect-atom:** start a request registry with initialValues, readable atoms included ([67cf767](https://github.com/KATT/raf-effect-atom/commit/67cf767e121e76b385ff0808a087efc6662aed89))
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
|
|
17
|
+
- correct the generated changelogs' cut-off breaking change and bogus issue links ([c21f64c](https://github.com/KATT/raf-effect-atom/commit/c21f64cad3b4638f2341968aa2e10af5a19904c1))
|
|
18
|
+
|
|
3
19
|
## [0.2.3](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.2...raf-effect-atom%400.2.3) (2026-10-23)
|
|
4
20
|
|
|
5
21
|
### Features
|
|
6
22
|
|
|
7
|
-
|
|
23
|
+
- **raf-effect-atom:** run Effect code on a loader's registry with Loader.Loader.run ([d26307d](https://github.com/KATT/raf-effect-atom/commit/d26307dc6279106ebd9d26078c88e4ad10a8cbc9))
|
|
8
24
|
|
|
9
25
|
## [0.2.2](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.1...raf-effect-atom%400.2.2) (2026-10-23)
|
|
10
26
|
|
|
11
27
|
### Features
|
|
12
28
|
|
|
13
|
-
- **raf-effect-atom:** stop a loader's wait when its request is aborted ([b1f2f16](https://github.com/KATT/raf-effect-atom/commit/b1f2f16fcce9cd5dd1ba18fa653b40c805eebd93))
|
|
29
|
+
- **raf-effect-atom:** stop a loader's wait when its request is aborted ([b1f2f16](https://github.com/KATT/raf-effect-atom/commit/b1f2f16fcce9cd5dd1ba18fa653b40c805eebd93))
|
|
14
30
|
|
|
15
31
|
### Bug Fixes
|
|
16
32
|
|
|
@@ -25,13 +41,13 @@
|
|
|
25
41
|
|
|
26
42
|
### Features
|
|
27
43
|
|
|
28
|
-
- **raf-effect-atom:** run React Router loaders in the browser after the first page ([bee00a9](https://github.com/KATT/raf-effect-atom/commit/bee00a981fd24fcdc9d746053dcd73dbc7ebc853))
|
|
44
|
+
- **raf-effect-atom:** run React Router loaders in the browser after the first page ([bee00a9](https://github.com/KATT/raf-effect-atom/commit/bee00a981fd24fcdc9d746053dcd73dbc7ebc853))
|
|
29
45
|
|
|
30
46
|
## [0.2.0](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.1.0...raf-effect-atom%400.2.0) (2026-10-23)
|
|
31
47
|
|
|
32
48
|
### ⚠ BREAKING CHANGES
|
|
33
49
|
|
|
34
|
-
- **raf-effect-atom:** `dehydrate()` from `raf-effect-atom/next` returns a
|
|
50
|
+
- **raf-effect-atom:** `dehydrate()` from `raf-effect-atom/next` returns a promise: write `<HydrateAtoms state={await dehydrate()}>`.
|
|
35
51
|
|
|
36
52
|
### Features
|
|
37
53
|
|
|
@@ -123,7 +139,7 @@
|
|
|
123
139
|
|
|
124
140
|
### Bug Fixes
|
|
125
141
|
|
|
126
|
-
- **raf-effect-atom:** call use() on a streamed result's promise on every render that reads it ([36d2aaa](https://github.com/KATT/raf-effect-atom/commit/36d2aaa8bacf18a60507e4997fd61476d7a908c0))
|
|
142
|
+
- **raf-effect-atom:** call use() on a streamed result's promise on every render that reads it ([36d2aaa](https://github.com/KATT/raf-effect-atom/commit/36d2aaa8bacf18a60507e4997fd61476d7a908c0))
|
|
127
143
|
- **raf-effect-atom:** point waterfall reports at the URL before the escape hatches ([0d127e3](https://github.com/KATT/raf-effect-atom/commit/0d127e38a10cb3a44340c5540c75b53491faceee))
|
|
128
144
|
- **raf-effect-atom:** refresh the atom the registry runs for a key in Loader.fetch ([0b35c97](https://github.com/KATT/raf-effect-atom/commit/0b35c97b4de60de254c7fc921b89aed7be753ec8))
|
|
129
145
|
- **raf-effect-atom:** wait for results streamed in a server component payload ([00cb981](https://github.com/KATT/raf-effect-atom/commit/00cb98125aad2cda70525fbfdedcd2b5a8f7fc79))
|
package/dist/Hooks.mjs
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
import { stream } from "./internal/pending.mjs";
|
|
3
3
|
import { hydrated } from "./Hydration.mjs";
|
|
4
4
|
import { keyOf, release } from "./internal/leases.mjs";
|
|
5
|
-
import { atomOf } from "./internal/handles.mjs";
|
|
5
|
+
import { atomOf, sourceOf } from "./internal/handles.mjs";
|
|
6
6
|
import { requireRequestRegistry } from "./internal/registry.mjs";
|
|
7
7
|
import { ModeContext, check } from "./internal/waterfalls.mjs";
|
|
8
|
-
import * as Atom from "effect/reactivity/Atom";
|
|
9
8
|
import * as Predicate from "effect/Predicate";
|
|
10
9
|
import * as Cause from "effect/Cause";
|
|
11
10
|
import * as Option from "effect/Option";
|
|
@@ -20,15 +19,6 @@ import * as React from "react";
|
|
|
20
19
|
* @since 0.1.0
|
|
21
20
|
*/
|
|
22
21
|
/**
|
|
23
|
-
* The atom the loader started and the server sent: the first serializable
|
|
24
|
-
* atom in `atom`'s `initialValueTarget` chain, starting with `atom`. An
|
|
25
|
-
* AtomRpc query is serializable itself, though it points at an inner atom.
|
|
26
|
-
*/
|
|
27
|
-
const sourceOf = (atom) => {
|
|
28
|
-
for (let target = atom; target !== void 0; target = target.initialValueTarget) if (Atom.isSerializable(target)) return target;
|
|
29
|
-
return atom;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
22
|
* Reads a handle through React Suspense, through the source that made it: a
|
|
33
23
|
* result streamed from the server, a hydrated one, or one a loader started.
|
|
34
24
|
*
|
package/dist/Loader.d.mts
CHANGED
|
@@ -40,10 +40,24 @@ export declare const LeaseTTL: Context.Reference<Duration.Duration>;
|
|
|
40
40
|
*
|
|
41
41
|
* **Details**
|
|
42
42
|
*
|
|
43
|
-
* Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
44
|
-
* Takes a lease either way. The component that reads the handle
|
|
45
|
-
* until the result settles. On a request registry whose async
|
|
46
|
-
* running, it waits for the seed first.
|
|
43
|
+
* - Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
44
|
+
* is. Takes a lease either way. The component that reads the handle
|
|
45
|
+
* suspends until the result settles. On a request registry whose async
|
|
46
|
+
* seed is still running, it waits for the seed first.
|
|
47
|
+
* - A derived atom that isn't serializable, such as an error boundary's
|
|
48
|
+
* `wrap(source)`, starts the first serializable atom its
|
|
49
|
+
* `initialValueTarget` chain points at, the one `useAtomResult` reads it
|
|
50
|
+
* through: the lease, the handle's key and what the server sends are
|
|
51
|
+
* that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
52
|
+
* result.
|
|
53
|
+
*
|
|
54
|
+
* **Gotchas**
|
|
55
|
+
*
|
|
56
|
+
* The server sends a result still loading as a promise only when the atom
|
|
57
|
+
* it sends holds an `AsyncResult`. A derived atom whose serializable atom
|
|
58
|
+
* holds another value, such as an `Option` snapshot, crosses with the value
|
|
59
|
+
* it has when the registry is dehydrated: point it at an `AsyncResult`
|
|
60
|
+
* atom, or `ensure` it.
|
|
47
61
|
*
|
|
48
62
|
* **Example**
|
|
49
63
|
*
|
package/dist/Loader.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
|
|
|
2
2
|
import { hydrated } from "./Hydration.mjs";
|
|
3
3
|
import { isDevelopment } from "./internal/development.mjs";
|
|
4
4
|
import { keyOf, take } from "./internal/leases.mjs";
|
|
5
|
-
import { atomOf, loaded as loaded$1, make as make$1 } from "./internal/handles.mjs";
|
|
5
|
+
import { atomOf, loaded as loaded$1, make as make$1, sourceOf } from "./internal/handles.mjs";
|
|
6
6
|
import { afterSeed, pending } from "./internal/seeds.mjs";
|
|
7
7
|
import { isRequestRegistry } from "./RequestRegistry.mjs";
|
|
8
8
|
import * as Atom from "effect/reactivity/Atom";
|
|
@@ -70,14 +70,16 @@ const start = Effect.fnUntraced(function* (atom) {
|
|
|
70
70
|
const seed = pending(registry);
|
|
71
71
|
if (seed !== void 0) yield* Effect.promise(() => seed);
|
|
72
72
|
const request = isRequestRegistry(registry);
|
|
73
|
-
|
|
73
|
+
const source = sourceOf(atom);
|
|
74
|
+
if (request && !Atom.isSerializable(source) && (yield* isDevelopment)) return yield* Effect.die(/* @__PURE__ */ new Error(`raf-effect-atom: a loader started ${String(atom)}, which isn't serializable and doesn't point at a serializable atom with initialValueTarget, so the browser would request it again. Give it a serialization key, such as AtomRpc's serializationKey option.`));
|
|
74
75
|
const ttl = request ? void 0 : Duration.toMillis(yield* LeaseTTL);
|
|
75
|
-
const target = hydrated(
|
|
76
|
+
const target = hydrated(source);
|
|
76
77
|
const key = keyOf(target);
|
|
77
78
|
const existed = registry.getNodes().has(key) || Predicate.isString(key) && registry.preloadedSerializable.has(key);
|
|
78
79
|
take(registry, target, ttl);
|
|
79
80
|
return {
|
|
80
81
|
existed,
|
|
82
|
+
read: source === atom ? hydrated(atom) : atom,
|
|
81
83
|
registry,
|
|
82
84
|
request,
|
|
83
85
|
target
|
|
@@ -115,10 +117,24 @@ const rejectDefects = (result) => {
|
|
|
115
117
|
*
|
|
116
118
|
* **Details**
|
|
117
119
|
*
|
|
118
|
-
* Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
119
|
-
* Takes a lease either way. The component that reads the handle
|
|
120
|
-
* until the result settles. On a request registry whose async
|
|
121
|
-
* running, it waits for the seed first.
|
|
120
|
+
* - Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
121
|
+
* is. Takes a lease either way. The component that reads the handle
|
|
122
|
+
* suspends until the result settles. On a request registry whose async
|
|
123
|
+
* seed is still running, it waits for the seed first.
|
|
124
|
+
* - A derived atom that isn't serializable, such as an error boundary's
|
|
125
|
+
* `wrap(source)`, starts the first serializable atom its
|
|
126
|
+
* `initialValueTarget` chain points at, the one `useAtomResult` reads it
|
|
127
|
+
* through: the lease, the handle's key and what the server sends are
|
|
128
|
+
* that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
129
|
+
* result.
|
|
130
|
+
*
|
|
131
|
+
* **Gotchas**
|
|
132
|
+
*
|
|
133
|
+
* The server sends a result still loading as a promise only when the atom
|
|
134
|
+
* it sends holds an `AsyncResult`. A derived atom whose serializable atom
|
|
135
|
+
* holds another value, such as an `Option` snapshot, crosses with the value
|
|
136
|
+
* it has when the registry is dehydrated: point it at an `AsyncResult`
|
|
137
|
+
* atom, or `ensure` it.
|
|
122
138
|
*
|
|
123
139
|
* **Example**
|
|
124
140
|
*
|
|
@@ -181,7 +197,7 @@ const loaded = (args, atom, result) => {
|
|
|
181
197
|
const ensure = (source, ...args) => Effect.gen(function* () {
|
|
182
198
|
const atom = atomOf(source, args);
|
|
183
199
|
const started = yield* start(atom);
|
|
184
|
-
const result = yield* settled(started.registry, started.
|
|
200
|
+
const result = yield* settled(started.registry, started.read, started.request ? isSettled : AsyncResult.isNotInitial);
|
|
185
201
|
return loaded(args, atom, result);
|
|
186
202
|
});
|
|
187
203
|
/**
|
|
@@ -207,12 +223,12 @@ const ensure = (source, ...args) => Effect.gen(function* () {
|
|
|
207
223
|
const fetch = (source, ...args) => Effect.gen(function* () {
|
|
208
224
|
const atom = atomOf(source, args);
|
|
209
225
|
const started = yield* start(atom);
|
|
210
|
-
const { registry, target } = started;
|
|
211
|
-
if (started.existed && isSettled(registry.get(
|
|
226
|
+
const { read, registry, target } = started;
|
|
227
|
+
if (started.existed && isSettled(registry.get(read))) {
|
|
212
228
|
const node = registry.getNodes().get(keyOf(target));
|
|
213
|
-
registry.refresh(node?.atom ?? target);
|
|
229
|
+
registry.refresh(read === target ? node?.atom ?? target : read);
|
|
214
230
|
}
|
|
215
|
-
const result = yield* settled(registry,
|
|
231
|
+
const result = yield* settled(registry, read, isSettled);
|
|
216
232
|
return loaded(args, atom, result);
|
|
217
233
|
});
|
|
218
234
|
const results = /* @__PURE__ */ new WeakMap();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Seed as Seed$1 } from "./internal/seeds.mjs";
|
|
2
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
2
3
|
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
3
4
|
import * as Layer from "effect/Layer";
|
|
4
5
|
declare namespace RequestRegistry_d_exports {
|
|
5
|
-
export { Options, Seed, isRequestRegistry, layer, make, settled };
|
|
6
|
+
export { InitialValues, Options, Seed, isRequestRegistry, layer, make, settled };
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* Prepares a request registry before the loader verbs start atoms in it,
|
|
@@ -13,6 +14,16 @@ declare namespace RequestRegistry_d_exports {
|
|
|
13
14
|
* @since 0.2.0
|
|
14
15
|
*/
|
|
15
16
|
export type Seed = Seed$1;
|
|
17
|
+
/**
|
|
18
|
+
* Atoms paired with the values a registry starts with, as
|
|
19
|
+
* `AtomRegistry.make`'s `initialValues` takes them: build each pair with
|
|
20
|
+
* `Atom.initialValue`.
|
|
21
|
+
*
|
|
22
|
+
* @stability unstable
|
|
23
|
+
* @category models
|
|
24
|
+
* @since 0.2.4
|
|
25
|
+
*/
|
|
26
|
+
export type InitialValues = Iterable<readonly [Atom.Atom<any>, any, Atom.InitialValueOptions?]>;
|
|
16
27
|
/**
|
|
17
28
|
* Options for `make`.
|
|
18
29
|
*
|
|
@@ -21,6 +32,14 @@ export type Seed = Seed$1;
|
|
|
21
32
|
* @since 0.2.0
|
|
22
33
|
*/
|
|
23
34
|
export interface Options {
|
|
35
|
+
/**
|
|
36
|
+
* Values the registry starts with, as `AtomRegistry.make`'s
|
|
37
|
+
* `initialValues`. Unlike `registry.set` in a seed, they reach readable
|
|
38
|
+
* atoms, such as one that provides a per-request service. The registry
|
|
39
|
+
* keeps each of these atoms mounted until it's disposed, so the value
|
|
40
|
+
* outlives the atoms that read it.
|
|
41
|
+
*/
|
|
42
|
+
readonly initialValues?: InitialValues | undefined;
|
|
24
43
|
/**
|
|
25
44
|
* Runs on the new registry before any verb starts an atom in it. When it
|
|
26
45
|
* returns a promise, `ensure` and `fetch` wait for it, and `prefetch`
|
|
@@ -38,10 +57,15 @@ export interface Options {
|
|
|
38
57
|
* in the background, and a loader's lease lasts until the registry is
|
|
39
58
|
* disposed. In development, the loader verbs refuse an atom that isn't
|
|
40
59
|
* serializable, because the browser would request it again.
|
|
60
|
+
* - `initialValues` are values the request's atoms start with, set on each
|
|
61
|
+
* atom, or on the end of its `initialValueTarget` chain, before anything
|
|
62
|
+
* reads it. They reach atoms `registry.set` can't, such as a readable atom
|
|
63
|
+
* that provides the request's `fetch`, and each stays mounted until the
|
|
64
|
+
* registry is disposed.
|
|
41
65
|
* - `seed` sets what the request's atoms need before they run, such as the
|
|
42
66
|
* page request's cookie for an RPC protocol that forwards it. It can be
|
|
43
67
|
* async, for request data only a promise gives, such as Next.js's
|
|
44
|
-
* `headers()`.
|
|
68
|
+
* `headers()`. It runs after `initialValues` are set.
|
|
45
69
|
*
|
|
46
70
|
* **Gotchas**
|
|
47
71
|
*
|
|
@@ -52,9 +76,11 @@ export interface Options {
|
|
|
52
76
|
* **Example**
|
|
53
77
|
*
|
|
54
78
|
* ```ts
|
|
79
|
+
* import { Atom } from "effect/reactivity"
|
|
55
80
|
* import { RequestRegistry } from "raf-effect-atom"
|
|
56
81
|
*
|
|
57
82
|
* const registry = RequestRegistry.make({
|
|
83
|
+
* initialValues: [Atom.initialValue(requestFetch, request.fetch)],
|
|
58
84
|
* seed: (registry) => registry.set(requestCookie, request.headers.get("cookie") ?? undefined)
|
|
59
85
|
* })
|
|
60
86
|
* ```
|
package/dist/RequestRegistry.mjs
CHANGED
|
@@ -33,10 +33,15 @@ const requestRegistries = /* @__PURE__ */ new WeakSet();
|
|
|
33
33
|
* in the background, and a loader's lease lasts until the registry is
|
|
34
34
|
* disposed. In development, the loader verbs refuse an atom that isn't
|
|
35
35
|
* serializable, because the browser would request it again.
|
|
36
|
+
* - `initialValues` are values the request's atoms start with, set on each
|
|
37
|
+
* atom, or on the end of its `initialValueTarget` chain, before anything
|
|
38
|
+
* reads it. They reach atoms `registry.set` can't, such as a readable atom
|
|
39
|
+
* that provides the request's `fetch`, and each stays mounted until the
|
|
40
|
+
* registry is disposed.
|
|
36
41
|
* - `seed` sets what the request's atoms need before they run, such as the
|
|
37
42
|
* page request's cookie for an RPC protocol that forwards it. It can be
|
|
38
43
|
* async, for request data only a promise gives, such as Next.js's
|
|
39
|
-
* `headers()`.
|
|
44
|
+
* `headers()`. It runs after `initialValues` are set.
|
|
40
45
|
*
|
|
41
46
|
* **Gotchas**
|
|
42
47
|
*
|
|
@@ -47,9 +52,11 @@ const requestRegistries = /* @__PURE__ */ new WeakSet();
|
|
|
47
52
|
* **Example**
|
|
48
53
|
*
|
|
49
54
|
* ```ts
|
|
55
|
+
* import { Atom } from "effect/reactivity"
|
|
50
56
|
* import { RequestRegistry } from "raf-effect-atom"
|
|
51
57
|
*
|
|
52
58
|
* const registry = RequestRegistry.make({
|
|
59
|
+
* initialValues: [Atom.initialValue(requestFetch, request.fetch)],
|
|
53
60
|
* seed: (registry) => registry.set(requestCookie, request.headers.get("cookie") ?? undefined)
|
|
54
61
|
* })
|
|
55
62
|
* ```
|
|
@@ -59,8 +66,10 @@ const requestRegistries = /* @__PURE__ */ new WeakSet();
|
|
|
59
66
|
* @since 0.1.0
|
|
60
67
|
*/
|
|
61
68
|
const make = (options) => {
|
|
62
|
-
const
|
|
69
|
+
const initialValues = options?.initialValues === void 0 ? void 0 : Array.from(options.initialValues);
|
|
70
|
+
const registry = AtomRegistry.make({ initialValues });
|
|
63
71
|
requestRegistries.add(registry);
|
|
72
|
+
if (initialValues !== void 0) for (const [atom] of initialValues) registry.mount(atom);
|
|
64
73
|
if (options?.seed !== void 0) run(registry, options.seed);
|
|
65
74
|
return registry;
|
|
66
75
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Seed } from "./RequestRegistry.mjs";
|
|
1
|
+
import { InitialValues, Seed } from "./RequestRegistry.mjs";
|
|
2
2
|
import * as EffectHydration from "effect/reactivity/Hydration";
|
|
3
3
|
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
4
4
|
import { AnyRouter } from "@tanstack/react-router";
|
|
@@ -39,6 +39,12 @@ export interface RouterAtomsOptions<TRouter extends AnyRouter> {
|
|
|
39
39
|
* default registry does. An atom's own `Atom.setIdleTTL` or
|
|
40
40
|
* `Atom.keepAlive` wins. The server's request registry lives for one
|
|
41
41
|
* request, so it has none.
|
|
42
|
+
* - `initialValues` are values both registries start with, as
|
|
43
|
+
* `AtomRegistry.make`'s `initialValues`, such as the session the server
|
|
44
|
+
* verified or a readable atom that provides the request's `fetch`. The
|
|
45
|
+
* server's request registry keeps those atoms mounted until it's disposed.
|
|
46
|
+
* The browser's registry drops an atom no component reads, value included,
|
|
47
|
+
* so make one whose value must outlive its readers `Atom.keepAlive`.
|
|
42
48
|
* - `seed` runs on the server's request registry before the loaders start
|
|
43
49
|
* atoms in it, as `RequestRegistry.make`'s does: set what the request's
|
|
44
50
|
* atoms need, such as its cookie. It can be async. The browser's registry
|
|
@@ -64,6 +70,7 @@ export interface RouterAtomsOptions<TRouter extends AnyRouter> {
|
|
|
64
70
|
*/
|
|
65
71
|
export declare const makeRegistry: (options?: {
|
|
66
72
|
readonly defaultIdleTTL?: number | undefined;
|
|
73
|
+
readonly initialValues?: InitialValues | undefined;
|
|
67
74
|
readonly seed?: Seed | undefined;
|
|
68
75
|
}) => AtomRegistry.AtomRegistry;
|
|
69
76
|
/**
|
package/dist/TanStackRouter.mjs
CHANGED
|
@@ -51,6 +51,12 @@ import { jsx } from "react/jsx-runtime";
|
|
|
51
51
|
* default registry does. An atom's own `Atom.setIdleTTL` or
|
|
52
52
|
* `Atom.keepAlive` wins. The server's request registry lives for one
|
|
53
53
|
* request, so it has none.
|
|
54
|
+
* - `initialValues` are values both registries start with, as
|
|
55
|
+
* `AtomRegistry.make`'s `initialValues`, such as the session the server
|
|
56
|
+
* verified or a readable atom that provides the request's `fetch`. The
|
|
57
|
+
* server's request registry keeps those atoms mounted until it's disposed.
|
|
58
|
+
* The browser's registry drops an atom no component reads, value included,
|
|
59
|
+
* so make one whose value must outlive its readers `Atom.keepAlive`.
|
|
54
60
|
* - `seed` runs on the server's request registry before the loaders start
|
|
55
61
|
* atoms in it, as `RequestRegistry.make`'s does: set what the request's
|
|
56
62
|
* atoms need, such as its cookie. It can be async. The browser's registry
|
package/dist/Waterfalls.d.mts
CHANGED
|
@@ -72,12 +72,9 @@ export declare const WaterfallDetection: (props: {
|
|
|
72
72
|
* - `useAtomResult` doesn't report an atom started this way.
|
|
73
73
|
* - The handle is a prefetched one: its reader suspends until the result
|
|
74
74
|
* settles, as for a handle from a loader's `prefetch`.
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* Pass it the source a loader would start, not an error boundary's
|
|
79
|
-
* `wrap(source)`: the wrapper's atoms aren't serializable, so the server
|
|
80
|
-
* couldn't send them to the browser. Read the handle through the wrapper.
|
|
75
|
+
* - A derived source, such as an error boundary's `wrap(source)`, starts
|
|
76
|
+
* the serializable atom its `initialValueTarget` chain points at, as
|
|
77
|
+
* `Loader.prefetch` does.
|
|
81
78
|
*
|
|
82
79
|
* **Example**
|
|
83
80
|
*
|
package/dist/Waterfalls.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { get } from "./internal/pending.mjs";
|
|
3
3
|
import { hydrated } from "./Hydration.mjs";
|
|
4
4
|
import { keyOf } from "./internal/leases.mjs";
|
|
5
|
-
import { atomOf, make } from "./internal/handles.mjs";
|
|
5
|
+
import { atomOf, make, sourceOf } from "./internal/handles.mjs";
|
|
6
6
|
import { prefetch } from "./Loader.mjs";
|
|
7
7
|
import { ModeContext, isStarted } from "./internal/waterfalls.mjs";
|
|
8
8
|
import * as Predicate from "effect/Predicate";
|
|
@@ -76,12 +76,9 @@ const WaterfallDetection = (props) => process.env.NODE_ENV === "production" ? pr
|
|
|
76
76
|
* - `useAtomResult` doesn't report an atom started this way.
|
|
77
77
|
* - The handle is a prefetched one: its reader suspends until the result
|
|
78
78
|
* settles, as for a handle from a loader's `prefetch`.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* Pass it the source a loader would start, not an error boundary's
|
|
83
|
-
* `wrap(source)`: the wrapper's atoms aren't serializable, so the server
|
|
84
|
-
* couldn't send them to the browser. Read the handle through the wrapper.
|
|
79
|
+
* - A derived source, such as an error boundary's `wrap(source)`, starts
|
|
80
|
+
* the serializable atom its `initialValueTarget` chain points at, as
|
|
81
|
+
* `Loader.prefetch` does.
|
|
85
82
|
*
|
|
86
83
|
* **Example**
|
|
87
84
|
*
|
|
@@ -103,7 +100,7 @@ const WaterfallDetection = (props) => process.env.NODE_ENV === "production" ? pr
|
|
|
103
100
|
const useWaterfall = (source, ...args) => {
|
|
104
101
|
const registry = React.useContext(RegistryContext);
|
|
105
102
|
const atom = atomOf(source, args);
|
|
106
|
-
const target = hydrated(atom);
|
|
103
|
+
const target = hydrated(sourceOf(atom));
|
|
107
104
|
const key = keyOf(target);
|
|
108
105
|
if (!(Predicate.isString(key) && get(registry, key) !== void 0) && !isStarted(registry, target)) return Effect.runSync(Effect.provideService(prefetch(source, ...args), AtomRegistry.AtomRegistry, registry));
|
|
109
106
|
return make(args, atom);
|
|
@@ -4,9 +4,18 @@ import * as Predicate from "effect/Predicate";
|
|
|
4
4
|
// src/internal/handles.ts
|
|
5
5
|
/** The atom a source makes for its arguments. */
|
|
6
6
|
const atomOf = (source, args) => Atom.isAtom(source) ? source : source(...args);
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* The atom the loader starts and the server sends for `atom`: the first
|
|
9
|
+
* serializable atom in its `initialValueTarget` chain, starting with `atom`.
|
|
10
|
+
* An AtomRpc query is serializable itself, though it points at an inner atom.
|
|
11
|
+
*/
|
|
12
|
+
const sourceOf = (atom) => {
|
|
13
|
+
for (let target = atom; target !== void 0; target = target.initialValueTarget) if (Atom.isSerializable(target)) return target;
|
|
14
|
+
return atom;
|
|
15
|
+
};
|
|
16
|
+
/** The registry key a handle records: its source atom's serialization key. */
|
|
8
17
|
const keyOf = (atom) => {
|
|
9
|
-
const key = keyOf$1(atom);
|
|
18
|
+
const key = keyOf$1(sourceOf(atom));
|
|
10
19
|
if (!Predicate.isString(key)) return;
|
|
11
20
|
return key;
|
|
12
21
|
};
|
|
@@ -19,4 +28,4 @@ const loaded = (args, atom) => ({
|
|
|
19
28
|
key: keyOf(atom),
|
|
20
29
|
loaded: true
|
|
21
30
|
});
|
|
22
|
-
export { atomOf, loaded, make };
|
|
31
|
+
export { atomOf, loaded, make, sourceOf };
|
|
@@ -19,8 +19,12 @@ const defaultIdleTTL = 400;
|
|
|
19
19
|
* A request registry on the server, and in the browser a registry like
|
|
20
20
|
* `@effect/atom-react`'s `RegistryProvider` makes.
|
|
21
21
|
*/
|
|
22
|
-
const make = (options) => isServer() ? make$1({
|
|
22
|
+
const make = (options) => isServer() ? make$1({
|
|
23
|
+
initialValues: options?.initialValues,
|
|
24
|
+
seed: options?.seed
|
|
25
|
+
}) : AtomRegistry.make({
|
|
23
26
|
defaultIdleTTL: options?.defaultIdleTTL ?? defaultIdleTTL,
|
|
27
|
+
initialValues: options?.initialValues,
|
|
24
28
|
scheduleTask
|
|
25
29
|
});
|
|
26
30
|
let mounted;
|
package/package.json
CHANGED