raf-effect-atom 0.3.0 → 0.3.2
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 +29 -2
- package/README.md +2 -2
- package/dist/Loader.d.mts +12 -10
- package/dist/Loader.mjs +11 -9
- package/dist/{ReactHydration.react-server.d.mts → hydration-boundary-react-server.d.mts} +1 -1
- package/dist/{ReactHydration.react-server.mjs → hydration-boundary-react-server.mjs} +2 -2
- package/dist/{ReactHydration.mjs → hydration-boundary.mjs} +1 -1
- package/dist/{index.react-server.d.mts → index-react-server.d.mts} +9 -9
- package/dist/index-react-server.mjs +8 -0
- package/dist/{index.shared.d.mts → index-shared.d.mts} +7 -7
- package/dist/index.d.mts +8 -8
- package/dist/index.mjs +5 -5
- package/dist/internal/leases.mjs +36 -15
- package/dist/{ReactRouter.mjs → react-router.mjs} +1 -1
- package/dist/{RegistryProvider.mjs → registry-provider.mjs} +1 -1
- package/dist/{Rsc.d.mts → rsc.d.mts} +1 -1
- package/dist/{Rsc.mjs → rsc.mjs} +1 -1
- package/dist/{TanStackRouter.mjs → tanstack-router.mjs} +1 -1
- package/dist/{Hooks.d.mts → use-atom-result.d.mts} +69 -10
- package/dist/{Hooks.mjs → use-atom-result.mjs} +124 -22
- package/dist/{Waterfalls.d.mts → waterfalls.d.mts} +3 -4
- package/dist/{Waterfalls.mjs → waterfalls.mjs} +3 -4
- package/package.json +6 -6
- package/dist/index.react-server.mjs +0 -8
- /package/dist/{Handle.d.mts → handle.d.mts} +0 -0
- /package/dist/{ReactHydration.d.mts → hydration-boundary.d.mts} +0 -0
- /package/dist/{ReactRouter.d.mts → react-router.d.mts} +0 -0
- /package/dist/{RegistryProvider.d.mts → registry-provider.d.mts} +0 -0
- /package/dist/{TanStackRouter.d.mts → tanstack-router.d.mts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.2](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.3.1...raf-effect-atom%400.3.2) (2026-10-24)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* **raf-effect-atom:** take no lease on an atom a mounted component reads ([899d0b7](https://github.com/KATT/raf-effect-atom/commit/899d0b7c70f6836c41c4416b0c2063c1ccf3d8b2))
|
|
8
|
+
|
|
9
|
+
## [0.3.1](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.3.0...raf-effect-atom%400.3.1) (2026-10-24)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- **raf-effect-atom:** add useHandleValue, a handle read that doesn't suspend ([4b083f7](https://github.com/KATT/raf-effect-atom/commit/4b083f7dee91834cda71691f44a1498061f3cfe1))
|
|
14
|
+
|
|
15
|
+
### Code Refactoring
|
|
16
|
+
|
|
17
|
+
- name files in kebab-case, PascalCase only for Effect modules ([d76b06a](https://github.com/KATT/raf-effect-atom/commit/d76b06aef3d04d6be6c0b0e086a756234ab3f253))
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- **raf-effect-atom:** pass a read's result to a boundary's hook in the README and JSDoc ([fd82e5c](https://github.com/KATT/raf-effect-atom/commit/fd82e5c1f92b3f99dc166140383837b11b695ca7))
|
|
22
|
+
- **raf-effect-atom:** pass the atom to a boundary's hook in the README and JSDoc ([772d349](https://github.com/KATT/raf-effect-atom/commit/772d3494954f64a5c0fc92ebfd146b5f14e16e51))
|
|
23
|
+
|
|
24
|
+
### Tests
|
|
25
|
+
|
|
26
|
+
- **raf-effect-atom:** pass a read's result to a boundary's hook ([df11247](https://github.com/KATT/raf-effect-atom/commit/df11247edab69b060c0677059ae24a4d8835c28e))
|
|
27
|
+
- **raf-effect-atom:** read through a boundary's hook with the atom ([de19b85](https://github.com/KATT/raf-effect-atom/commit/de19b8502ef41a8efbd9b50da6e00843cb38f2fd))
|
|
28
|
+
- **raf-effect-atom:** start an Atom.swr over a keyed readable that picks a seed or a live query ([697e785](https://github.com/KATT/raf-effect-atom/commit/697e78550bff0dce02903b963677828786770338))
|
|
29
|
+
|
|
3
30
|
## [0.3.0](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.6...raf-effect-atom%400.3.0) (2026-10-23)
|
|
4
31
|
|
|
5
32
|
### ⚠ BREAKING CHANGES
|
|
6
33
|
|
|
7
|
-
|
|
34
|
+
- **raf-effect-atom:** `raf-effect-atom/next` is `raf-effect-atom/rsc`, without `dehydrate`; write `<HydrationBoundary registry={getRegistry()}>` from `raf-effect-atom` instead of `<HydrateAtoms state={await dehydrate()}>`, and import `RegistryProvider` from `raf-effect-atom`.
|
|
8
35
|
|
|
9
36
|
### Features
|
|
10
37
|
|
|
11
|
-
|
|
38
|
+
- **raf-effect-atom:** import HydrationBoundary from raf-effect-atom in server components, and the RSC verbs from raf-effect-atom/rsc ([bf7fdbc](https://github.com/KATT/raf-effect-atom/commit/bf7fdbcde2e9f785bd276a08117aefa359051b82))
|
|
12
39
|
|
|
13
40
|
## [0.2.6](https://github.com/KATT/raf-effect-atom/compare/raf-effect-atom%400.2.5...raf-effect-atom%400.2.6) (2026-10-23)
|
|
14
41
|
|
package/README.md
CHANGED
|
@@ -37,13 +37,13 @@ export async function loader(args: LoaderArgs) {
|
|
|
37
37
|
}
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
A component takes the handle as a prop and reads it with `useAtomResult(source, handle)`, which waits for a streamed result instead of starting the atom again, and returns typed failures. Given a handle instead of an id, it can't start a request of its own.
|
|
40
|
+
A component takes the handle as a prop and reads it with `useAtomResult(source, handle)`, which waits for a streamed result instead of starting the atom again, and returns typed failures. Given a handle instead of an id, it can't start a request of its own. An [`effect-atom-boundary`](https://github.com/KATT/raf-effect-atom/tree/main/packages/effect-atom-boundary) boundary's hook takes the result, throws the errors that boundary claims to it, and returns the rest:
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
import { type Handle, useAtomResult } from "raf-effect-atom";
|
|
44
44
|
|
|
45
45
|
function IssueTitle(props: { readonly issue: Handle<typeof issue> }) {
|
|
46
|
-
const result =
|
|
46
|
+
const result = useIssueBoundary(useAtomResult(issue, props.issue));
|
|
47
47
|
// Success<Issue, never>: its boundaries claim every failure
|
|
48
48
|
return <h1>{result.value.title}</h1>;
|
|
49
49
|
}
|
package/dist/Loader.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArgsOf, ErrorOf, Handle, LoadedHandle, Source, SuccessOf } from "./
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, LoadedHandle, Source, SuccessOf } from "./handle.mjs";
|
|
2
2
|
import * as Context from "effect/Context";
|
|
3
3
|
import * as Duration from "effect/Duration";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
@@ -21,9 +21,11 @@ export type SettledResult<A, E> = AsyncResult.Failure<A, E> | AsyncResult.Succes
|
|
|
21
21
|
*
|
|
22
22
|
* **Details**
|
|
23
23
|
*
|
|
24
|
-
* A lease ends when `useAtomResult` mounts the atom, or
|
|
25
|
-
* passed, after which the registry's idle TTL applies as
|
|
26
|
-
*
|
|
24
|
+
* A lease ends when `useAtomResult` or `useHandleValue` mounts the atom, or
|
|
25
|
+
* when this time has passed, after which the registry's idle TTL applies as
|
|
26
|
+
* usual. While a component reads the atom, a verb takes no lease on it, so the
|
|
27
|
+
* atom goes idle when the last reader unmounts. On a request registry, leases
|
|
28
|
+
* last until the registry is disposed.
|
|
27
29
|
*
|
|
28
30
|
* @stability unstable
|
|
29
31
|
* @category references
|
|
@@ -41,14 +43,14 @@ export declare const LeaseTTL: Context.Reference<Duration.Duration>;
|
|
|
41
43
|
* **Details**
|
|
42
44
|
*
|
|
43
45
|
* - Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
44
|
-
* is. Takes a lease either way
|
|
46
|
+
* is. Takes a lease either way, unless a mounted component reads the
|
|
47
|
+
* atom. The component that reads the handle
|
|
45
48
|
* suspends until the result settles. On a request registry whose async
|
|
46
49
|
* seed is still running, it waits for the seed first.
|
|
47
|
-
* - A derived atom that isn't serializable
|
|
48
|
-
* `
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
50
|
+
* - A derived atom that isn't serializable starts the first serializable
|
|
51
|
+
* atom its `initialValueTarget` chain points at, the one `useAtomResult`
|
|
52
|
+
* reads it through: the lease, the handle's key and what the server sends
|
|
53
|
+
* are that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
52
54
|
* result.
|
|
53
55
|
*
|
|
54
56
|
* **Gotchas**
|
package/dist/Loader.mjs
CHANGED
|
@@ -60,9 +60,11 @@ var Loader_exports = /* @__PURE__ */ __exportAll({
|
|
|
60
60
|
*
|
|
61
61
|
* **Details**
|
|
62
62
|
*
|
|
63
|
-
* A lease ends when `useAtomResult` mounts the atom, or
|
|
64
|
-
* passed, after which the registry's idle TTL applies as
|
|
65
|
-
*
|
|
63
|
+
* A lease ends when `useAtomResult` or `useHandleValue` mounts the atom, or
|
|
64
|
+
* when this time has passed, after which the registry's idle TTL applies as
|
|
65
|
+
* usual. While a component reads the atom, a verb takes no lease on it, so the
|
|
66
|
+
* atom goes idle when the last reader unmounts. On a request registry, leases
|
|
67
|
+
* last until the registry is disposed.
|
|
66
68
|
*
|
|
67
69
|
* @stability unstable
|
|
68
70
|
* @category references
|
|
@@ -122,14 +124,14 @@ const rejectDefects = (result) => {
|
|
|
122
124
|
* **Details**
|
|
123
125
|
*
|
|
124
126
|
* - Starts the atom if it isn't in the registry, and leaves it alone if it
|
|
125
|
-
* is. Takes a lease either way
|
|
127
|
+
* is. Takes a lease either way, unless a mounted component reads the
|
|
128
|
+
* atom. The component that reads the handle
|
|
126
129
|
* suspends until the result settles. On a request registry whose async
|
|
127
130
|
* seed is still running, it waits for the seed first.
|
|
128
|
-
* - A derived atom that isn't serializable
|
|
129
|
-
* `
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
131
|
+
* - A derived atom that isn't serializable starts the first serializable
|
|
132
|
+
* atom its `initialValueTarget` chain points at, the one `useAtomResult`
|
|
133
|
+
* reads it through: the lease, the handle's key and what the server sends
|
|
134
|
+
* are that atom's. `ensure` and `fetch` wait for the derived atom's own
|
|
133
135
|
* result.
|
|
134
136
|
*
|
|
135
137
|
* **Gotchas**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { dehydrate } from "./Hydration.mjs";
|
|
2
2
|
import { isRequestRegistry, settled } from "./RequestRegistry.mjs";
|
|
3
|
-
import { HydrationBoundary as HydrationBoundary$1 } from "./
|
|
3
|
+
import { HydrationBoundary as HydrationBoundary$1 } from "./hydration-boundary.mjs";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
// src/
|
|
5
|
+
// src/hydration-boundary-react-server.tsx
|
|
6
6
|
/**
|
|
7
7
|
* Sends a server component's request registry to the client components
|
|
8
8
|
* under it.
|
|
@@ -5,7 +5,7 @@ import { isServer, requireRequestRegistry } from "./internal/registry.mjs";
|
|
|
5
5
|
import { HydrationBoundary, RegistryContext } from "@effect/atom-react";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
// src/
|
|
8
|
+
// src/hydration-boundary.tsx
|
|
9
9
|
/**
|
|
10
10
|
* Applies a server registry's dehydrated state to the nearest
|
|
11
11
|
* `RegistryContext`, while rendering.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./handle.mjs";
|
|
2
|
+
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
2
3
|
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
4
|
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import "./
|
|
10
|
-
|
|
11
|
-
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, HydrationBoundary, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useWaterfall };
|
|
5
|
+
import { useAtomResult, useHandleValue } from "./use-atom-result.mjs";
|
|
6
|
+
import { HydrationBoundaryProps } from "./hydration-boundary.mjs";
|
|
7
|
+
import { RegistryProvider } from "./registry-provider.mjs";
|
|
8
|
+
import { WaterfallDetection, WaterfallMode, useWaterfall } from "./waterfalls.mjs";
|
|
9
|
+
import "./index-shared.mjs";
|
|
10
|
+
import { HydrationBoundary } from "./hydration-boundary-react-server.mjs";
|
|
11
|
+
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, HydrationBoundary, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useHandleValue, useWaterfall };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Hydration_exports } from "./Hydration.mjs";
|
|
2
|
+
import { RequestRegistry_exports } from "./RequestRegistry.mjs";
|
|
3
|
+
import { Loader_exports } from "./Loader.mjs";
|
|
4
|
+
import { useAtomResult, useHandleValue } from "./use-atom-result.mjs";
|
|
5
|
+
import { RegistryProvider } from "./registry-provider.mjs";
|
|
6
|
+
import { WaterfallDetection, useWaterfall } from "./waterfalls.mjs";
|
|
7
|
+
import { HydrationBoundary } from "./hydration-boundary-react-server.mjs";
|
|
8
|
+
export { Hydration_exports as Hydration, HydrationBoundary, Loader_exports as Loader, RegistryProvider, RequestRegistry_exports as RequestRegistry, WaterfallDetection, useAtomResult, useHandleValue, useWaterfall };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./handle.mjs";
|
|
2
|
+
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
2
3
|
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
4
|
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useWaterfall };
|
|
5
|
+
import { useAtomResult, useHandleValue } from "./use-atom-result.mjs";
|
|
6
|
+
import { HydrationBoundaryProps } from "./hydration-boundary.mjs";
|
|
7
|
+
import { RegistryProvider } from "./registry-provider.mjs";
|
|
8
|
+
import { WaterfallDetection, WaterfallMode, useWaterfall } from "./waterfalls.mjs";
|
|
9
|
+
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useHandleValue, useWaterfall };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./handle.mjs";
|
|
2
|
+
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
2
3
|
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
4
|
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, HydrationBoundary, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useWaterfall };
|
|
5
|
+
import { useAtomResult, useHandleValue } from "./use-atom-result.mjs";
|
|
6
|
+
import { HydrationBoundary, HydrationBoundaryProps } from "./hydration-boundary.mjs";
|
|
7
|
+
import { RegistryProvider } from "./registry-provider.mjs";
|
|
8
|
+
import { WaterfallDetection, WaterfallMode, useWaterfall } from "./waterfalls.mjs";
|
|
9
|
+
import "./index-shared.mjs";
|
|
10
|
+
export { ArgsOf, ErrorOf, Handle, HandleKey, Hydration_d_exports as Hydration, HydrationBoundary, type HydrationBoundaryProps, LoadedHandle, Loader_d_exports as Loader, RegistryProvider, RequestRegistry_d_exports as RequestRegistry, Source, SuccessOf, WaterfallDetection, WaterfallMode, useAtomResult, useHandleValue, useWaterfall };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Hydration_exports } from "./Hydration.mjs";
|
|
2
2
|
import { RequestRegistry_exports } from "./RequestRegistry.mjs";
|
|
3
3
|
import { Loader_exports } from "./Loader.mjs";
|
|
4
|
-
import { useAtomResult } from "./
|
|
5
|
-
import { RegistryProvider } from "./
|
|
6
|
-
import { WaterfallDetection, useWaterfall } from "./
|
|
7
|
-
import { HydrationBoundary } from "./
|
|
8
|
-
export { Hydration_exports as Hydration, HydrationBoundary, Loader_exports as Loader, RegistryProvider, RequestRegistry_exports as RequestRegistry, WaterfallDetection, useAtomResult, useWaterfall };
|
|
4
|
+
import { useAtomResult, useHandleValue } from "./use-atom-result.mjs";
|
|
5
|
+
import { RegistryProvider } from "./registry-provider.mjs";
|
|
6
|
+
import { WaterfallDetection, useWaterfall } from "./waterfalls.mjs";
|
|
7
|
+
import { HydrationBoundary } from "./hydration-boundary.mjs";
|
|
8
|
+
export { Hydration_exports as Hydration, HydrationBoundary, Loader_exports as Loader, RegistryProvider, RequestRegistry_exports as RequestRegistry, WaterfallDetection, useAtomResult, useHandleValue, useWaterfall };
|
package/dist/internal/leases.mjs
CHANGED
|
@@ -1,39 +1,60 @@
|
|
|
1
1
|
import * as Atom from "effect/reactivity/Atom";
|
|
2
2
|
// src/internal/leases.ts
|
|
3
|
-
const
|
|
3
|
+
const registries = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
const leasesOf = (registry) => {
|
|
5
|
+
let state = registries.get(registry);
|
|
6
|
+
if (state === void 0) {
|
|
7
|
+
state = {
|
|
8
|
+
leases: /* @__PURE__ */ new Map(),
|
|
9
|
+
readers: /* @__PURE__ */ new Map()
|
|
10
|
+
};
|
|
11
|
+
registries.set(registry, state);
|
|
12
|
+
}
|
|
13
|
+
return state;
|
|
14
|
+
};
|
|
4
15
|
/** The registry's key for an atom: its serialization key, or the atom. */
|
|
5
16
|
const keyOf = (atom) => Atom.isSerializable(atom) ? atom[Atom.SerializableTypeId].key : atom;
|
|
6
17
|
/**
|
|
7
18
|
* Mounts `atom` until `release`, or until `ttl` milliseconds pass. Taking a
|
|
8
|
-
* lease the atom already has restarts its timer.
|
|
19
|
+
* lease the atom already has restarts its timer. While a component holds the
|
|
20
|
+
* atom (see `hold`), it takes none: the component keeps the atom mounted, and
|
|
21
|
+
* a lease would keep it mounted after the component unmounts.
|
|
9
22
|
*/
|
|
10
23
|
const take = (registry, atom, ttl) => {
|
|
11
|
-
|
|
12
|
-
if (byKey === void 0) {
|
|
13
|
-
byKey = /* @__PURE__ */ new Map();
|
|
14
|
-
leases.set(registry, byKey);
|
|
15
|
-
}
|
|
24
|
+
const state = leasesOf(registry);
|
|
16
25
|
const key = keyOf(atom);
|
|
17
|
-
|
|
26
|
+
if (state.readers.has(key)) return;
|
|
27
|
+
let lease = state.leases.get(key);
|
|
18
28
|
if (lease === void 0) {
|
|
19
29
|
const unmount = registry.mount(atom);
|
|
20
|
-
const owner = byKey;
|
|
21
30
|
const created = {
|
|
22
31
|
release: () => {
|
|
23
32
|
clearTimeout(created.timer);
|
|
24
|
-
|
|
33
|
+
state.leases.delete(key);
|
|
25
34
|
unmount();
|
|
26
35
|
},
|
|
27
36
|
timer: void 0
|
|
28
37
|
};
|
|
29
|
-
|
|
38
|
+
state.leases.set(key, created);
|
|
30
39
|
lease = created;
|
|
31
40
|
}
|
|
32
41
|
clearTimeout(lease.timer);
|
|
33
42
|
lease.timer = ttl === void 0 ? void 0 : setTimeout(lease.release, ttl);
|
|
34
43
|
};
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Marks `atom` as held by a component subscribed to it, until the returned
|
|
46
|
+
* function runs. Ends the atom's lease, and `take` takes none while any
|
|
47
|
+
* component holds it.
|
|
48
|
+
*/
|
|
49
|
+
const hold = (registry, atom) => {
|
|
50
|
+
const state = leasesOf(registry);
|
|
51
|
+
const key = keyOf(atom);
|
|
52
|
+
state.readers.set(key, (state.readers.get(key) ?? 0) + 1);
|
|
53
|
+
state.leases.get(key)?.release();
|
|
54
|
+
return () => {
|
|
55
|
+
const count = (state.readers.get(key) ?? 1) - 1;
|
|
56
|
+
if (count === 0) state.readers.delete(key);
|
|
57
|
+
else state.readers.set(key, count);
|
|
58
|
+
};
|
|
38
59
|
};
|
|
39
|
-
export {
|
|
60
|
+
export { hold, keyOf, take };
|
|
@@ -3,7 +3,7 @@ import { make, settled } from "./RequestRegistry.mjs";
|
|
|
3
3
|
import { make as make$1 } from "./Loader.mjs";
|
|
4
4
|
import { current } from "./internal/registry.mjs";
|
|
5
5
|
import * as Predicate from "effect/Predicate";
|
|
6
|
-
// src/
|
|
6
|
+
// src/react-router.ts
|
|
7
7
|
/**
|
|
8
8
|
* Connects the loader verbs to React Router's Framework Mode.
|
|
9
9
|
*
|
|
@@ -3,7 +3,7 @@ import { make, mount } from "./internal/registry.mjs";
|
|
|
3
3
|
import { RegistryContext } from "@effect/atom-react";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
// src/
|
|
6
|
+
// src/registry-provider.tsx
|
|
7
7
|
/**
|
|
8
8
|
* The registry provider for apps that render the server's state through
|
|
9
9
|
* `HydrationBoundary`, such as React Server Components and React Router.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArgsOf, Handle, LoadedHandle, Source } from "./
|
|
1
|
+
import { ArgsOf, Handle, LoadedHandle, Source } from "./handle.mjs";
|
|
2
2
|
import { Loader } from "./Loader.mjs";
|
|
3
3
|
import { Options } from "./RequestRegistry.mjs";
|
|
4
4
|
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
package/dist/{Rsc.mjs → rsc.mjs}
RENAMED
|
@@ -5,7 +5,7 @@ import * as Predicate from "effect/Predicate";
|
|
|
5
5
|
import { RegistryContext } from "@effect/atom-react";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
// src/
|
|
8
|
+
// src/tanstack-router.tsx
|
|
9
9
|
/**
|
|
10
10
|
* Connects the loader verbs to TanStack Router and TanStack Start.
|
|
11
11
|
*
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ErrorOf, Handle, Source, SuccessOf } from "./
|
|
1
|
+
import { ErrorOf, Handle, Source, SuccessOf } from "./handle.mjs";
|
|
2
2
|
import { SettledResult } from "./Loader.mjs";
|
|
3
3
|
import * as Atom from "effect/reactivity/Atom";
|
|
4
4
|
import * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
5
5
|
/**
|
|
6
6
|
* A source with the same arguments and success type as `S`, and any error:
|
|
7
|
-
* the sources whose handles `S` reads, such as the source
|
|
8
|
-
*
|
|
7
|
+
* the sources whose handles `S` reads, such as the source a derived `S`
|
|
8
|
+
* points at.
|
|
9
9
|
*/
|
|
10
10
|
type Readable<S> = S extends ((...args: infer Args) => Atom.Atom<AsyncResult.AsyncResult<infer A, infer _E>>) ? (...args: Args) => Atom.Atom<AsyncResult.AsyncResult<A, unknown>> : S extends Atom.Atom<AsyncResult.AsyncResult<infer A, infer _E>> ? Atom.Atom<AsyncResult.AsyncResult<A, unknown>> : never;
|
|
11
11
|
/**
|
|
@@ -16,8 +16,9 @@ type Readable<S> = S extends ((...args: infer Args) => Atom.Atom<AsyncResult.Asy
|
|
|
16
16
|
*
|
|
17
17
|
* Use in the component a loader, a server component or `useWaterfall` gave
|
|
18
18
|
* the handle to. The source can be the one the verb started, or one derived
|
|
19
|
-
* from it whose atoms point at its atoms with `initialValueTarget
|
|
20
|
-
* an error boundary's
|
|
19
|
+
* from it whose atoms point at its atoms with `initialValueTarget`. To send
|
|
20
|
+
* some failures to an error boundary, pass the result to the boundary's hook,
|
|
21
|
+
* such as `useIssueBoundary(useAtomResult(issue, handle))`.
|
|
21
22
|
*
|
|
22
23
|
* **Details**
|
|
23
24
|
*
|
|
@@ -33,13 +34,14 @@ type Readable<S> = S extends ((...args: infer Args) => Atom.Atom<AsyncResult.Asy
|
|
|
33
34
|
* instead of started, so the browser doesn't request it a second time.
|
|
34
35
|
* - The atom is read through `hydrated`, so a hydrated result is kept.
|
|
35
36
|
* - Once the component mounts, the loader's lease ends and the component
|
|
36
|
-
* keeps the atom mounted.
|
|
37
|
+
* keeps the atom mounted. A loader that starts the atom again while it's
|
|
38
|
+
* mounted takes no lease, so the atom goes idle when the component unmounts.
|
|
37
39
|
* - A derived atom is read through the first serializable atom its
|
|
38
40
|
* `initialValueTarget` chain points at: that one is awaited, hydrated and
|
|
39
41
|
* released, so the derived atom doesn't request it again.
|
|
40
42
|
* - The settled result is returned, typed failures included. A defect is
|
|
41
|
-
* thrown to the error boundaries above. With no typed failures
|
|
42
|
-
* as
|
|
43
|
+
* thrown to the error boundaries above. With no typed failures, it's typed
|
|
44
|
+
* as a success.
|
|
43
45
|
* - While a failed atom refreshes, such as after a boundary's `reset`, the
|
|
44
46
|
* read suspends instead of returning the old failure again.
|
|
45
47
|
*
|
|
@@ -64,8 +66,8 @@ type Readable<S> = S extends ((...args: infer Args) => Atom.Atom<AsyncResult.Asy
|
|
|
64
66
|
* `Atom.transform`'s `initialValueTarget` option points at the end of the
|
|
65
67
|
* target's own chain, which for an AtomRpc query with `reactivityKeys` is an
|
|
66
68
|
* inner atom with no serialization key. A derived atom read here sets
|
|
67
|
-
* `initialValueTarget` to its source itself,
|
|
68
|
-
*
|
|
69
|
+
* `initialValueTarget` to its source itself, or it requests the source again
|
|
70
|
+
* after hydration.
|
|
69
71
|
*
|
|
70
72
|
* **Example**
|
|
71
73
|
*
|
|
@@ -86,4 +88,61 @@ type Readable<S> = S extends ((...args: infer Args) => Atom.Atom<AsyncResult.Asy
|
|
|
86
88
|
* @since 0.1.0
|
|
87
89
|
*/
|
|
88
90
|
export declare const useAtomResult: <S extends Source>(source: S, handle: NoInfer<Handle<Readable<S>>>) => [ErrorOf<S>] extends [never] ? AsyncResult.Success<SuccessOf<S>, never> : SettledResult<SuccessOf<S>, ErrorOf<S>>;
|
|
91
|
+
/**
|
|
92
|
+
* Reads a handle without React Suspense, through the source that made it,
|
|
93
|
+
* and returns the atom's current result as it is.
|
|
94
|
+
*
|
|
95
|
+
* **When to use**
|
|
96
|
+
*
|
|
97
|
+
* Use where a component renders every state of the read itself: its loading
|
|
98
|
+
* state, a failure that stays on the page while the atom refreshes, or a
|
|
99
|
+
* defect. Otherwise prefer `useAtomResult`, which suspends until the result
|
|
100
|
+
* settles and sends defects to the error boundaries above.
|
|
101
|
+
*
|
|
102
|
+
* **Details**
|
|
103
|
+
*
|
|
104
|
+
* - It reads the atom as `useAtomResult` does: through `hydrated`, through
|
|
105
|
+
* the serializable atom a derived source points at, and with the same
|
|
106
|
+
* development checks on the handle's key and on request waterfalls.
|
|
107
|
+
* - It returns `Initial` while the atom loads, and while a result the server
|
|
108
|
+
* was still loading streams in. It doesn't read the atom until the stream
|
|
109
|
+
* settles, so the browser doesn't request it a second time.
|
|
110
|
+
* - A failure is returned as it is, `waiting` while the atom refreshes, and
|
|
111
|
+
* so is a defect.
|
|
112
|
+
* - Once the component has subscribed to the atom, the loader's lease ends
|
|
113
|
+
* and the component keeps the atom mounted. A loader that starts the atom
|
|
114
|
+
* again while it's mounted takes no lease, so the atom goes idle when the
|
|
115
|
+
* component unmounts.
|
|
116
|
+
* - A handle `Loader.prefetchInBrowser` returned on the server reads as
|
|
117
|
+
* `Initial` there, without starting the atom; the browser's read starts
|
|
118
|
+
* it.
|
|
119
|
+
*
|
|
120
|
+
* **Gotchas**
|
|
121
|
+
*
|
|
122
|
+
* The server renders what the read returns, `Initial` for a result still
|
|
123
|
+
* loading, and the browser's first render has to match it: render the same
|
|
124
|
+
* loading state for every `Initial`.
|
|
125
|
+
*
|
|
126
|
+
* During server rendering, the registry must be a request registry (see
|
|
127
|
+
* `RequestRegistry.make`): in development, the hook throws without one.
|
|
128
|
+
*
|
|
129
|
+
* **Example**
|
|
130
|
+
*
|
|
131
|
+
* ```tsx
|
|
132
|
+
* import { AsyncResult } from "effect/reactivity"
|
|
133
|
+
* import { type Handle, useHandleValue } from "raf-effect-atom"
|
|
134
|
+
*
|
|
135
|
+
* function IssueTitle(props: { readonly issue: Handle<typeof issue> }) {
|
|
136
|
+
* const result = useHandleValue(issue, props.issue)
|
|
137
|
+
* return AsyncResult.isSuccess(result) ? <h1>{result.value.title}</h1> : <p>Loading…</p>
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* @see {@link useAtomResult} for a read that suspends until the result settles
|
|
142
|
+
*
|
|
143
|
+
* @stability unstable
|
|
144
|
+
* @category hooks
|
|
145
|
+
* @since 0.3.1
|
|
146
|
+
*/
|
|
147
|
+
export declare const useHandleValue: <S extends Source>(source: S, handle: NoInfer<Handle<Readable<S>>>) => AsyncResult.AsyncResult<SuccessOf<S>, ErrorOf<S>>;
|
|
89
148
|
export {};
|
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { stream } from "./internal/pending.mjs";
|
|
2
|
+
import { get, stream } from "./internal/pending.mjs";
|
|
3
3
|
import { hydrated } from "./Hydration.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { hold, keyOf } from "./internal/leases.mjs";
|
|
5
5
|
import { atomOf, sourceOf } from "./internal/handles.mjs";
|
|
6
6
|
import { isRequestRegistry } from "./RequestRegistry.mjs";
|
|
7
7
|
import { requireRequestRegistry } from "./internal/registry.mjs";
|
|
8
8
|
import { ModeContext, check } from "./internal/waterfalls.mjs";
|
|
9
|
+
import * as Atom from "effect/reactivity/Atom";
|
|
9
10
|
import * as Predicate from "effect/Predicate";
|
|
10
11
|
import * as Cause from "effect/Cause";
|
|
11
12
|
import * as Option from "effect/Option";
|
|
12
13
|
import * as AsyncResult from "effect/reactivity/AsyncResult";
|
|
13
|
-
import { RegistryContext, useAtomSuspense } from "@effect/atom-react";
|
|
14
|
+
import { RegistryContext, useAtomSuspense, useAtomValue } from "@effect/atom-react";
|
|
14
15
|
import * as React from "react";
|
|
15
|
-
// src/
|
|
16
|
+
// src/use-atom-result.ts
|
|
16
17
|
/**
|
|
17
|
-
* The read
|
|
18
|
+
* The read hooks for atoms started by loaders and streamed from the server.
|
|
18
19
|
*
|
|
19
20
|
* @stability unstable
|
|
20
21
|
* @since 0.1.0
|
|
21
22
|
*/
|
|
23
|
+
const targetsOf = (atom, handle, hook) => {
|
|
24
|
+
const target = sourceOf(atom);
|
|
25
|
+
const started = hydrated(target);
|
|
26
|
+
const read = target === atom ? hydrated(atom) : atom;
|
|
27
|
+
const key = keyOf(started);
|
|
28
|
+
if (process.env.NODE_ENV !== "production" && handle.key !== void 0 && Predicate.isString(key) && handle.key !== key) throw new Error(`raf-effect-atom: ${hook} read the handle of ${handle.key} through a source that makes ${key}. Read a handle through the source that made it.`);
|
|
29
|
+
return {
|
|
30
|
+
key,
|
|
31
|
+
read,
|
|
32
|
+
started
|
|
33
|
+
};
|
|
34
|
+
};
|
|
22
35
|
/**
|
|
23
36
|
* Reads a handle through React Suspense, through the source that made it: a
|
|
24
37
|
* result streamed from the server, a hydrated one, or one a loader started.
|
|
@@ -27,8 +40,9 @@ import * as React from "react";
|
|
|
27
40
|
*
|
|
28
41
|
* Use in the component a loader, a server component or `useWaterfall` gave
|
|
29
42
|
* the handle to. The source can be the one the verb started, or one derived
|
|
30
|
-
* from it whose atoms point at its atoms with `initialValueTarget
|
|
31
|
-
* an error boundary's
|
|
43
|
+
* from it whose atoms point at its atoms with `initialValueTarget`. To send
|
|
44
|
+
* some failures to an error boundary, pass the result to the boundary's hook,
|
|
45
|
+
* such as `useIssueBoundary(useAtomResult(issue, handle))`.
|
|
32
46
|
*
|
|
33
47
|
* **Details**
|
|
34
48
|
*
|
|
@@ -44,13 +58,14 @@ import * as React from "react";
|
|
|
44
58
|
* instead of started, so the browser doesn't request it a second time.
|
|
45
59
|
* - The atom is read through `hydrated`, so a hydrated result is kept.
|
|
46
60
|
* - Once the component mounts, the loader's lease ends and the component
|
|
47
|
-
* keeps the atom mounted.
|
|
61
|
+
* keeps the atom mounted. A loader that starts the atom again while it's
|
|
62
|
+
* mounted takes no lease, so the atom goes idle when the component unmounts.
|
|
48
63
|
* - A derived atom is read through the first serializable atom its
|
|
49
64
|
* `initialValueTarget` chain points at: that one is awaited, hydrated and
|
|
50
65
|
* released, so the derived atom doesn't request it again.
|
|
51
66
|
* - The settled result is returned, typed failures included. A defect is
|
|
52
|
-
* thrown to the error boundaries above. With no typed failures
|
|
53
|
-
* as
|
|
67
|
+
* thrown to the error boundaries above. With no typed failures, it's typed
|
|
68
|
+
* as a success.
|
|
54
69
|
* - While a failed atom refreshes, such as after a boundary's `reset`, the
|
|
55
70
|
* read suspends instead of returning the old failure again.
|
|
56
71
|
*
|
|
@@ -75,8 +90,8 @@ import * as React from "react";
|
|
|
75
90
|
* `Atom.transform`'s `initialValueTarget` option points at the end of the
|
|
76
91
|
* target's own chain, which for an AtomRpc query with `reactivityKeys` is an
|
|
77
92
|
* inner atom with no serialization key. A derived atom read here sets
|
|
78
|
-
* `initialValueTarget` to its source itself,
|
|
79
|
-
*
|
|
93
|
+
* `initialValueTarget` to its source itself, or it requests the source again
|
|
94
|
+
* after hydration.
|
|
80
95
|
*
|
|
81
96
|
* **Example**
|
|
82
97
|
*
|
|
@@ -101,12 +116,9 @@ const useAtomResult = (source, handle) => {
|
|
|
101
116
|
const atom = atomOf(source, handle.args);
|
|
102
117
|
requireRequestRegistry(registry, "useAtomResult");
|
|
103
118
|
if (handle.inBrowser === true && isRequestRegistry(registry)) throw new Error(`raf-effect-atom: ${String(atom)} starts in the browser (Loader.prefetchInBrowser), so the server renders the nearest Suspense boundary's fallback, and the browser renders the boundary.`);
|
|
104
|
-
const
|
|
105
|
-
const started =
|
|
106
|
-
const
|
|
107
|
-
const key = keyOf(started);
|
|
108
|
-
if (process.env.NODE_ENV !== "production" && handle.key !== void 0 && Predicate.isString(key) && handle.key !== key) throw new Error(`raf-effect-atom: useAtomResult read the handle of ${handle.key} through a source that makes ${key}. Read a handle through the source that made it.`);
|
|
109
|
-
const streamed = Predicate.isString(key) ? stream(registry, key) : void 0;
|
|
119
|
+
const targets = targetsOf(atom, handle, "useAtomResult");
|
|
120
|
+
const { read, started } = targets;
|
|
121
|
+
const streamed = Predicate.isString(targets.key) ? stream(registry, targets.key) : void 0;
|
|
110
122
|
if (streamed !== void 0) React.use(streamed);
|
|
111
123
|
if (process.env.NODE_ENV !== "production" && handle.inBrowser !== true) check(registry, started, React.use(ModeContext));
|
|
112
124
|
if (read !== started) registry.get(started);
|
|
@@ -115,10 +127,100 @@ const useAtomResult = (source, handle) => {
|
|
|
115
127
|
includeFailure: true,
|
|
116
128
|
suspendOnWaiting: AsyncResult.isFailure(current) && current.waiting
|
|
117
129
|
});
|
|
118
|
-
React.useEffect(() =>
|
|
119
|
-
release(registry, started);
|
|
120
|
-
}, [registry, started]);
|
|
130
|
+
React.useEffect(() => hold(registry, started), [registry, started]);
|
|
121
131
|
if (AsyncResult.isFailure(result) && Option.isNone(Cause.findErrorOption(result.cause))) throw Cause.squash(result.cause);
|
|
122
132
|
return result;
|
|
123
133
|
};
|
|
124
|
-
|
|
134
|
+
/** What a read shows while it can't read the atom yet. */
|
|
135
|
+
const loading = Atom.make(AsyncResult.initial(true));
|
|
136
|
+
/**
|
|
137
|
+
* Reads a handle without React Suspense, through the source that made it,
|
|
138
|
+
* and returns the atom's current result as it is.
|
|
139
|
+
*
|
|
140
|
+
* **When to use**
|
|
141
|
+
*
|
|
142
|
+
* Use where a component renders every state of the read itself: its loading
|
|
143
|
+
* state, a failure that stays on the page while the atom refreshes, or a
|
|
144
|
+
* defect. Otherwise prefer `useAtomResult`, which suspends until the result
|
|
145
|
+
* settles and sends defects to the error boundaries above.
|
|
146
|
+
*
|
|
147
|
+
* **Details**
|
|
148
|
+
*
|
|
149
|
+
* - It reads the atom as `useAtomResult` does: through `hydrated`, through
|
|
150
|
+
* the serializable atom a derived source points at, and with the same
|
|
151
|
+
* development checks on the handle's key and on request waterfalls.
|
|
152
|
+
* - It returns `Initial` while the atom loads, and while a result the server
|
|
153
|
+
* was still loading streams in. It doesn't read the atom until the stream
|
|
154
|
+
* settles, so the browser doesn't request it a second time.
|
|
155
|
+
* - A failure is returned as it is, `waiting` while the atom refreshes, and
|
|
156
|
+
* so is a defect.
|
|
157
|
+
* - Once the component has subscribed to the atom, the loader's lease ends
|
|
158
|
+
* and the component keeps the atom mounted. A loader that starts the atom
|
|
159
|
+
* again while it's mounted takes no lease, so the atom goes idle when the
|
|
160
|
+
* component unmounts.
|
|
161
|
+
* - A handle `Loader.prefetchInBrowser` returned on the server reads as
|
|
162
|
+
* `Initial` there, without starting the atom; the browser's read starts
|
|
163
|
+
* it.
|
|
164
|
+
*
|
|
165
|
+
* **Gotchas**
|
|
166
|
+
*
|
|
167
|
+
* The server renders what the read returns, `Initial` for a result still
|
|
168
|
+
* loading, and the browser's first render has to match it: render the same
|
|
169
|
+
* loading state for every `Initial`.
|
|
170
|
+
*
|
|
171
|
+
* During server rendering, the registry must be a request registry (see
|
|
172
|
+
* `RequestRegistry.make`): in development, the hook throws without one.
|
|
173
|
+
*
|
|
174
|
+
* **Example**
|
|
175
|
+
*
|
|
176
|
+
* ```tsx
|
|
177
|
+
* import { AsyncResult } from "effect/reactivity"
|
|
178
|
+
* import { type Handle, useHandleValue } from "raf-effect-atom"
|
|
179
|
+
*
|
|
180
|
+
* function IssueTitle(props: { readonly issue: Handle<typeof issue> }) {
|
|
181
|
+
* const result = useHandleValue(issue, props.issue)
|
|
182
|
+
* return AsyncResult.isSuccess(result) ? <h1>{result.value.title}</h1> : <p>Loading…</p>
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @see {@link useAtomResult} for a read that suspends until the result settles
|
|
187
|
+
*
|
|
188
|
+
* @stability unstable
|
|
189
|
+
* @category hooks
|
|
190
|
+
* @since 0.3.1
|
|
191
|
+
*/
|
|
192
|
+
const useHandleValue = (source, handle) => {
|
|
193
|
+
const registry = React.useContext(RegistryContext);
|
|
194
|
+
const atom = atomOf(source, handle.args);
|
|
195
|
+
requireRequestRegistry(registry, "useHandleValue");
|
|
196
|
+
const targets = targetsOf(atom, handle, "useHandleValue");
|
|
197
|
+
const { started } = targets;
|
|
198
|
+
const streamed = Predicate.isString(targets.key) ? get(registry, targets.key) : void 0;
|
|
199
|
+
const [, settled] = React.useReducer((count) => count + 1, 0);
|
|
200
|
+
React.useEffect(() => {
|
|
201
|
+
if (streamed === void 0) return;
|
|
202
|
+
let active = true;
|
|
203
|
+
const rerender = () => {
|
|
204
|
+
if (active) settled();
|
|
205
|
+
};
|
|
206
|
+
streamed.then(rerender, rerender);
|
|
207
|
+
return () => {
|
|
208
|
+
active = false;
|
|
209
|
+
};
|
|
210
|
+
}, [streamed]);
|
|
211
|
+
const waiting = streamed !== void 0 || handle.inBrowser === true && isRequestRegistry(registry);
|
|
212
|
+
if (!waiting) {
|
|
213
|
+
if (process.env.NODE_ENV !== "production" && handle.inBrowser !== true) check(registry, started, React.use(ModeContext));
|
|
214
|
+
if (targets.read !== started) registry.get(started);
|
|
215
|
+
}
|
|
216
|
+
const result = useAtomValue(waiting ? loading : targets.read);
|
|
217
|
+
React.useEffect(() => {
|
|
218
|
+
if (!waiting) return hold(registry, started);
|
|
219
|
+
}, [
|
|
220
|
+
registry,
|
|
221
|
+
started,
|
|
222
|
+
waiting
|
|
223
|
+
]);
|
|
224
|
+
return result;
|
|
225
|
+
};
|
|
226
|
+
export { useAtomResult, useHandleValue };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArgsOf, Handle, Source } from "./
|
|
1
|
+
import { ArgsOf, Handle, Source } from "./handle.mjs";
|
|
2
2
|
import { Mode } from "./internal/waterfalls.mjs";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
/**
|
|
@@ -72,9 +72,8 @@ 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
|
-
* - A derived source
|
|
76
|
-
*
|
|
77
|
-
* `Loader.prefetch` does.
|
|
75
|
+
* - A derived source starts the serializable atom its `initialValueTarget`
|
|
76
|
+
* chain points at, as `Loader.prefetch` does.
|
|
78
77
|
*
|
|
79
78
|
* **Example**
|
|
80
79
|
*
|
|
@@ -11,7 +11,7 @@ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
|
11
11
|
import { RegistryContext } from "@effect/atom-react";
|
|
12
12
|
import * as React from "react";
|
|
13
13
|
import { jsx } from "react/jsx-runtime";
|
|
14
|
-
// src/
|
|
14
|
+
// src/waterfalls.tsx
|
|
15
15
|
/**
|
|
16
16
|
* Request waterfalls: the escape hatch for atoms only a render can start,
|
|
17
17
|
* and the development check that finds the others.
|
|
@@ -76,9 +76,8 @@ 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
|
-
* - A derived source
|
|
80
|
-
*
|
|
81
|
-
* `Loader.prefetch` does.
|
|
79
|
+
* - A derived source starts the serializable atom its `initialValueTarget`
|
|
80
|
+
* chain points at, as `Loader.prefetch` does.
|
|
82
81
|
*
|
|
83
82
|
* **Example**
|
|
84
83
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "raf-effect-atom",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Render-as-you-fetch for Effect Atom: start atoms from route loaders and stream them into the browser, typed failures intact",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"sideEffects": false,
|
|
35
35
|
"exports": {
|
|
36
36
|
".": {
|
|
37
|
-
"react-server": "./dist/index
|
|
37
|
+
"react-server": "./dist/index-react-server.mjs",
|
|
38
38
|
"default": "./dist/index.mjs"
|
|
39
39
|
},
|
|
40
|
-
"./react-router": "./dist/
|
|
41
|
-
"./rsc": "./dist/
|
|
42
|
-
"./tanstack-router": "./dist/
|
|
40
|
+
"./react-router": "./dist/react-router.mjs",
|
|
41
|
+
"./rsc": "./dist/rsc.mjs",
|
|
42
|
+
"./tanstack-router": "./dist/tanstack-router.mjs"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@effect/atom-react": "^4.0.6",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@types/react-dom": "19.3.0",
|
|
62
62
|
"@vitest/coverage-v8": "5.0.5",
|
|
63
63
|
"effect": "4.0.6",
|
|
64
|
-
"effect-atom-boundary": "0.
|
|
64
|
+
"effect-atom-boundary": "0.3.0",
|
|
65
65
|
"happy-dom": "21.0.4",
|
|
66
66
|
"react": "19.3.1",
|
|
67
67
|
"react-dom": "19.3.1",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Hydration_exports } from "./Hydration.mjs";
|
|
2
|
-
import { RequestRegistry_exports } from "./RequestRegistry.mjs";
|
|
3
|
-
import { Loader_exports } from "./Loader.mjs";
|
|
4
|
-
import { useAtomResult } from "./Hooks.mjs";
|
|
5
|
-
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
6
|
-
import { WaterfallDetection, useWaterfall } from "./Waterfalls.mjs";
|
|
7
|
-
import { HydrationBoundary } from "./ReactHydration.react-server.mjs";
|
|
8
|
-
export { Hydration_exports as Hydration, HydrationBoundary, Loader_exports as Loader, RegistryProvider, RequestRegistry_exports as RequestRegistry, WaterfallDetection, useAtomResult, useWaterfall };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|