raf-effect-atom 0.2.6 → 0.3.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.
- package/CHANGELOG.md +14 -4
- package/README.md +2 -2
- package/dist/ReactHydration.d.mts +46 -13
- package/dist/ReactHydration.mjs +33 -10
- package/dist/ReactHydration.react-server.d.mts +25 -0
- package/dist/ReactHydration.react-server.mjs +41 -0
- package/dist/ReactRouter.d.mts +1 -3
- package/dist/ReactRouter.mjs +8 -8
- package/dist/RegistryProvider.d.mts +1 -1
- package/dist/RegistryProvider.mjs +3 -2
- package/dist/{Next.d.mts → Rsc.d.mts} +9 -36
- package/dist/{Next.mjs → Rsc.mjs} +8 -31
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +3 -2
- package/dist/index.react-server.d.mts +11 -0
- package/dist/index.react-server.mjs +8 -0
- package/dist/index.shared.d.mts +9 -0
- package/dist/internal/{next.mjs → rsc.mjs} +2 -8
- package/package.json +6 -3
- package/dist/NextClient.d.mts +0 -32
- package/dist/NextClient.mjs +0 -44
package/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [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
|
+
|
|
5
|
+
### ⚠ BREAKING CHANGES
|
|
6
|
+
|
|
7
|
+
* **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
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **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
|
+
|
|
3
13
|
## [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)
|
|
4
14
|
|
|
5
15
|
### Features
|
|
6
16
|
|
|
7
|
-
|
|
17
|
+
- **raf-effect-atom:** start browser-only reads with prefetchInBrowser ([65f783a](https://github.com/KATT/raf-effect-atom/commit/65f783a0014e44a8aa11ce5e8fa34ab863063403))
|
|
8
18
|
|
|
9
19
|
### Documentation
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
- **www:** keep a search box's text in the URL, and drop the debounce sample ([a3949bf](https://github.com/KATT/raf-effect-atom/commit/a3949bfca4b64e478132f983033b2776e50ba949))
|
|
12
22
|
|
|
13
23
|
### Tests
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
- **raf-effect-atom:** start a browser-only read from a client-only TanStack route ([69a8bd8](https://github.com/KATT/raf-effect-atom/commit/69a8bd887c34a7aeef51fdd20057ac30aa9e1fbc))
|
|
26
|
+
- **raf-effect-atom:** type a derived atom's handle through it and its wrappers ([a16b587](https://github.com/KATT/raf-effect-atom/commit/a16b587a59dc4827dd18ecb3a3d5bb8f6fdedf0b))
|
|
17
27
|
|
|
18
28
|
## [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)
|
|
19
29
|
|
package/README.md
CHANGED
|
@@ -52,8 +52,8 @@ function IssueTitle(props: { readonly issue: Handle<typeof issue> }) {
|
|
|
52
52
|
Each framework has a subpath that gives every server request its own registry and sends it to the browser:
|
|
53
53
|
|
|
54
54
|
- `raf-effect-atom/tanstack-router`, for TanStack Router and TanStack Start: `setupRouterAtoms({ router, registry })` in `getRouter`, with `Loader.make(registry)` on the router context.
|
|
55
|
-
- `raf-effect-atom/
|
|
56
|
-
- `raf-effect-atom/react-router`, for Framework Mode: `atomsMiddleware(atomsContext)` as the root middleware and `clientAtomsMiddleware(atomsContext)` as its client middleware, loaders that return `atoms.dehydrate()` with their handles and double as client loaders, and
|
|
55
|
+
- `raf-effect-atom/rsc`, for React Server Components such as the Next.js App Router: `prefetch`, `ensure` and `fetch` in server components, which pass the handles to client components as props, and `<HydrationBoundary registry={getRegistry()}>` around them. `HydrationBoundary` and `RegistryProvider` come from `raf-effect-atom` itself: server components get the build that takes the request's registry through the `react-server` export condition. `makeRequestAtoms({ seed })` makes the same functions over a registry seeded from the request, such as with its cookie.
|
|
56
|
+
- `raf-effect-atom/react-router`, for Framework Mode: `atomsMiddleware(atomsContext)` as the root middleware and `clientAtomsMiddleware(atomsContext)` as its client middleware, loaders that return `atoms.dehydrate()` with their handles and double as client loaders, and `<HydrationBoundary state={loaderData.atoms}>` in the route component.
|
|
57
57
|
|
|
58
58
|
In development, `useAtomResult` reports a read that starts an atom nothing started, a request waterfall. `<WaterfallDetection mode="throw">` at the root makes it throw to the nearest error boundary. `useWaterfall(source, ...args)` starts an atom whose input exists only in render, marks it as a known waterfall, and returns its handle.
|
|
59
59
|
|
|
@@ -1,33 +1,52 @@
|
|
|
1
1
|
import * as Hydration from "effect/reactivity/Hydration";
|
|
2
|
+
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
/**
|
|
4
|
-
* Props for `HydrationBoundary
|
|
5
|
+
* Props for `HydrationBoundary`: the request's `registry` in a server
|
|
6
|
+
* component, or the `state` it dehydrated anywhere else.
|
|
5
7
|
*
|
|
6
8
|
* @stability unstable
|
|
7
9
|
* @category models
|
|
8
10
|
* @since 0.1.0
|
|
9
11
|
*/
|
|
10
|
-
export
|
|
12
|
+
export type HydrationBoundaryProps = {
|
|
11
13
|
readonly children?: React.ReactNode | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The request registry of the server component render, such as
|
|
16
|
+
* `raf-effect-atom/rsc`'s `getRegistry()`. Server components only.
|
|
17
|
+
*/
|
|
18
|
+
readonly registry: AtomRegistry.AtomRegistry;
|
|
19
|
+
readonly state?: never;
|
|
20
|
+
} | {
|
|
21
|
+
readonly children?: React.ReactNode | undefined;
|
|
22
|
+
readonly registry?: never;
|
|
12
23
|
/** The state `Hydration.dehydrate` returned on the server. */
|
|
13
24
|
readonly state?: Iterable<Hydration.DehydratedAtom> | undefined;
|
|
14
|
-
}
|
|
25
|
+
};
|
|
15
26
|
/**
|
|
16
27
|
* Hydrates the state a server registry dehydrated, streamed results
|
|
17
28
|
* included.
|
|
18
29
|
*
|
|
19
30
|
* **When to use**
|
|
20
31
|
*
|
|
21
|
-
* Use where the server's state reaches the React tree
|
|
22
|
-
*
|
|
23
|
-
* that hydrates before rendering calls
|
|
32
|
+
* Use where the server's state reaches the React tree through rendering
|
|
33
|
+
* rather than a router: a server component's registry, or a React Router
|
|
34
|
+
* loader's data. A router that hydrates before rendering calls
|
|
35
|
+
* `Hydration.hydrate` instead.
|
|
24
36
|
*
|
|
25
37
|
* **Details**
|
|
26
38
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
39
|
+
* In a server component, pass the request's `registry`. Server components
|
|
40
|
+
* get their own build of `HydrationBoundary` through the package's
|
|
41
|
+
* `react-server` export condition: it waits for the registry's seed,
|
|
42
|
+
* dehydrates it, and sends the state with the server component's payload,
|
|
43
|
+
* so results still loading stream in as they settle.
|
|
44
|
+
*
|
|
45
|
+
* Anywhere else, pass the `state` a loader dehydrated. Settled values go to
|
|
46
|
+
* `@effect/atom-react`'s `HydrationBoundary`, which hydrates new atoms
|
|
47
|
+
* during render and existing ones after commit. Each streamed result is
|
|
48
|
+
* held until it arrives, so `useAtomResult` waits for it instead of
|
|
49
|
+
* requesting it again.
|
|
31
50
|
*
|
|
32
51
|
* During server rendering, when `state` is the array `dehydrate` returned,
|
|
33
52
|
* as React Router passes a loader's data to the server render, the children
|
|
@@ -37,15 +56,29 @@ export interface HydrationBoundaryProps {
|
|
|
37
56
|
*
|
|
38
57
|
* **Gotchas**
|
|
39
58
|
*
|
|
40
|
-
*
|
|
41
|
-
* a
|
|
42
|
-
*
|
|
59
|
+
* `registry` works only in server components: in a client component it
|
|
60
|
+
* throws, since a registry can't cross to the browser. In development, it
|
|
61
|
+
* throws during server rendering when the registry isn't a request
|
|
62
|
+
* registry, such as `@effect/atom-react`'s default one, which every request
|
|
63
|
+
* shares: one request's state would reach the others.
|
|
43
64
|
*
|
|
44
65
|
* **Example**
|
|
45
66
|
*
|
|
46
67
|
* ```tsx
|
|
47
68
|
* import { HydrationBoundary } from "raf-effect-atom"
|
|
69
|
+
* import { ensure, getRegistry } from "raf-effect-atom/rsc"
|
|
70
|
+
*
|
|
71
|
+
* // A server component
|
|
72
|
+
* export default async function IssueRoute(props: { params: Promise<{ id: string }> }) {
|
|
73
|
+
* const handle = await ensure(issue, Number((await props.params).id))
|
|
74
|
+
* return (
|
|
75
|
+
* <HydrationBoundary registry={getRegistry()}>
|
|
76
|
+
* <IssuePage issue={handle} />
|
|
77
|
+
* </HydrationBoundary>
|
|
78
|
+
* )
|
|
79
|
+
* }
|
|
48
80
|
*
|
|
81
|
+
* // A React Router route component
|
|
49
82
|
* <HydrationBoundary state={loaderData.atoms}>
|
|
50
83
|
* <IssuePage issue={loaderData.issue} />
|
|
51
84
|
* </HydrationBoundary>
|
package/dist/ReactHydration.mjs
CHANGED
|
@@ -19,16 +19,24 @@ import { jsx } from "react/jsx-runtime";
|
|
|
19
19
|
*
|
|
20
20
|
* **When to use**
|
|
21
21
|
*
|
|
22
|
-
* Use where the server's state reaches the React tree
|
|
23
|
-
*
|
|
24
|
-
* that hydrates before rendering calls
|
|
22
|
+
* Use where the server's state reaches the React tree through rendering
|
|
23
|
+
* rather than a router: a server component's registry, or a React Router
|
|
24
|
+
* loader's data. A router that hydrates before rendering calls
|
|
25
|
+
* `Hydration.hydrate` instead.
|
|
25
26
|
*
|
|
26
27
|
* **Details**
|
|
27
28
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* In a server component, pass the request's `registry`. Server components
|
|
30
|
+
* get their own build of `HydrationBoundary` through the package's
|
|
31
|
+
* `react-server` export condition: it waits for the registry's seed,
|
|
32
|
+
* dehydrates it, and sends the state with the server component's payload,
|
|
33
|
+
* so results still loading stream in as they settle.
|
|
34
|
+
*
|
|
35
|
+
* Anywhere else, pass the `state` a loader dehydrated. Settled values go to
|
|
36
|
+
* `@effect/atom-react`'s `HydrationBoundary`, which hydrates new atoms
|
|
37
|
+
* during render and existing ones after commit. Each streamed result is
|
|
38
|
+
* held until it arrives, so `useAtomResult` waits for it instead of
|
|
39
|
+
* requesting it again.
|
|
32
40
|
*
|
|
33
41
|
* During server rendering, when `state` is the array `dehydrate` returned,
|
|
34
42
|
* as React Router passes a loader's data to the server render, the children
|
|
@@ -38,15 +46,29 @@ import { jsx } from "react/jsx-runtime";
|
|
|
38
46
|
*
|
|
39
47
|
* **Gotchas**
|
|
40
48
|
*
|
|
41
|
-
*
|
|
42
|
-
* a
|
|
43
|
-
*
|
|
49
|
+
* `registry` works only in server components: in a client component it
|
|
50
|
+
* throws, since a registry can't cross to the browser. In development, it
|
|
51
|
+
* throws during server rendering when the registry isn't a request
|
|
52
|
+
* registry, such as `@effect/atom-react`'s default one, which every request
|
|
53
|
+
* shares: one request's state would reach the others.
|
|
44
54
|
*
|
|
45
55
|
* **Example**
|
|
46
56
|
*
|
|
47
57
|
* ```tsx
|
|
48
58
|
* import { HydrationBoundary } from "raf-effect-atom"
|
|
59
|
+
* import { ensure, getRegistry } from "raf-effect-atom/rsc"
|
|
60
|
+
*
|
|
61
|
+
* // A server component
|
|
62
|
+
* export default async function IssueRoute(props: { params: Promise<{ id: string }> }) {
|
|
63
|
+
* const handle = await ensure(issue, Number((await props.params).id))
|
|
64
|
+
* return (
|
|
65
|
+
* <HydrationBoundary registry={getRegistry()}>
|
|
66
|
+
* <IssuePage issue={handle} />
|
|
67
|
+
* </HydrationBoundary>
|
|
68
|
+
* )
|
|
69
|
+
* }
|
|
49
70
|
*
|
|
71
|
+
* // A React Router route component
|
|
50
72
|
* <HydrationBoundary state={loaderData.atoms}>
|
|
51
73
|
* <IssuePage issue={loaderData.issue} />
|
|
52
74
|
* </HydrationBoundary>
|
|
@@ -57,6 +79,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
57
79
|
* @since 0.1.0
|
|
58
80
|
*/
|
|
59
81
|
const HydrationBoundary$1 = (props) => {
|
|
82
|
+
if (props.registry !== void 0) throw new Error("raf-effect-atom: HydrationBoundary needs `state` here. `registry` works only in server components.");
|
|
60
83
|
const context = React.useContext(RegistryContext);
|
|
61
84
|
const state = props.state;
|
|
62
85
|
const source = isServer() ? sourceOf(state) : void 0;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Sends a server component's request registry to the client components
|
|
5
|
+
* under it.
|
|
6
|
+
*
|
|
7
|
+
* **Details**
|
|
8
|
+
*
|
|
9
|
+
* With `registry`, it waits for the registry's seed, dehydrates the atoms
|
|
10
|
+
* started so far, and renders the client `HydrationBoundary` with that
|
|
11
|
+
* state. React serializes the state's promises with the payload, so a result
|
|
12
|
+
* still loading streams in when it settles. With `state`, it passes that
|
|
13
|
+
* state on.
|
|
14
|
+
*
|
|
15
|
+
* **Gotchas**
|
|
16
|
+
*
|
|
17
|
+
* Call the verbs before rendering it: each boundary sends what its registry
|
|
18
|
+
* held when it rendered. It throws for a registry that isn't a request
|
|
19
|
+
* registry, which every request would share.
|
|
20
|
+
*
|
|
21
|
+
* @stability unstable
|
|
22
|
+
* @category components
|
|
23
|
+
* @since 0.3.0
|
|
24
|
+
*/
|
|
25
|
+
export declare const HydrationBoundary: (props: HydrationBoundaryProps) => Promise<React.ReactNode>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { dehydrate } from "./Hydration.mjs";
|
|
2
|
+
import { isRequestRegistry, settled } from "./RequestRegistry.mjs";
|
|
3
|
+
import { HydrationBoundary as HydrationBoundary$1 } from "./ReactHydration.mjs";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
// src/ReactHydration.react-server.tsx
|
|
6
|
+
/**
|
|
7
|
+
* Sends a server component's request registry to the client components
|
|
8
|
+
* under it.
|
|
9
|
+
*
|
|
10
|
+
* **Details**
|
|
11
|
+
*
|
|
12
|
+
* With `registry`, it waits for the registry's seed, dehydrates the atoms
|
|
13
|
+
* started so far, and renders the client `HydrationBoundary` with that
|
|
14
|
+
* state. React serializes the state's promises with the payload, so a result
|
|
15
|
+
* still loading streams in when it settles. With `state`, it passes that
|
|
16
|
+
* state on.
|
|
17
|
+
*
|
|
18
|
+
* **Gotchas**
|
|
19
|
+
*
|
|
20
|
+
* Call the verbs before rendering it: each boundary sends what its registry
|
|
21
|
+
* held when it rendered. It throws for a registry that isn't a request
|
|
22
|
+
* registry, which every request would share.
|
|
23
|
+
*
|
|
24
|
+
* @stability unstable
|
|
25
|
+
* @category components
|
|
26
|
+
* @since 0.3.0
|
|
27
|
+
*/
|
|
28
|
+
const HydrationBoundary = async (props) => {
|
|
29
|
+
const registry = props.registry;
|
|
30
|
+
if (registry === void 0) return /* @__PURE__ */ jsx(HydrationBoundary$1, {
|
|
31
|
+
state: props.state,
|
|
32
|
+
children: props.children
|
|
33
|
+
});
|
|
34
|
+
if (!isRequestRegistry(registry)) throw new Error("raf-effect-atom: HydrationBoundary got a registry that isn't a request registry, which would share results between requests. Pass raf-effect-atom/rsc's getRegistry(), or one makeRequestAtoms made.");
|
|
35
|
+
await settled(registry);
|
|
36
|
+
return /* @__PURE__ */ jsx(HydrationBoundary$1, {
|
|
37
|
+
state: dehydrate(registry),
|
|
38
|
+
children: props.children
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
export { HydrationBoundary };
|
package/dist/ReactRouter.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Loader } from "./Loader.mjs";
|
|
2
|
-
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
3
2
|
import * as EffectHydration from "effect/reactivity/Hydration";
|
|
4
3
|
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
5
4
|
/**
|
|
@@ -140,5 +139,4 @@ export declare const atomsMiddleware: (context: AtomsContext, options?: AtomsMid
|
|
|
140
139
|
* @category integrations
|
|
141
140
|
* @since 0.2.1
|
|
142
141
|
*/
|
|
143
|
-
export declare const clientAtomsMiddleware: (context: AtomsContext) => <Result>(args: MiddlewareArgs, next: () => Promise<Result>) => Promise<Result>;
|
|
144
|
-
export { RegistryProvider };
|
|
142
|
+
export declare const clientAtomsMiddleware: (context: AtomsContext) => <Result>(args: MiddlewareArgs, next: () => Promise<Result>) => Promise<Result>;
|
package/dist/ReactRouter.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { dehydrate } from "./Hydration.mjs";
|
|
|
2
2
|
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
|
-
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
6
5
|
import * as Predicate from "effect/Predicate";
|
|
7
6
|
// src/ReactRouter.ts
|
|
8
7
|
/**
|
|
@@ -11,11 +10,12 @@ import * as Predicate from "effect/Predicate";
|
|
|
11
10
|
* A root `middleware` gives each server request its own registry, under a
|
|
12
11
|
* router context the app creates. Loaders start atoms with its verbs and
|
|
13
12
|
* return its `dehydrate()` with their data; the route component hydrates it
|
|
14
|
-
* with `HydrationBoundary`, inside the root's `RegistryProvider
|
|
15
|
-
* `clientMiddleware` puts the browser's registry
|
|
16
|
-
* one function can be both the route's `loader`
|
|
17
|
-
* page, loaders run in the browser,
|
|
18
|
-
* already holds. Nothing is imported
|
|
13
|
+
* with `HydrationBoundary`, inside the root's `RegistryProvider`, both from
|
|
14
|
+
* `raf-effect-atom`. A root `clientMiddleware` puts the browser's registry
|
|
15
|
+
* under the same context, so one function can be both the route's `loader`
|
|
16
|
+
* and its `clientLoader`: after the first page, loaders run in the browser,
|
|
17
|
+
* where `ensure` finds what the registry already holds. Nothing is imported
|
|
18
|
+
* from `react-router`.
|
|
19
19
|
*
|
|
20
20
|
* **Example**
|
|
21
21
|
*
|
|
@@ -192,7 +192,7 @@ const disposeAfter = (body, registry) => {
|
|
|
192
192
|
*/
|
|
193
193
|
const clientAtomsMiddleware = (context) => (args, next) => {
|
|
194
194
|
const registry = current();
|
|
195
|
-
if (registry === void 0) throw new Error("clientAtomsMiddleware found no mounted RegistryProvider: render raf-effect-atom
|
|
195
|
+
if (registry === void 0) throw new Error("clientAtomsMiddleware found no mounted RegistryProvider: render raf-effect-atom's RegistryProvider around the app in the root layout.");
|
|
196
196
|
args.context.set(context, {
|
|
197
197
|
...make$1(registry, { signal: args.request.signal }),
|
|
198
198
|
dehydrate: () => [],
|
|
@@ -200,4 +200,4 @@ const clientAtomsMiddleware = (context) => (args, next) => {
|
|
|
200
200
|
});
|
|
201
201
|
return next();
|
|
202
202
|
};
|
|
203
|
-
export {
|
|
203
|
+
export { atomsMiddleware, clientAtomsMiddleware };
|
|
@@ -24,7 +24,7 @@ import * as React from "react";
|
|
|
24
24
|
* **Example**
|
|
25
25
|
*
|
|
26
26
|
* ```tsx
|
|
27
|
-
* import { RegistryProvider } from "raf-effect-atom
|
|
27
|
+
* import { RegistryProvider } from "raf-effect-atom"
|
|
28
28
|
*
|
|
29
29
|
* export default function RootLayout(props: { children: React.ReactNode }) {
|
|
30
30
|
* return (
|
|
@@ -5,7 +5,8 @@ import * as React from "react";
|
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
// src/RegistryProvider.tsx
|
|
7
7
|
/**
|
|
8
|
-
* The registry provider
|
|
8
|
+
* The registry provider for apps that render the server's state through
|
|
9
|
+
* `HydrationBoundary`, such as React Server Components and React Router.
|
|
9
10
|
*
|
|
10
11
|
* @stability unstable
|
|
11
12
|
* @since 0.1.0
|
|
@@ -35,7 +36,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
35
36
|
* **Example**
|
|
36
37
|
*
|
|
37
38
|
* ```tsx
|
|
38
|
-
* import { RegistryProvider } from "raf-effect-atom
|
|
39
|
+
* import { RegistryProvider } from "raf-effect-atom"
|
|
39
40
|
*
|
|
40
41
|
* export default function RootLayout(props: { children: React.ReactNode }) {
|
|
41
42
|
* return (
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { ArgsOf, Handle, LoadedHandle, Source } from "./Handle.mjs";
|
|
2
2
|
import { Loader } from "./Loader.mjs";
|
|
3
3
|
import { Options } from "./RequestRegistry.mjs";
|
|
4
|
-
import { HydrateAtoms } from "./NextClient.mjs";
|
|
5
|
-
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
6
|
-
import * as EffectHydration from "effect/reactivity/Hydration";
|
|
7
4
|
import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
8
5
|
/**
|
|
9
6
|
* The loader verbs over the request registry of the server render in
|
|
10
|
-
* progress, with its registry
|
|
7
|
+
* progress, with its registry.
|
|
11
8
|
*
|
|
12
9
|
* @stability unstable
|
|
13
10
|
* @category models
|
|
@@ -15,30 +12,28 @@ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
|
15
12
|
*/
|
|
16
13
|
export interface RequestAtoms extends Loader {
|
|
17
14
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* The request registry of the server render in progress, for
|
|
16
|
+
* `HydrationBoundary`'s `registry`.
|
|
20
17
|
*/
|
|
21
|
-
readonly dehydrate: () => Promise<Array<EffectHydration.DehydratedAtom>>;
|
|
22
|
-
/** The request registry of the server render in progress. */
|
|
23
18
|
readonly getRegistry: () => AtomRegistry.AtomRegistry;
|
|
24
19
|
}
|
|
25
20
|
/**
|
|
26
|
-
* Creates the verbs
|
|
27
|
-
*
|
|
21
|
+
* Creates the verbs and `getRegistry` over a request registry that `seed`
|
|
22
|
+
* prepares.
|
|
28
23
|
*
|
|
29
24
|
* **When to use**
|
|
30
25
|
*
|
|
31
26
|
* Use when the request's atoms need something from the request before they
|
|
32
27
|
* run, such as an RPC protocol that forwards the page request's cookie. Make
|
|
33
28
|
* them once, in a server-only module, and call the verbs on them instead of
|
|
34
|
-
* the ones `raf-effect-atom/
|
|
29
|
+
* the ones `raf-effect-atom/rsc` exports.
|
|
35
30
|
*
|
|
36
31
|
* **Details**
|
|
37
32
|
*
|
|
38
33
|
* The seed runs on each request's registry when a server component first
|
|
39
34
|
* uses it. It can be async, as `headers()` is: `ensure` and `fetch` wait
|
|
40
35
|
* for it, `prefetch` returns its handle at once and starts the atom once the
|
|
41
|
-
* seed resolves, and `
|
|
36
|
+
* seed resolves, and `HydrationBoundary` waits for both.
|
|
42
37
|
*
|
|
43
38
|
* **Example**
|
|
44
39
|
*
|
|
@@ -46,7 +41,7 @@ export interface RequestAtoms extends Loader {
|
|
|
46
41
|
* // src/atoms.server.ts
|
|
47
42
|
* import "server-only"
|
|
48
43
|
* import { headers } from "next/headers"
|
|
49
|
-
* import { makeRequestAtoms } from "raf-effect-atom/
|
|
44
|
+
* import { makeRequestAtoms } from "raf-effect-atom/rsc"
|
|
50
45
|
*
|
|
51
46
|
* export const atoms = makeRequestAtoms({
|
|
52
47
|
* seed: async (registry) => {
|
|
@@ -136,26 +131,4 @@ export declare const fetch: <S extends Source>(source: S, ...args: ArgsOf<S>) =>
|
|
|
136
131
|
* @category verbs
|
|
137
132
|
* @since 0.2.3
|
|
138
133
|
*/
|
|
139
|
-
export declare const run: Loader["run"];
|
|
140
|
-
/**
|
|
141
|
-
* `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
|
|
142
|
-
*
|
|
143
|
-
* **Gotchas**
|
|
144
|
-
*
|
|
145
|
-
* Includes the atoms started so far, so call it after the server component's
|
|
146
|
-
* verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
|
|
147
|
-
*
|
|
148
|
-
* **Example**
|
|
149
|
-
*
|
|
150
|
-
* ```tsx
|
|
151
|
-
* <HydrateAtoms state={await dehydrate()}>
|
|
152
|
-
* <Issue issue={handle} />
|
|
153
|
-
* </HydrateAtoms>
|
|
154
|
-
* ```
|
|
155
|
-
*
|
|
156
|
-
* @stability unstable
|
|
157
|
-
* @category dehydration
|
|
158
|
-
* @since 0.1.0
|
|
159
|
-
*/
|
|
160
|
-
export declare const dehydrate: () => Promise<Array<EffectHydration.DehydratedAtom>>;
|
|
161
|
-
export { HydrateAtoms, RegistryProvider };
|
|
134
|
+
export declare const run: Loader["run"];
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import { make } from "./internal/
|
|
2
|
-
|
|
3
|
-
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
4
|
-
// src/Next.ts
|
|
1
|
+
import { make } from "./internal/rsc.mjs";
|
|
2
|
+
// src/Rsc.ts
|
|
5
3
|
/**
|
|
6
|
-
* Creates the verbs
|
|
7
|
-
*
|
|
4
|
+
* Creates the verbs and `getRegistry` over a request registry that `seed`
|
|
5
|
+
* prepares.
|
|
8
6
|
*
|
|
9
7
|
* **When to use**
|
|
10
8
|
*
|
|
11
9
|
* Use when the request's atoms need something from the request before they
|
|
12
10
|
* run, such as an RPC protocol that forwards the page request's cookie. Make
|
|
13
11
|
* them once, in a server-only module, and call the verbs on them instead of
|
|
14
|
-
* the ones `raf-effect-atom/
|
|
12
|
+
* the ones `raf-effect-atom/rsc` exports.
|
|
15
13
|
*
|
|
16
14
|
* **Details**
|
|
17
15
|
*
|
|
18
16
|
* The seed runs on each request's registry when a server component first
|
|
19
17
|
* uses it. It can be async, as `headers()` is: `ensure` and `fetch` wait
|
|
20
18
|
* for it, `prefetch` returns its handle at once and starts the atom once the
|
|
21
|
-
* seed resolves, and `
|
|
19
|
+
* seed resolves, and `HydrationBoundary` waits for both.
|
|
22
20
|
*
|
|
23
21
|
* **Example**
|
|
24
22
|
*
|
|
@@ -26,7 +24,7 @@ import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
|
26
24
|
* // src/atoms.server.ts
|
|
27
25
|
* import "server-only"
|
|
28
26
|
* import { headers } from "next/headers"
|
|
29
|
-
* import { makeRequestAtoms } from "raf-effect-atom/
|
|
27
|
+
* import { makeRequestAtoms } from "raf-effect-atom/rsc"
|
|
30
28
|
*
|
|
31
29
|
* export const atoms = makeRequestAtoms({
|
|
32
30
|
* seed: async (registry) => {
|
|
@@ -118,25 +116,4 @@ const fetch = atoms.fetch;
|
|
|
118
116
|
* @since 0.2.3
|
|
119
117
|
*/
|
|
120
118
|
const run = atoms.run;
|
|
121
|
-
|
|
122
|
-
* `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
|
|
123
|
-
*
|
|
124
|
-
* **Gotchas**
|
|
125
|
-
*
|
|
126
|
-
* Includes the atoms started so far, so call it after the server component's
|
|
127
|
-
* verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
|
|
128
|
-
*
|
|
129
|
-
* **Example**
|
|
130
|
-
*
|
|
131
|
-
* ```tsx
|
|
132
|
-
* <HydrateAtoms state={await dehydrate()}>
|
|
133
|
-
* <Issue issue={handle} />
|
|
134
|
-
* </HydrateAtoms>
|
|
135
|
-
* ```
|
|
136
|
-
*
|
|
137
|
-
* @stability unstable
|
|
138
|
-
* @category dehydration
|
|
139
|
-
* @since 0.1.0
|
|
140
|
-
*/
|
|
141
|
-
const dehydrate = atoms.dehydrate;
|
|
142
|
-
export { HydrateAtoms, RegistryProvider, dehydrate, ensure, fetch, getRegistry, makeRequestAtoms, prefetch, prefetchInBrowser, run };
|
|
119
|
+
export { ensure, fetch, getRegistry, makeRequestAtoms, prefetch, prefetchInBrowser, run };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./Handle.mjs";
|
|
2
2
|
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
3
|
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
-
import { HydrationBoundary, HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
5
4
|
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
6
5
|
import { useAtomResult } from "./Hooks.mjs";
|
|
6
|
+
import { HydrationBoundary, HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
7
|
+
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
7
8
|
import { WaterfallDetection, WaterfallMode, useWaterfall } from "./Waterfalls.mjs";
|
|
8
|
-
|
|
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, useWaterfall };
|
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { Hydration_exports } from "./Hydration.mjs";
|
|
|
2
2
|
import { RequestRegistry_exports } from "./RequestRegistry.mjs";
|
|
3
3
|
import { Loader_exports } from "./Loader.mjs";
|
|
4
4
|
import { useAtomResult } from "./Hooks.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
6
6
|
import { WaterfallDetection, useWaterfall } from "./Waterfalls.mjs";
|
|
7
|
-
|
|
7
|
+
import { HydrationBoundary } from "./ReactHydration.mjs";
|
|
8
|
+
export { Hydration_exports as Hydration, HydrationBoundary, Loader_exports as Loader, RegistryProvider, RequestRegistry_exports as RequestRegistry, WaterfallDetection, useAtomResult, useWaterfall };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./Handle.mjs";
|
|
2
|
+
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
|
+
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
+
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
5
|
+
import { useAtomResult } from "./Hooks.mjs";
|
|
6
|
+
import { HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
7
|
+
import { RegistryProvider } from "./RegistryProvider.mjs";
|
|
8
|
+
import { WaterfallDetection, WaterfallMode, useWaterfall } from "./Waterfalls.mjs";
|
|
9
|
+
import "./index.shared.mjs";
|
|
10
|
+
import { HydrationBoundary } from "./ReactHydration.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, 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 } 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 };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ArgsOf, ErrorOf, Handle, HandleKey, LoadedHandle, Source, SuccessOf } from "./Handle.mjs";
|
|
2
|
+
import { Loader_d_exports } from "./Loader.mjs";
|
|
3
|
+
import { RequestRegistry_d_exports } from "./RequestRegistry.mjs";
|
|
4
|
+
import { Hydration_d_exports } from "./Hydration.mjs";
|
|
5
|
+
import { useAtomResult } from "./Hooks.mjs";
|
|
6
|
+
import { HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
7
|
+
import { RegistryProvider } from "./RegistryProvider.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, useWaterfall };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { make as make$1, settled } from "../RequestRegistry.mjs";
|
|
1
|
+
import { make as make$1 } from "../RequestRegistry.mjs";
|
|
3
2
|
import { make as make$2 } from "../Loader.mjs";
|
|
4
3
|
import * as React from "react";
|
|
5
|
-
// src/internal/
|
|
4
|
+
// src/internal/rsc.ts
|
|
6
5
|
const renderSignal = () => {
|
|
7
6
|
return React.cacheSignal();
|
|
8
7
|
};
|
|
@@ -14,11 +13,6 @@ const make = (options) => {
|
|
|
14
13
|
});
|
|
15
14
|
const getLoader = React.cache(() => make$2(getRegistry(), { signal: renderSignal() ?? void 0 }));
|
|
16
15
|
return {
|
|
17
|
-
dehydrate: async () => {
|
|
18
|
-
const registry = getRegistry();
|
|
19
|
-
await settled(registry);
|
|
20
|
-
return dehydrate(registry);
|
|
21
|
-
},
|
|
22
16
|
ensure: (source, ...args) => getLoader().ensure(source, ...args),
|
|
23
17
|
fetch: (source, ...args) => getLoader().fetch(source, ...args),
|
|
24
18
|
getRegistry,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "raf-effect-atom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -33,9 +33,12 @@
|
|
|
33
33
|
"type": "module",
|
|
34
34
|
"sideEffects": false,
|
|
35
35
|
"exports": {
|
|
36
|
-
".":
|
|
37
|
-
|
|
36
|
+
".": {
|
|
37
|
+
"react-server": "./dist/index.react-server.mjs",
|
|
38
|
+
"default": "./dist/index.mjs"
|
|
39
|
+
},
|
|
38
40
|
"./react-router": "./dist/ReactRouter.mjs",
|
|
41
|
+
"./rsc": "./dist/Rsc.mjs",
|
|
39
42
|
"./tanstack-router": "./dist/TanStackRouter.mjs"
|
|
40
43
|
},
|
|
41
44
|
"peerDependencies": {
|
package/dist/NextClient.d.mts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { HydrationBoundaryProps } from "./ReactHydration.mjs";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
/**
|
|
4
|
-
* Hydrates the state a server component dehydrated with `await 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 handle = await ensure(issue, Number((await props.params).id))
|
|
20
|
-
* return (
|
|
21
|
-
* <HydrateAtoms state={await dehydrate()}>
|
|
22
|
-
* <Issue issue={handle} />
|
|
23
|
-
* </HydrateAtoms>
|
|
24
|
-
* )
|
|
25
|
-
* }
|
|
26
|
-
* ```
|
|
27
|
-
*
|
|
28
|
-
* @stability unstable
|
|
29
|
-
* @category components
|
|
30
|
-
* @since 0.1.0
|
|
31
|
-
*/
|
|
32
|
-
export declare const HydrateAtoms: (props: HydrationBoundaryProps) => React.ReactNode;
|
package/dist/NextClient.mjs
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
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 `await 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 handle = await ensure(issue, Number((await props.params).id))
|
|
28
|
-
* return (
|
|
29
|
-
* <HydrateAtoms state={await dehydrate()}>
|
|
30
|
-
* <Issue issue={handle} />
|
|
31
|
-
* </HydrateAtoms>
|
|
32
|
-
* )
|
|
33
|
-
* }
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @stability unstable
|
|
37
|
-
* @category components
|
|
38
|
-
* @since 0.1.0
|
|
39
|
-
*/
|
|
40
|
-
const HydrateAtoms = (props) => /* @__PURE__ */ jsx(HydrationBoundary, {
|
|
41
|
-
state: props.state,
|
|
42
|
-
children: props.children
|
|
43
|
-
});
|
|
44
|
-
export { HydrateAtoms };
|