raf-effect-atom 0.2.4 → 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 +8 -2
- package/dist/Hooks.mjs +1 -11
- package/dist/Loader.d.mts +18 -4
- package/dist/Loader.mjs +28 -12
- package/dist/Waterfalls.d.mts +3 -6
- package/dist/Waterfalls.mjs +5 -8
- package/dist/internal/handles.mjs +12 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
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
|
+
|
|
3
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)
|
|
4
10
|
|
|
5
11
|
### Features
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
- **raf-effect-atom:** start a request registry with initialValues, readable atoms included ([67cf767](https://github.com/KATT/raf-effect-atom/commit/67cf767e121e76b385ff0808a087efc6662aed89))
|
|
8
14
|
|
|
9
15
|
### Documentation
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
- correct the generated changelogs' cut-off breaking change and bogus issue links ([c21f64c](https://github.com/KATT/raf-effect-atom/commit/c21f64cad3b4638f2341968aa2e10af5a19904c1))
|
|
12
18
|
|
|
13
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)
|
|
14
20
|
|
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();
|
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 };
|
package/package.json
CHANGED