raf-effect-atom 0.0.0 → 0.2.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/dist/Loader.d.mts CHANGED
@@ -1,11 +1,11 @@
1
- import * as Atom from "effect/reactivity/Atom";
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";
5
5
  import * as AsyncResult from "effect/reactivity/AsyncResult";
6
6
  import * as AtomRegistry from "effect/reactivity/AtomRegistry";
7
7
  declare namespace Loader_d_exports {
8
- export { LeaseTTL, Loader, SettledResult, ensure, fetch, make, prefetch };
8
+ export { LeaseTTL, Loader, SettledResult, ensure, fetch, make, prefetch, result };
9
9
  }
10
10
  /**
11
11
  * A settled `AsyncResult`: what `ensure` and `fetch` return.
@@ -31,7 +31,7 @@ export type SettledResult<A, E> = AsyncResult.Failure<A, E> | AsyncResult.Succes
31
31
  */
32
32
  export declare const LeaseTTL: Context.Reference<Duration.Duration>;
33
33
  /**
34
- * Starts an atom without waiting for it.
34
+ * Starts a source's atom without waiting for it, and returns its handle.
35
35
  *
36
36
  * **When to use**
37
37
  *
@@ -41,7 +41,9 @@ export declare const LeaseTTL: Context.Reference<Duration.Duration>;
41
41
  * **Details**
42
42
  *
43
43
  * Starts the atom if it isn't in the registry, and leaves it alone if it is.
44
- * Takes a lease either way.
44
+ * Takes a lease either way. The component that reads the handle suspends
45
+ * until the result settles. On a request registry whose async seed is still
46
+ * running, it waits for the seed first.
45
47
  *
46
48
  * **Example**
47
49
  *
@@ -49,17 +51,17 @@ export declare const LeaseTTL: Context.Reference<Duration.Duration>;
49
51
  * import { Effect } from "effect"
50
52
  * import { Loader } from "raf-effect-atom"
51
53
  *
52
- * const program = Loader.prefetch(comments(1))
54
+ * const program = Loader.prefetch(commentPage, issueId, 0)
53
55
  * ```
54
56
  *
55
57
  * @stability unstable
56
58
  * @category verbs
57
59
  * @since 0.1.0
58
60
  */
59
- export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Effect.Effect<void, never, AtomRegistry.AtomRegistry>;
61
+ export declare const prefetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Effect.Effect<Handle<S>, never, AtomRegistry.AtomRegistry>;
60
62
  /**
61
- * Starts an atom and returns its settled result, waiting only while it has
62
- * none.
63
+ * Starts a source's atom, waits only while it has no result, and returns a
64
+ * handle whose reader renders without suspending.
63
65
  *
64
66
  * **When to use**
65
67
  *
@@ -68,10 +70,11 @@ export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A,
68
70
  *
69
71
  * **Details**
70
72
  *
71
- * An atom with a result returns it at once, without refetching. On a request
73
+ * An atom with a result returns at once, without refetching. On a request
72
74
  * registry, it also waits out a refresh in flight, so the server never
73
- * renders a result that's about to change. A typed failure is returned as
74
- * the result; a defect or an interruption fails the Effect.
75
+ * renders a result that's about to change. A typed failure settles it like
76
+ * a success: `result` returns it. A defect or an interruption fails the
77
+ * Effect.
75
78
  *
76
79
  * **Example**
77
80
  *
@@ -81,7 +84,8 @@ export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A,
81
84
  * import { Loader } from "raf-effect-atom"
82
85
  *
83
86
  * const program = Effect.gen(function* () {
84
- * const result = yield* Loader.ensure(issue(1))
87
+ * const handle = yield* Loader.ensure(issue, 1)
88
+ * const result = Loader.result(handle)
85
89
  * return AsyncResult.isSuccess(result) ? result.value.title : "missing"
86
90
  * })
87
91
  * ```
@@ -90,10 +94,11 @@ export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A,
90
94
  * @category verbs
91
95
  * @since 0.1.0
92
96
  */
