react-fate 0.1.3 → 1.0.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.
Files changed (38) hide show
  1. package/README.md +810 -129
  2. package/docs/api/functions/FateClient.md +23 -0
  3. package/docs/api/functions/clientRoot.md +27 -0
  4. package/docs/api/functions/createClient.md +21 -0
  5. package/docs/api/functions/createHTTPTransport.md +51 -0
  6. package/docs/api/functions/createTRPCTransport.md +46 -0
  7. package/docs/api/functions/mutation.md +32 -0
  8. package/docs/api/functions/useFateClient.md +17 -0
  9. package/docs/api/functions/useListView.md +28 -0
  10. package/docs/api/functions/useLiveListView.md +28 -0
  11. package/docs/api/functions/useLiveView.md +38 -0
  12. package/docs/api/functions/useRequest.md +38 -0
  13. package/docs/api/functions/useView.md +37 -0
  14. package/docs/api/functions/view.md +26 -0
  15. package/docs/api/index.md +35 -0
  16. package/docs/api/type-aliases/ConnectionRef.md +13 -0
  17. package/docs/api/type-aliases/InferFateAPI.md +11 -0
  18. package/docs/api/type-aliases/ViewRef.md +13 -0
  19. package/docs/api/variables/toEntityId.md +21 -0
  20. package/docs/guide/actions.md +263 -0
  21. package/docs/guide/core-concepts.md +22 -0
  22. package/docs/guide/getting-started.md +57 -0
  23. package/docs/guide/list-views.md +86 -0
  24. package/docs/guide/live-views.md +245 -0
  25. package/docs/guide/requests.md +130 -0
  26. package/docs/guide/server-integration.md +630 -0
  27. package/docs/guide/views.md +278 -0
  28. package/docs/guide/void-integration.md +167 -0
  29. package/docs/index.md +4 -0
  30. package/lib/cli.d.mts +1 -1
  31. package/lib/cli.mjs +1 -2
  32. package/lib/client.d.mts +7 -0
  33. package/lib/client.mjs +2 -0
  34. package/lib/index.d.mts +41 -17
  35. package/lib/index.mjs +96 -46
  36. package/lib/vite.d.mts +12 -0
  37. package/lib/vite.mjs +8 -0
  38. package/package.json +17 -6