93
- export declare const ensure: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Effect.Effect<SettledResult<A, E>, never, AtomRegistry.AtomRegistry>;
97
+ export declare const ensure: <S extends Source>(source: S, ...args: ArgsOf<S>) => Effect.Effect<LoadedHandle<S>, never, AtomRegistry.AtomRegistry>;
94
98
  /**
95
- * Starts an atom, or refreshes it if it has a result, and returns the new
96
- * settled result.
99
+ * Starts a source's atom, or refreshes it if it has a result, waits for the
100
+ * new result to settle, and returns a handle whose reader renders without
101
+ * suspending.
97
102
  *
98
103
  * **When to use**
99
104
  *
@@ -102,14 +107,45 @@ export declare const ensure: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E
102
107
  *
103
108
  * **Details**
104
109
  *
105
- * Waits until the result settles and isn't refreshing. A typed failure is
106
- * returned as the result; a defect or an interruption fails the Effect.
110
+ * Waits until the result settles and isn't refreshing. A typed failure
111
+ * settles it like a success: `result` returns it. A defect or an
112
+ * interruption fails the Effect.
107
113
  *
108
114
  * @stability unstable
109
115
  * @category verbs
110
116
  * @since 0.1.0
111
117
  */
112
- export declare const fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Effect.Effect<SettledResult<A, E>, never, AtomRegistry.AtomRegistry>;
118
+ export declare const fetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Effect.Effect<LoadedHandle<S>, never, AtomRegistry.AtomRegistry>;
119
+ /**
120
+ * Returns the settled result `ensure` or `fetch` waited for.
121
+ *
122
+ * **When to use**
123
+ *
124
+ * Use in the loader that ran the verb, to branch on the result: redirect on
125
+ * a tag, or build another atom's arguments from it. Components read the
126
+ * handle with `useAtomResult`, which follows the registry.
127
+ *
128
+ * **Gotchas**
129
+ *
130
+ * Only the handle object the verb returned has it: a handle that crossed
131
+ * the network, as loader data or a server component's prop, is a copy, and
132
+ * this throws for it.
133
+ *
134
+ * **Example**
135
+ *
136
+ * ```ts
137
+ * import { AsyncResult } from "effect/reactivity"
138
+ * import { Loader } from "raf-effect-atom"
139
+ *
140
+ * const handle = await atoms.ensure(issue, id)
141
+ * const error = AsyncResult.error(Loader.result(handle))
142
+ * ```
143
+ *
144
+ * @stability unstable
145
+ * @category getters
146
+ * @since 0.1.0
147
+ */
148
+ export declare const result: <S extends Source>(handle: LoadedHandle<S>) => SettledResult<SuccessOf<S>, ErrorOf<S>>;
113
149
  /**
114
150
  * The loader verbs as Promises over one registry, as the framework
115
151
  * integrations put them on the router context.
@@ -120,11 +156,15 @@ export declare const fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>
120
156
  */
121
157
  export interface Loader {
122
158
  /** {@link ensure}, as a Promise that rejects only on a defect. */
123
- readonly ensure: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
159
+ readonly ensure: <S extends Source>(source: S, ...args: ArgsOf<S>) => Promise<LoadedHandle<S>>;
124
160
  /** {@link fetch}, as a Promise that rejects only on a defect. */
125
- readonly fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
126
- /** {@link prefetch}, run at once. */
127
- readonly prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => void;
161
+ readonly fetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Promise<LoadedHandle<S>>;
162
+ /**
163
+ * {@link prefetch}, run at once. On a request registry whose async seed is
164
+ * still running, it returns the handle at once and starts the atom once
165
+ * the seed resolves.
166
+ */
167
+ readonly prefetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Handle<S>;
128
168
  }
129
169
  /**
130
170
  * Creates the Promise verbs over one registry.
@@ -143,8 +183,8 @@ export interface Loader {
143
183
  * import { Loader, RequestRegistry } from "raf-effect-atom"
144
184
  *
145
185
  * const loader = Loader.make(RequestRegistry.make())
146
- * loader.prefetch(comments(1))
147
- * const result = await loader.ensure(issue(1))
186
+ * const comments = loader.prefetch(commentPage, 1, 0)
187
+ * const issueHandle = await loader.ensure(issue, 1)
148
188
  * ```
149
189
  *
150
190
  * @stability unstable
package/dist/Loader.mjs CHANGED
@@ -2,6 +2,8 @@ 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";
6
+ import { afterSeed, pending } from "./internal/seeds.mjs";
5
7
  import { isRequestRegistry } from "./RequestRegistry.mjs";
6
8
  import * as Atom from "effect/reactivity/Atom";
7
9
  import * as Predicate from "effect/Predicate";
@@ -17,9 +19,11 @@ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
17
19
  * Starts atoms from route loaders, before anything renders, so nothing
18
20
  * waterfalls.
19
21
  *
20
- * Each verb starts an `AsyncResult` atom in the registry and takes a lease
21
- * on it, so the registry's idle TTL can't evict it before the route renders
22
- * and `useAtomResult` takes it over:
22
+ * Each verb takes a source, an atom family or an `AsyncResult` atom, with its
23
+ * arguments. It starts the atom in the registry, takes a lease on it, so the
24
+ * registry's idle TTL can't evict it before the route renders and
25
+ * `useAtomResult` takes it over, and returns its handle for the component
26
+ * that reads it:
23
27
  *
24
28
  * | Verb | Starts the atom | Waits | Has a value already |
25
29
  * | ---------- | ------------------------------- | ----------------------------- | --------------------- |
@@ -27,9 +31,10 @@ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
27
31
  * | `ensure` | if it isn't in the registry | only while it's `Initial` | returns it at once |
28
32
  * | `fetch` | if it isn't, or refreshes it | until the new result settles | refreshes, then waits |
29
33
  *
30
- * Typed failures don't reject: `ensure` and `fetch` return the settled
31
- * `AsyncResult`, so a loader can redirect on a tag and otherwise let a
32
- * boundary render the failure. Only defects and interruptions reject.
34
+ * Typed failures don't reject: `ensure` and `fetch` settle on them, and
35
+ * `result` returns the settled `AsyncResult`, so a loader can redirect on a
36
+ * tag and otherwise let a boundary render the failure. Only defects and
37
+ * interruptions reject.
33
38
  *
34
39
  * The verbs are Effects that need the `AtomRegistry`; `make` gives the same
35
40
  * verbs as Promises over one registry, for loaders that are async functions.
@@ -42,7 +47,8 @@ var Loader_exports = /* @__PURE__ */ __exportAll({
42
47
  ensure: () => ensure,
43
48
  fetch: () => fetch,
44
49
  make: () => make,
45
- prefetch: () => prefetch
50
+ prefetch: () => prefetch,
51
+ result: () => result
46
52
  });