@@ -0,0 +1,278 @@
1
+ # Views
2
+
3
+ ## Defining Views
4
+
5
+ Let's start by defining a simple view for a blog's `Post` component. fate requires you to explicitly "select" each field that you plan to use in your components. Here is how you can define a view for a `Post` entity that has `title` and `content` fields:
6
+
7
+ ```tsx
8
+ import { view } from 'react-fate';
9
+
10
+ type Post = {
11
+ content: string;
12
+ id: string;
13
+ title: string;
14
+ };
15
+
16
+ export const PostView = view<Post>()({
17
+ content: true,
18
+ id: true,
19
+ title: true,
20
+ });
21
+ ```
22
+
23
+ Fields are selected by setting them to `true` in the view definition. This tells **_fate_** that these fields should be fetched from the server and made available to components that use this view.
24
+
25
+ > [!NOTE]
26
+ > The `Post` type above is an example. In a real application, this type is defined on the server and imported into your client code.
27
+
28
+ ## Resolving a View with `useView`
29
+
30
+ Now we can use the view that we defined in a `PostCard` React component to resolve the data against a reference of an individual `Post`:
31
+
32
+ ```tsx
33
+ import { useView, ViewRef } from 'react-fate';
34
+
35
+ export const PostCard = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
36
+ const post = useView(PostView, postRef);
37
+
38
+ return (
39
+ <Card>
40
+ <h2>{post.title}</h2>
41
+ <p>{post.content}</p>
42
+ </Card>
43
+ );
44
+ };
45
+ ```
46
+
47
+ A `ViewRef` is a reference to a concrete object of a specific type, for example a `Post` with id `7`. It contains the unique ID of the object, the type name (as `__typename`) and some fate-specific metadata. fate creates and manages these references for you, and you can pass them around your components as needed.
48
+
49
+ Components using `useView` listen to changes for all selected fields. When data changes, fate re-renders all of the fields that depend on that data. For example, if the `title` of the `Post` changes, the `PostCard` component re-renders with new data. However, if a different field such as `likes` that isn't selected in `PostView` changes, the `PostCard` component will not re-render.
50
+
51
+ ## Fetching Data with `useRequest`
52
+
53
+ Now that we defined our view and component, we fetch the data from the server using the `useRequest` hook from fate. This hook allows us to declare what data we need for a specific screen or component tree. At the root of our app, we can request a list of posts like this:
54
+
55
+ ```tsx
56
+ import { useRequest } from 'react-fate';
57
+ import { PostCard, PostView } from './PostCard.tsx';
58
+
59
+ export function App() {
60
+ const { posts } = useRequest({ posts: { list: PostView } });
61
+
62
+ return posts.map((post) => <PostCard key={post.id} post={post} />);
63
+ }
64
+ ```
65
+
66
+ _Learn more about `useRequest` in the [Requests Guide](requests.md)._
67
+
68
+ ## Composing Views
69
+
70
+ In the above example we are defining a single view for a `Post`. One of fate's core strengths is view composition. Let's say we want to show the author's name along with the post. A simple way to do this is by adding an `author` field to the `PostView` with a concrete selection:
71
+
72
+ ```tsx
73
+ import { Suspense } from 'react';
74
+ import { useView, ViewRef } from 'react-fate';
75
+
76
+ export const PostView = view<Post>()({
77
+ author: {
78
+ id: true,
79
+ name: true,
80
+ },
81
+ content: true,
82
+ id: true,
83
+ title: true,
84
+ });
85
+
86
+ const PostCard = ({ postRef }: { postRef: ViewRef<'Post'> }) => {
87
+ const post = useView(PostView, postRef);
88
+ return (
89
+ <Card>
90
+ <h2>{post.title}</h2>
91
+ <p>by {post.author.name}</p>
92
+ <p>{post.content}</p>
93
+ </Card>
94
+ );
95
+ };
96
+ ```
97
+
98
+ This code fetches the author associated with the Post and makes it available to the `PostCard` component. However, this approach has some downsides:
99
+
100
+ 1. The `author` selection is tightly coupled to the `PostView`. If we want to use the author's data in another component, we would need to duplicate the field selection.
101
+ 1. If the `author` has more fields that we want to use in other components, we would need to add them to the `PostView`, leading to overfetching.
102
+ 1. We cannot reuse the `author` field selection in other views or components.
103
+
104
+ In fate, views are composable and reusable. Instead of inlining the selection, we can define a `UserView` and compose it into the `PostView` like this:
105
+
106
+ ```tsx
107
+ import type { Post, User } from '@your-org/server/trpc/views';
108
+ import { view } from 'react-fate';
109
+
110
+ export const UserView = view<User>()({
111
+ id: true,
112
+ name: true,
113
+ profilePicture: true,
114
+ });
115
+
116
+ export const PostView = view<Post>()({
117
+ author: UserView,
118
+ content: true,
119
+ id: true,
120
+ title: true,
121
+ });
122
+ ```
123
+
124
+ Now we can create a separate `UserCard` component that uses our `UserView`:
125
+
126
+ ```tsx
127
+ import { useView, ViewRef } from 'react-fate';
128
+
129
+ export const UserCard = ({ user: userRef }: { user: ViewRef<'User'> }) => {
130
+ const user = useView(UserView, userRef);
131
+
132
+ return (
133
+ <div>
134
+ <img src={user.profilePicture} alt={user.name} />
135
+ <p>{user.name}</p>
136
+ </div>
137
+ );
138
+ };
139
+ ```
140
+
141
+ And update `PostCard` to use our `UserCard` component:
142
+
143
+ ```tsx
144
+ import { UserCard } from './UserCard.tsx';
145
+
146
+ export const PostCard = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
147
+ const post = useView(PostView, postRef);
148
+
149
+ return (
150
+ <Card>
151
+ <h2>{post.title}</h2>
152
+ <UserCard user={post.author} />
153
+ <p>{post.content}</p>
154
+ </Card>
155
+ );
156
+ };
157
+ ```
158
+
159
+ ## View Spreads
160
+
161
+ When building complex UIs, you will often build multiple components that share the same data requirements. In fate, you can use view spreads to compose such views together. This is similar to GraphQL fragment spreads, but works with plain JavaScript objects.
162
+
163
+ Let's assume we want to fetch and display additional information about the author in the `PostCard`, such as their bio. Instead of directly assigning our `UserView` to the `author` field, we can instead spread it and add the `bio` field:
164
+
165
+ ```tsx
166
+ export const PostView = view<Post>()({
167
+ author: {
168
+ ...UserView,
169
+ bio: true,
170
+ },
171
+ content: true,
172
+ id: true,
173
+ title: true,
174
+ });
175
+ ```
176
+
177
+ Now the `PostCard` component can access the `bio` field of the author:
178
+
179
+ ```tsx
180
+ export const PostCard = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
181
+ const post = useView(PostView, postRef);
182
+
183
+ return (
184
+ <Card>
185
+ <h2>{post.title}</h2>
186
+ <UserCard author={post.author} />
187
+ {/* Accessing the bio field */}
188
+ <p>{post.author.bio}</p>
189
+ <p>{post.content}</p>
190
+ </Card>
191
+ );
192
+ };
193
+ ```
194
+
195
+ We can also spread multiple views together. For example, if we have another view called `UserStatsView` that selects some statistics about the user, we can include it in the `PostView` like this:
196
+
197
+ ```tsx
198
+ export const UserStatsView = view<User>()({
199
+ followerCount: true,
200
+ postCount: true,
201
+ });
202
+
203
+ export const PostView = view<Post>()({
204
+ author: {
205
+ ...UserView,
206
+ ...UserStatsView,
207
+ bio: true,
208
+ },
209
+ content: true,
210
+ id: true,
211
+ title: true,
212
+ });
213
+ ```
214
+
215
+ Views are opaque objects. Even if you select the same field multiple times through different views, the composed object won't have conflicting fields or result in TypeScript errors. fate automatically deduplicates fields during runtime and ensures that each field is only fetched once.
216
+
217
+ ## `useView` and Suspense
218
+
219
+ We learned that `useRequest` is responsible for fetching data from the server and `useView` is used for reading data from the cache. In some situations data may not be available in the cache and `useView` might need to suspend the component to fetch only the missing data. Once that data is fetched and written to the cache, the component resumes rendering.
220
+
221
+ _Tip: You can test this behavior in development mode with Fast Refresh (HMR) enabled in your bundler. When you edit the selection of a view, components using that view will suspend, fetch the missing data, and then resume rendering._
222
+
223
+ ## Type Safety and Data Masking
224
+
225
+ fate provides guarantees through TypeScript and during runtime that prevent you from accessing data that wasn't selected in a component. This ensures that you declare all the data dependencies at the right level in your component tree, and prevents accidental coupling between components.
226
+
227
+ In the below example, we forgot to select the `content` of a `Post`. As a result, type-checks fail and the `content` field is undefined during runtime:
228
+
229
+ ```tsx
230
+ const PostView = view<Post>()({
231
+ id: true,
232
+ title: true,
233
+ // `content: true` is omitted.
234
+ });
235
+
236
+ const PostCard = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
237
+ const post = useView(PostView, postRef);
238
+
239
+ return (
240
+ <Card>
241
+ <h2>{post.title}</h2>
242
+ {/* TypeScript errors here, and `post.content` is undefined during runtime */}
243
+ <p>{post.content}</p>
244
+ </Card>
245
+ );
246
+ };
247
+ ```
248
+
249
+ Views can only be resolved against refs that include that view directly or via view spreads. If a component tries to resolve a view against a ref that isn't linked, it will throw an error during runtime:
250
+
251
+ ```tsx
252
+ const PostDetailView = view<Post>()({
253
+ content: true,
254
+ });
255
+
256
+ const AnotherPostView = view<Post>()({
257
+ content: true,
258
+ });
259
+
260
+ const PostView = view<Post>()({
261
+ id: true,
262
+ title: true,
263
+ ...AnotherPostView,
264
+ });
265
+
266
+ const PostCard = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
267
+ const post = useView(PostView, postRef);
268
+ return <PostDetail post={post} />;
269
+ };
270
+
271
+ const PostDetail = ({ post: postRef }: { post: ViewRef<'Post'> }) => {
272
+ // This throws because the post reference passed into this component
273
+ // is of type `AnotherPostView`, not `PostDetailView`.
274
+ const post = useView(PostDetailView, postRef);
275
+ };
276
+ ```
277
+
278
+ ViewRefs carry a set of view names they can resolve. `useView` throws if a ref does not include the required view.
@@ -0,0 +1,167 @@
1
+ # Void Integration
2
+
3
+ `void-fate` is the first-class [Void](https://void.cloud) adapter for fate to ease integration with the Void SDK and for deploying to the Void platform.
4
+
5
+ Use this integration when your app runs on Void and you want the example app's
6
+ setup without copying its adapter glue.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pnpm add @nkzw/fate react-fate void-fate void
12
+ ```
13
+
14
+ ## Vite
15
+
16
+ Use the regular `react-fate` Vite plugin with the Void transport:
17
+
18
+ ```tsx
19
+ import { voidReact } from '@void/react/plugin';
20
+ import { fate } from 'react-fate/vite';
21
+ import { defineConfig } from 'vite-plus';
22
+ import { voidPlugin } from 'void';
23
+
24
+ export default defineConfig({
25
+ plugins: [
26
+ voidPlugin(),
27
+ voidReact(),
28
+ fate({
29
+ module: './src/fate/server.ts',
30
+ transport: 'void',
31
+ }),
32
+ ],
33
+ });
34
+ ```
35
+
36
+ The generated client uses `/fate` for RPC requests and `/fate-live` for live
37
+ updates by default. In SSR, it calls the exported fate server directly. In the
38
+ browser, it uses fetch and the SSE live endpoint.
39
+
40
+ ## Server Setup
41
+
42
+ Create a Void live adapter with `createVoidFateLive`, pass its `live` event bus
43
+ to `createFateServer`, and export the adapter next to your fate server.
44
+
45
+ ```tsx
46
+ import { createFateServer } from '@nkzw/fate/server';
47
+ import { createDrizzleSourceAdapter } from '@nkzw/fate/server/drizzle';
48
+ import { createVoidFateLive } from 'void-fate/server';
49
+ import { db } from 'void/db';
50
+ import schema from '../db/schema.ts';
51
+ import { createContext } from './context.ts';
52
+ import { Root } from './views.ts';
53
+
54
+ const sources = createDrizzleSourceAdapter({
55
+ db,
56
+ schema,
57
+ views: Root,
58
+ });
59
+
60
+ export const fateLive = createVoidFateLive();
61
+ export const { live } = fateLive;
62
+
63
+ export const fateServer = createFateServer({
64
+ context: ({ request }) => createContext({ request }),
65
+ live,
66
+ roots: Root,
67
+ sources,
68
+ });
69
+ ```
70
+
71
+ Your app can publish live updates through the normal fate live bus:
72
+
73
+ ```tsx
74
+ live.update('Post', postId, { changed: ['likes'] });
75
+ live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId, {
76
+ node: comment,
77
+ });
78
+ ```
79
+
80
+ `changed` is optional. Void still uses generic topic fanout, while fate uses the changed field paths to refetch or write only the selected fields affected by the event.
81
+
82
+ ## Routes
83
+
84
+ Add one route for fate RPC requests:
85
+
86
+ ```tsx
87
+ // routes/fate.ts
88
+ import { defineVoidFateRoute } from 'void-fate/server';
89
+ import { fateLive, fateServer } from '../src/fate/server.ts';
90
+
91
+ export const { GET, POST } = defineVoidFateRoute(fateServer, fateLive);
92
+ ```
93
+
94
+ Add a second route for the live SSE transport:
95
+
96
+ ```tsx
97
+ // routes/fate-live.ts
98
+ import { defineVoidFateLiveRoute } from 'void-fate/server';
99
+ import { fateLive, fateServer } from '../src/fate/server.ts';
100
+
101
+ export const { GET, POST } = defineVoidFateLiveRoute(fateServer, fateLive);
102
+ ```
103
+
104
+ The live route handles `GET /fate-live` SSE connections and `POST /fate-live`
105
+ control messages. `void-fate` does not use WebSockets.
106
+
107
+ ## React Layout
108
+
109
+ Wrap your app with `VoidFateClient` from `void-fate/react`. It creates the
110
+ generated fate client and provides it through `react-fate`:
111
+
112
+ ```tsx
113
+ import { useShared } from '@void/react';
114
+ import type { ReactNode } from 'react';
115
+ import { VoidFateClient } from 'void-fate/react';
116
+ import type { SharedData } from '../src/lib/shared.ts';
117
+
118
+ export default function Layout({ children }: { children: ReactNode }) {
119
+ const shared = useShared<SharedData>();
120
+ const userId = shared.auth.user?.id;
121
+ const origin = typeof window === 'undefined' ? shared.origin : window.location.origin;
122
+
123
+ return (
124
+ <VoidFateClient origin={origin} userId={userId}>
125
+ {children}
126
+ </VoidFateClient>
127
+ );
128
+ }
129
+ ```
130
+
131
+ `userId` is optional, but passing it lets `VoidFateClient` recreate the client
132
+ when the signed-in user changes. Browser requests include credentials when a
133
+ `userId` is present.
134
+
135
+ ## Custom Paths
136
+
137
+ The default route pair is `/fate` and `/fate-live`. If your Void app uses
138
+ different paths, configure the same values on the live adapter and client.
139
+
140
+ ```tsx
141
+ export const fateLive = createVoidFateLive({
142
+ livePath: '/custom-fate-live',
143
+ });
144
+ ```
145
+
146
+ ```tsx
147
+ <VoidFateClient livePath="/custom-fate-live" origin={origin} rpcPath="/custom-fate" userId={userId}>
148
+ {children}
149
+ </VoidFateClient>
150
+ ```
151
+
152
+ The route helper does not own the route path. Make sure your Void route filename
153
+ or router configuration matches the paths you pass to the client.
154
+
155
+ ## Live Transport
156
+
157
+ Void can run separate request handlers for mutations and long-lived SSE
158
+ connections. `createVoidFateLive` bridges those handlers by publishing live
159
+ events from the request that changed data to the live route.
160
+
161
+ In local development, `void-fate` uses a development token for that internal
162
+ publish request. Outside local development, Void must provide `__VOID_PROXY_TOKEN`
163
+ in the route environment. If no internal publish token is available, the adapter
164
+ falls back to the in-memory live bus for the current request context.
165
+
166
+ The live transport is best-effort and does not replay missed events after a
167
+ client reconnects. This matches fate's default in-memory live event bus.
package/docs/index.md ADDED
@@ -0,0 +1,4 @@
1
+ # react-fate Docs
2
+
3
+ - [Guides](guide/getting-started.md)
4
+ - [API Reference](api/index.md)
package/lib/cli.d.mts CHANGED
@@ -1 +1 @@
1
- import "@nkzw/fate/cli";
1
+ export { };
package/lib/cli.mjs CHANGED
@@ -1,3 +1,2 @@
1
1
  import "@nkzw/fate/cli";
2
-
3
- export { };
2
+ export {};
@@ -0,0 +1,7 @@
1
+ import { createFateClient } from "@nkzw/fate/client";
2
+
3
+ //#region src/client.d.ts
4
+ interface ClientMutations {}
5
+ interface ClientRoots {}
6
+ //#endregion
7
+ export { ClientMutations, ClientRoots, createFateClient };
package/lib/client.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { createFateClient } from "@nkzw/fate/client";
2
+ export { createFateClient };
package/lib/index.d.mts CHANGED
@@ -1,9 +1,11 @@
1
- import { ConnectionRef, FateClient as FateClient$1, FateMutations, FateRoots, Pagination, Request, RequestOptions, RequestResult, View, ViewData, ViewEntity, ViewEntityName, ViewRef, ViewRef as ViewRef$1, ViewSelection, clientRoot, createClient, createTRPCTransport, mutation, toEntityId, view } from "@nkzw/fate";
1
+ import { ConnectionRef, FateClient as FateClient$1, FateMutations, FateRoots, InferFateAPI, Pagination, Request, RequestOptions, RequestResult, View, ViewData, ViewEntity, ViewEntityName, ViewRef, ViewRef as ViewRef$1, ViewSelection, clientRoot, createClient, createHTTPTransport, createTRPCTransport, mutation, toEntityId, view } from "@nkzw/fate";
2
2
  import { ReactNode } from "react";
3
- import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
+ import * as _$react_fate_client0 from "react-fate/client";
4
5
 
5
6
  //#region src/useRequest.d.ts
6
- type Roots = keyof ClientRoots extends never ? FateRoots : ClientRoots;
7
+ type GeneratedFateClient$1 = ReturnType<typeof _$react_fate_client0.createFateClient>;
8
+ type Roots = [GeneratedFateClient$1] extends [never] ? FateRoots : GeneratedFateClient$1 extends FateClient$1<infer R, any> ? R : FateRoots;
7
9
  /**
8
10
  * Declares the data a screen needs and kicks off fetching, suspending while the
9
11
  * request resolves.
@@ -14,7 +16,8 @@ type Roots = keyof ClientRoots extends never ? FateRoots : ClientRoots;
14
16
  declare function useRequest<R extends Request, O extends FateRoots = Roots>(request: R, options?: RequestOptions): RequestResult<O, R>;
15
17
  //#endregion
16
18
  //#region src/context.d.ts
17
- type Mutations = keyof ClientMutations extends never ? FateMutations : ClientMutations;
19
+ type GeneratedFateClient = ReturnType<typeof _$react_fate_client0.createFateClient>;
20
+ type Mutations = [GeneratedFateClient] extends [never] ? FateMutations : GeneratedFateClient extends FateClient$1<any, infer M> ? M : FateMutations;
18
21
  /**
19
22
  * Provider component that supplies a configured `FateClient` to React hooks.
20
23
  */
@@ -24,25 +27,26 @@ declare function FateClient({
24
27
  }: {
25
28
  children: ReactNode;
26
29
  client: FateClient$1<any, any>;
27
- }): react_jsx_runtime0.JSX.Element;
30
+ }): _$react_jsx_runtime0.JSX.Element;
28
31
  /**
29
32
  * Returns the nearest `FateClient` from context.
30
33
  */
31
- declare function useFateClient<T extends [Roots, Mutations]>(): FateClient$1<T[0], T[1]>;
34
+ declare function useFateClient<T extends [Roots, Mutations] = [Roots, Mutations]>(): FateClient$1<T[0], T[1]>;
32
35
  //#endregion
33
- //#region src/useView.d.ts
34
- type ViewEntityWithTypename<V extends View<any, any>> = ViewEntity<V> & {
36
+ //#region src/useLiveView.d.ts
37
+ type ViewEntityWithTypename$1<V extends View<any, any>> = ViewEntity<V> & {
35
38
  __typename: ViewEntityName<V>;
36
39
  };
37
40
  /**
38
- * Resolves a reference against a view and subscribes to updates for that selection.
41
+ * Resolves a reference against a view and subscribes to live server updates for
42
+ * that selection.
39
43
  *
40
44
  * @example
41
- * const post = useView(PostView, postRef);
45
+ * const post = useLiveView(PostView, postRef);
42
46
  */
43
- declare function useView<V extends View<any, any>, R extends ViewRef$1<ViewEntityName<V>> | null>(view: V, ref: R): R extends null ? null : ViewData<ViewEntityWithTypename<V>, ViewSelection<V>>;
47
+ declare function useLiveView<V extends View<any, any>, R extends ViewRef$1<ViewEntityName<V>> | null>(view: V, ref: R): R extends null ? null : ViewData<ViewEntityWithTypename$1<V>, ViewSelection<V>>;
44
48
  //#endregion
45
- //#region src/useListView.d.ts
49
+ //#region src/listView.d.ts
46
50
  type ConnectionItems<C> = C extends {
47
51
  items?: ReadonlyArray<infer Item>;
48
52
  } ? ReadonlyArray<Item> : ReadonlyArray<never>;
@@ -52,6 +56,30 @@ type ConnectionSelection = {
52
56
  node?: unknown;
53
57
  };
54
58
  };
59
+ //#endregion
60
+ //#region src/useLiveListView.d.ts
61
+ /**
62
+ * Subscribes to a connection field, returning live-updating items and pagination
63
+ * helpers to load the next or previous page.
64
+ */
65
+ declare function useLiveListView<C extends {
66
+ items?: ReadonlyArray<any>;
67
+ pagination?: Pagination;
68
+ } | null | undefined>(selection: ConnectionSelection, connection: C): [ConnectionItems<NonNullable<C>>, LoadMoreFn | null, LoadMoreFn | null];
69
+ //#endregion
70
+ //#region src/useView.d.ts
71
+ type ViewEntityWithTypename<V extends View<any, any>> = ViewEntity<V> & {
72
+ __typename: ViewEntityName<V>;
73
+ };
74
+ /**
75
+ * Resolves a reference against a view and subscribes to updates for that selection.
76
+ *
77
+ * @example
78
+ * const post = useView(PostView, postRef);
79
+ */
80
+ declare function useView<V extends View<any, any>, R extends ViewRef$1<ViewEntityName<V>> | null>(view: V, ref: R): R extends null ? null : ViewData<ViewEntityWithTypename<V>, ViewSelection<V>>;
81
+ //#endregion
82
+ //#region src/useListView.d.ts
55
83
  /**
56
84
  * Subscribes to a connection field, returning the current items and pagination
57
85
  * helpers to load the next or previous page.
@@ -61,8 +89,4 @@ declare function useListView<C extends {
61
89
  pagination?: Pagination;
62
90
  } | null | undefined>(selection: ConnectionSelection, connection: C): [ConnectionItems<NonNullable<C>>, LoadMoreFn | null, LoadMoreFn | null];
63
91
  //#endregion
64
- //#region src/index.d.ts
65
- interface ClientMutations {}
66
- interface ClientRoots {}
67
- //#endregion
68
- export { ClientMutations, ClientRoots, type ConnectionRef, FateClient, type ViewRef, clientRoot, createClient, createTRPCTransport, mutation, toEntityId, useFateClient, useListView, useRequest, useView, view };
92
+ export { type ConnectionRef, FateClient, type InferFateAPI, type ViewRef, clientRoot, createClient, createHTTPTransport, createTRPCTransport, mutation, toEntityId, useFateClient, useListView, useLiveListView, useLiveView, useRequest, useView, view };