47
53
  /**
48
54
  * How long a loader's lease keeps an atom mounted when no component takes it
@@ -61,6 +67,8 @@ var Loader_exports = /* @__PURE__ */ __exportAll({
61
67
  const LeaseTTL = Context.Reference("raf-effect-atom/Loader/LeaseTTL", { defaultValue: () => Duration.seconds(30) });
62
68
  const start = Effect.fnUntraced(function* (atom) {
63
69
  const registry = yield* AtomRegistry.AtomRegistry;
70
+ const seed = pending(registry);
71
+ if (seed !== void 0) yield* Effect.promise(() => seed);
64
72
  const request = isRequestRegistry(registry);
65
73
  if (request && !Atom.isSerializable(atom) && (yield* isDevelopment)) return yield* Effect.die(/* @__PURE__ */ new Error(`raf-effect-atom: a loader started ${String(atom)}, which isn't serializable, so the browser would request it again. Give it a serialization key, such as AtomRpc's serializationKey option.`));
66
74
  const ttl = request ? void 0 : Duration.toMillis(yield* LeaseTTL);
@@ -98,7 +106,7 @@ const rejectDefects = (result) => {
98
106
  return Effect.succeed(result);
99
107
  };
100
108
  /**
101
- * Starts an atom without waiting for it.
109
+ * Starts a source's atom without waiting for it, and returns its handle.
102
110
  *
103
111
  * **When to use**
104
112
  *
@@ -108,7 +116,9 @@ const rejectDefects = (result) => {
108
116
  * **Details**
109
117
  *
110
118
  * Starts the atom if it isn't in the registry, and leaves it alone if it is.
111
- * Takes a lease either way.
119
+ * Takes a lease either way. The component that reads the handle suspends
120
+ * until the result settles. On a request registry whose async seed is still
121
+ * running, it waits for the seed first.
112
122
  *
113
123
  * **Example**
114
124
  *
@@ -116,19 +126,26 @@ const rejectDefects = (result) => {
116
126
  * import { Effect } from "effect"
117
127
  * import { Loader } from "raf-effect-atom"
118
128
  *
119
- * const program = Loader.prefetch(comments(1))
129
+ * const program = Loader.prefetch(commentPage, issueId, 0)
120
130
  * ```
121
131
  *
122
132
  * @stability unstable
123
133
  * @category verbs
124
134
  * @since 0.1.0
125
135
  */
126
- const prefetch = Effect.fnUntraced(function* (atom) {
136
+ const prefetch = (source, ...args) => Effect.gen(function* () {
137
+ const atom = atomOf(source, args);
127
138
  yield* start(atom);
139
+ return make$1(args, atom);
128
140
  });
141
+ const loaded = (args, atom, result) => {
142
+ const handle = loaded$1(args, atom);
143
+ results.set(handle, result);
144
+ return handle;
145
+ };
129
146
  /**
130
- * Starts an atom and returns its settled result, waiting only while it has
131
- * none.
147
+ * Starts a source's atom, waits only while it has no result, and returns a
148
+ * handle whose reader renders without suspending.
132
149
  *
133
150
  * **When to use**
134
151
  *
@@ -137,10 +154,11 @@ const prefetch = Effect.fnUntraced(function* (atom) {
137
154
  *
138
155
  * **Details**
139
156
  *
140
- * An atom with a result returns it at once, without refetching. On a request
157
+ * An atom with a result returns at once, without refetching. On a request
141
158
  * registry, it also waits out a refresh in flight, so the server never
142
- * renders a result that's about to change. A typed failure is returned as
143
- * the result; a defect or an interruption fails the Effect.
159
+ * renders a result that's about to change. A typed failure settles it like
160
+ * a success: `result` returns it. A defect or an interruption fails the
161
+ * Effect.
144
162
  *
145
163
  * **Example**
146
164
  *
@@ -150,7 +168,8 @@ const prefetch = Effect.fnUntraced(function* (atom) {
150
168
  * import { Loader } from "raf-effect-atom"
151
169
  *
152
170
  * const program = Effect.gen(function* () {
153
- * const result = yield* Loader.ensure(issue(1))
171
+ * const handle = yield* Loader.ensure(issue, 1)
172
+ * const result = Loader.result(handle)
154
173
  * return AsyncResult.isSuccess(result) ? result.value.title : "missing"
155
174
  * })
156
175
  * ```
@@ -159,13 +178,16 @@ const prefetch = Effect.fnUntraced(function* (atom) {
159
178
  * @category verbs
160
179
  * @since 0.1.0
161
180
  */
162
- const ensure = Effect.fnUntraced(function* (atom) {
181
+ const ensure = (source, ...args) => Effect.gen(function* () {
182
+ const atom = atomOf(source, args);
163
183
  const started = yield* start(atom);
164
- return yield* settled(started.registry, started.target, started.request ? isSettled : AsyncResult.isNotInitial);
184
+ const result = yield* settled(started.registry, started.target, started.request ? isSettled : AsyncResult.isNotInitial);
185
+ return loaded(args, atom, result);
165
186
  });
166
187
  /**
167
- * Starts an atom, or refreshes it if it has a result, and returns the new
168
- * settled result.
188
+ * Starts a source's atom, or refreshes it if it has a result, waits for the
189
+ * new result to settle, and returns a handle whose reader renders without
190
+ * suspending.
169
191
  *
170
192
  * **When to use**
171
193
  *
@@ -174,22 +196,60 @@ const ensure = Effect.fnUntraced(function* (atom) {
174
196
  *
175
197
  * **Details**
176
198
  *
177
- * Waits until the result settles and isn't refreshing. A typed failure is
178
- * returned as the result; a defect or an interruption fails the Effect.
199
+ * Waits until the result settles and isn't refreshing. A typed failure
200
+ * settles it like a success: `result` returns it. A defect or an
201
+ * interruption fails the Effect.
179
202
  *
180
203
  * @stability unstable
181
204
  * @category verbs
182
205
  * @since 0.1.0
183
206
  */
184
- const fetch = Effect.fnUntraced(function* (atom) {
207
+ const fetch = (source, ...args) => Effect.gen(function* () {
208
+ const atom = atomOf(source, args);
185
209
  const started = yield* start(atom);
186
210
  const { registry, target } = started;
187
211
  if (started.existed && isSettled(registry.get(target))) {
188
212
  const node = registry.getNodes().get(keyOf(target));
189
213
  registry.refresh(node?.atom ?? target);
190
214
  }
191
- return yield* settled(registry, target, isSettled);
215
+ const result = yield* settled(registry, target, isSettled);
216
+ return loaded(args, atom, result);
192
217
  });
218
+ const results = /* @__PURE__ */ new WeakMap();
219
+ /**
220
+ * Returns the settled result `ensure` or `fetch` waited for.
221
+ *
222
+ * **When to use**
223
+ *
224
+ * Use in the loader that ran the verb, to branch on the result: redirect on
225
+ * a tag, or build another atom's arguments from it. Components read the
226
+ * handle with `useAtomResult`, which follows the registry.
227
+ *
228
+ * **Gotchas**
229
+ *
230
+ * Only the handle object the verb returned has it: a handle that crossed
231
+ * the network, as loader data or a server component's prop, is a copy, and
232
+ * this throws for it.
233
+ *
234
+ * **Example**
235
+ *
236
+ * ```ts
237
+ * import { AsyncResult } from "effect/reactivity"
238
+ * import { Loader } from "raf-effect-atom"
239
+ *
240
+ * const handle = await atoms.ensure(issue, id)
241
+ * const error = AsyncResult.error(Loader.result(handle))
242
+ * ```
243
+ *
244
+ * @stability unstable
245
+ * @category getters
246
+ * @since 0.1.0
247
+ */
248
+ const result = (handle) => {
249
+ const settledResult = results.get(handle);
250
+ if (settledResult === void 0) throw new Error("raf-effect-atom: Loader.result got a handle that no ensure or fetch returned here. Only the code that ran the verb has its result: a handle that crossed the network is a copy. Read it with useAtomResult instead.");
251
+ return settledResult;
252
+ };
193
253
  /**
194
254
  * Creates the Promise verbs over one registry.
195
255
  *
@@ -207,8 +267,8 @@ const fetch = Effect.fnUntraced(function* (atom) {
207
267
  * import { Loader, RequestRegistry } from "raf-effect-atom"
208
268
  *
209
269
  * const loader = Loader.make(RequestRegistry.make())
210
- * loader.prefetch(comments(1))
211
- * const result = await loader.ensure(issue(1))
270
+ * const comments = loader.prefetch(commentPage, 1, 0)
271
+ * const issueHandle = await loader.ensure(issue, 1)
212
272
  * ```
213
273
  *
214
274
  * @stability unstable
@@ -222,11 +282,15 @@ const make = (registry, options) => {
222
282
  return leaseTTL === void 0 ? provided : Effect.provideService(provided, LeaseTTL, leaseTTL);
223
283
  };
224
284
  return {
225
- ensure: (atom) => Effect.runPromise(provide(ensure(atom))),
226
- fetch: (atom) => Effect.runPromise(provide(fetch(atom))),
227
- prefetch: (atom) => {
228
- Effect.runSync(provide(prefetch(atom)));
285
+ ensure: (source, ...args) => Effect.runPromise(provide(ensure(source, ...args))),
286
+ fetch: (source, ...args) => Effect.runPromise(provide(fetch(source, ...args))),
287
+ prefetch: (source, ...args) => {
288
+ const atom = atomOf(source, args);
289
+ afterSeed(registry, () => {
290
+ Effect.runSync(provide(start(atom)));
291
+ });
292
+ return make$1(args, atom);
229
293
  }
230
294
  };
231
295
  };
232
- export { LeaseTTL, Loader_exports, ensure, fetch, make, prefetch };
296
+ export { LeaseTTL, Loader_exports, ensure, fetch, make, prefetch, result };
package/dist/Next.d.mts CHANGED
@@ -1,10 +1,65 @@
1
- import { SettledResult } from "./Loader.mjs";
1
+ import { ArgsOf, Handle, LoadedHandle, Source } from "./Handle.mjs";
2
+ import { Loader } from "./Loader.mjs";
3
+ import { Options } from "./RequestRegistry.mjs";
2
4
  import { HydrateAtoms } from "./NextClient.mjs";
3
5
  import { RegistryProvider } from "./RegistryProvider.mjs";
4
- import * as Atom from "effect/reactivity/Atom";
5
6
  import * as EffectHydration from "effect/reactivity/Hydration";
6
- import * as AsyncResult from "effect/reactivity/AsyncResult";
7
7
  import * as AtomRegistry from "effect/reactivity/AtomRegistry";
8
+ /**
9
+ * The loader verbs over the request registry of the server render in
10
+ * progress, with its registry and `dehydrate`.
11
+ *
12
+ * @stability unstable
13
+ * @category models
14
+ * @since 0.2.0
15
+ */
16
+ export interface RequestAtoms extends Loader {
17
+ /**
18
+ * `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`,
19
+ * once its seed has settled.
20
+ */
21
+ readonly dehydrate: () => Promise<Array<EffectHydration.DehydratedAtom>>;
22
+ /** The request registry of the server render in progress. */
23
+ readonly getRegistry: () => AtomRegistry.AtomRegistry;
24
+ }
25
+ /**
26
+ * Creates the verbs, `getRegistry` and `dehydrate` over a request registry
27
+ * that `seed` prepares.
28
+ *
29
+ * **When to use**
30
+ *
31
+ * Use when the request's atoms need something from the request before they
32
+ * run, such as an RPC protocol that forwards the page request's cookie. Make
33
+ * them once, in a server-only module, and call the verbs on them instead of
34
+ * the ones `raf-effect-atom/next` exports.
35
+ *
36
+ * **Details**
37
+ *
38
+ * The seed runs on each request's registry when a server component first
39
+ * uses it. It can be async, as `headers()` is: `ensure` and `fetch` wait
40
+ * for it, `prefetch` returns its handle at once and starts the atom once the
41
+ * seed resolves, and `dehydrate` waits for both.
42
+ *
43
+ * **Example**
44
+ *
45
+ * ```ts
46
+ * // src/atoms.server.ts
47
+ * import "server-only"
48
+ * import { headers } from "next/headers"
49
+ * import { makeRequestAtoms } from "raf-effect-atom/next"
50
+ *
51
+ * export const atoms = makeRequestAtoms({
52
+ * seed: async (registry) => {
53
+ * registry.set(requestCookie, (await headers()).get("cookie") ?? undefined)
54
+ * }
55
+ * })
56
+ * ```
57
+ *
58
+ * @stability unstable
59
+ * @category constructors
60
+ * @since 0.2.0
61
+ */
62
+ export declare const makeRequestAtoms: (options?: Options) => RequestAtoms;
8
63
  /**
9
64
  * Returns the request registry of the server render in progress.
10
65
  *
@@ -25,31 +80,32 @@ import * as AtomRegistry from "effect/reactivity/AtomRegistry";
25
80
  */
26
81
  export declare const getRegistry: () => AtomRegistry.AtomRegistry;
27
82
  /**
28
- * `Loader.prefetch` on the request's registry: starts an atom, to stream it.
83
+ * `Loader.prefetch` on the request's registry: starts a source's atom, to
84
+ * stream it, and returns its handle.
29
85
  *
30
86
  * @stability unstable
31
87
  * @category verbs
32
88
  * @since 0.1.0
33
89
  */
34
- export declare const prefetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => void;
90
+ export declare const prefetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Handle<S>;
35
91
  /**
36
- * `Loader.ensure` on the request's registry: starts an atom and returns its
37
- * settled result.
92
+ * `Loader.ensure` on the request's registry: starts a source's atom, waits
93
+ * for its result, and returns its handle.
38
94
  *
39
95
  * @stability unstable
40
96
  * @category verbs
41
97
  * @since 0.1.0
42
98
  */
43
- export declare const ensure: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
99
+ export declare const ensure: <S extends Source>(source: S, ...args: ArgsOf<S>) => Promise<LoadedHandle<S>>;
44
100
  /**
45
- * `Loader.fetch` on the request's registry: starts or refreshes an atom and
46
- * returns the new settled result.
101
+ * `Loader.fetch` on the request's registry: starts or refreshes a source's
102
+ * atom, waits for the new result, and returns its handle.
47
103
  *
48
104
  * @stability unstable
49
105
  * @category verbs
50
106
  * @since 0.1.0
51
107
  */
52
- export declare const fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>>) => Promise<SettledResult<A, E>>;
108
+ export declare const fetch: <S extends Source>(source: S, ...args: ArgsOf<S>) => Promise<LoadedHandle<S>>;
53
109
  /**
54
110
  * `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
55
111
  *
@@ -58,9 +114,17 @@ export declare const fetch: <A, E>(atom: Atom.Atom<AsyncResult.AsyncResult<A, E>
58
114
  * Includes the atoms started so far, so call it after the server component's
59
115
  * verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
60
116
  *
117
+ * **Example**
118
+ *
119
+ * ```tsx
120
+ * <HydrateAtoms state={await dehydrate()}>
121
+ * <Issue issue={handle} />
122
+ * </HydrateAtoms>
123
+ * ```
124
+ *
61
125
  * @stability unstable
62
126
  * @category dehydration
63
127
  * @since 0.1.0
64
128
  */
65
- export declare const dehydrate: () => Array<EffectHydration.DehydratedAtom>;
129
+ export declare const dehydrate: () => Promise<Array<EffectHydration.DehydratedAtom>>;
66
130
  export { HydrateAtoms, RegistryProvider };
package/dist/Next.mjs CHANGED
@@ -1,8 +1,47 @@
1
- import { dehydrate as dehydrate$1, ensure as ensure$1, fetch as fetch$1, getRegistry as getRegistry$1, prefetch as prefetch$1 } from "./internal/next.mjs";
1
+ import { make } from "./internal/next.mjs";
2
2
  import { HydrateAtoms } from "./NextClient.mjs";
3
3
  import { RegistryProvider } from "./RegistryProvider.mjs";
4
4
  // src/Next.ts
5
5
  /**
6
+ * Creates the verbs, `getRegistry` and `dehydrate` over a request registry
7
+ * that `seed` prepares.
8
+ *
9
+ * **When to use**
10
+ *
11
+ * Use when the request's atoms need something from the request before they
12
+ * run, such as an RPC protocol that forwards the page request's cookie. Make
13
+ * them once, in a server-only module, and call the verbs on them instead of
14
+ * the ones `raf-effect-atom/next` exports.
15
+ *
16
+ * **Details**
17
+ *
18
+ * The seed runs on each request's registry when a server component first
19
+ * uses it. It can be async, as `headers()` is: `ensure` and `fetch` wait
20
+ * for it, `prefetch` returns its handle at once and starts the atom once the
21
+ * seed resolves, and `dehydrate` waits for both.
22
+ *
23
+ * **Example**
24
+ *
25
+ * ```ts
26
+ * // src/atoms.server.ts
27
+ * import "server-only"
28
+ * import { headers } from "next/headers"
29
+ * import { makeRequestAtoms } from "raf-effect-atom/next"
30
+ *
31
+ * export const atoms = makeRequestAtoms({
32
+ * seed: async (registry) => {
33
+ * registry.set(requestCookie, (await headers()).get("cookie") ?? undefined)
34
+ * }
35
+ * })
36
+ * ```
37
+ *
38
+ * @stability unstable
39
+ * @category constructors
40
+ * @since 0.2.0
41
+ */
42
+ const makeRequestAtoms = make;
43
+ const atoms = make();
44
+ /**
6
45
  * Returns the request registry of the server render in progress.
7
46
  *
8
47
  * **Details**
@@ -20,33 +59,34 @@ import { RegistryProvider } from "./RegistryProvider.mjs";
20
59
  * @category registry
21
60
  * @since 0.1.0
22
61
  */
23
- const getRegistry = getRegistry$1;
62
+ const getRegistry = atoms.getRegistry;
24
63
  /**
25
- * `Loader.prefetch` on the request's registry: starts an atom, to stream it.
64
+ * `Loader.prefetch` on the request's registry: starts a source's atom, to
65
+ * stream it, and returns its handle.
26
66
  *
27
67
  * @stability unstable
28
68
  * @category verbs
29
69
  * @since 0.1.0
30
70
  */
31
- const prefetch = prefetch$1;
71
+ const prefetch = atoms.prefetch;
32
72
  /**
33
- * `Loader.ensure` on the request's registry: starts an atom and returns its
34
- * settled result.
73
+ * `Loader.ensure` on the request's registry: starts a source's atom, waits
74
+ * for its result, and returns its handle.
35
75
  *
36
76
  * @stability unstable
37
77
  * @category verbs
38
78
  * @since 0.1.0
39
79
  */
40
- const ensure = ensure$1;
80
+ const ensure = atoms.ensure;
41
81
  /**
42
- * `Loader.fetch` on the request's registry: starts or refreshes an atom and
43
- * returns the new settled result.
82
+ * `Loader.fetch` on the request's registry: starts or refreshes a source's
83
+ * atom, waits for the new result, and returns its handle.
44
84
  *
45
85
  * @stability unstable
46
86
  * @category verbs
47
87
  * @since 0.1.0
48
88
  */
49
- const fetch = fetch$1;
89
+ const fetch = atoms.fetch;
50
90
  /**
51
91
  * `Hydration.dehydrate` on the request's registry, for `HydrateAtoms`.
52
92
  *
@@ -55,9 +95,17 @@ const fetch = fetch$1;
55
95
  * Includes the atoms started so far, so call it after the server component's
56
96
  * verbs. Each `HydrateAtoms` hydrates what its own `dehydrate()` saw.
57
97
  *
98
+ * **Example**
99
+ *
100
+ * ```tsx
101
+ * <HydrateAtoms state={await dehydrate()}>
102
+ * <Issue issue={handle} />
103
+ * </HydrateAtoms>
104
+ * ```
105
+ *
58
106
  * @stability unstable
59
107
  * @category dehydration
60
108
  * @since 0.1.0
61
109
  */
62
- const dehydrate = dehydrate$1;
63
- export { HydrateAtoms, RegistryProvider, dehydrate, ensure, fetch, getRegistry, prefetch };
110
+ const dehydrate = atoms.dehydrate;
111
+ export { HydrateAtoms, RegistryProvider, dehydrate, ensure, fetch, getRegistry, makeRequestAtoms, prefetch };