@nkzw/fate 1.1.0 → 1.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.
Files changed (174) hide show
  1. package/README.md +745 -24
  2. package/docs/api/classes/FateClient.md +63 -39
  3. package/docs/api/functions/clientRoot.md +1 -1
  4. package/docs/api/functions/createClient.md +1 -1
  5. package/docs/api/functions/createGraphQLTransport.md +1 -1
  6. package/docs/api/functions/createHTTPTransport.md +1 -1
  7. package/docs/api/functions/createTRPCTransport.md +1 -1
  8. package/docs/api/functions/defer.md +21 -0
  9. package/docs/api/functions/getDeferredMetadata.md +21 -0
  10. package/docs/api/functions/getListEntries.md +1 -1
  11. package/docs/api/functions/getSelectionPlan.md +1 -1
  12. package/docs/api/functions/graphqlMutation.md +1 -1
  13. package/docs/api/functions/isDeferred.md +15 -0
  14. package/docs/api/functions/isRecord.md +1 -1
  15. package/docs/api/functions/isViewTag.md +1 -1
  16. package/docs/api/functions/liveConnectionTopic.md +1 -1
  17. package/docs/api/functions/liveEntityTopic.md +1 -1
  18. package/docs/api/functions/liveGlobalConnectionTopic.md +1 -1
  19. package/docs/api/functions/mutation.md +1 -1
  20. package/docs/api/functions/toEntityId.md +1 -1
  21. package/docs/api/functions/view.md +1 -1
  22. package/docs/api/index.md +9 -0
  23. package/docs/api/interfaces/FateThenable.md +3 -3
  24. package/docs/api/interfaces/Transport.md +7 -7
  25. package/docs/api/server/classes/FateRequestError.md +5 -5
  26. package/docs/api/server/drizzle/functions/createDrizzleFate.md +1 -1
  27. package/docs/api/server/drizzle/functions/createDrizzleSourceAdapter.md +1 -1
  28. package/docs/api/server/drizzle/functions/createDrizzleSourceRegistry.md +1 -1
  29. package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyConfig.md +1 -1
  30. package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyInput.md +1 -1
  31. package/docs/api/server/drizzle/type-aliases/DrizzleQueryExtra.md +3 -3
  32. package/docs/api/server/drizzle/type-aliases/DrizzleSourceAdapter.md +9 -9
  33. package/docs/api/server/drizzle/type-aliases/DrizzleViewConfig.md +1 -1
  34. package/docs/api/server/functions/bindSourceProcedures.md +1 -1
  35. package/docs/api/server/functions/computed.md +1 -1
  36. package/docs/api/server/functions/count.md +1 -1
  37. package/docs/api/server/functions/createFateFetchHandler.md +1 -1
  38. package/docs/api/server/functions/createFateServer.md +1 -1
  39. package/docs/api/server/functions/createHonoFateHandler.md +1 -1
  40. package/docs/api/server/functions/createLiveEventBus.md +1 -1
  41. package/docs/api/server/functions/createNestedSourcePlan.md +1 -1
  42. package/docs/api/server/functions/createResolver.md +1 -1
  43. package/docs/api/server/functions/createSourcePlan.md +1 -1
  44. package/docs/api/server/functions/createSourceProcedures.md +1 -1
  45. package/docs/api/server/functions/dataView.md +1 -1
  46. package/docs/api/server/functions/field.md +1 -1
  47. package/docs/api/server/functions/getNestedSelection.md +1 -1
  48. package/docs/api/server/functions/getScopedArgs.md +1 -1
  49. package/docs/api/server/functions/hasNestedSelection.md +1 -1
  50. package/docs/api/server/functions/list.md +1 -1
  51. package/docs/api/server/functions/refetchSourceById.md +1 -1
  52. package/docs/api/server/functions/resolveSourceById.md +1 -1
  53. package/docs/api/server/functions/resolveSourceByIds.md +1 -1
  54. package/docs/api/server/functions/resolveSourceConnection.md +1 -1
  55. package/docs/api/server/functions/resolver.md +1 -1
  56. package/docs/api/server/functions/toPrismaSelect.md +1 -1
  57. package/docs/api/server/functions/withConnection.md +1 -1
  58. package/docs/api/server/prisma/functions/createPrismaFate.md +1 -1
  59. package/docs/api/server/prisma/functions/createPrismaSourceAdapter.md +1 -1
  60. package/docs/api/server/prisma/functions/createPrismaSourceRegistry.md +1 -1
  61. package/docs/api/server/prisma/functions/prismaConnectionArgs.md +1 -1
  62. package/docs/api/server/prisma/type-aliases/PrismaDelegate.md +4 -4
  63. package/docs/api/server/prisma/type-aliases/PrismaQueryExtra.md +1 -1
  64. package/docs/api/server/prisma/type-aliases/PrismaSourceAdapter.md +9 -9
  65. package/docs/api/server/prisma/type-aliases/PrismaViewConfig.md +1 -1
  66. package/docs/api/server/type-aliases/ComputedField.md +5 -5
  67. package/docs/api/server/type-aliases/ComputedSelection.md +1 -1
  68. package/docs/api/server/type-aliases/ConnectionItem.md +3 -3
  69. package/docs/api/server/type-aliases/ConnectionPagination.md +5 -5
  70. package/docs/api/server/type-aliases/ConnectionResult.md +3 -3
  71. package/docs/api/server/type-aliases/CountSelection.md +4 -4
  72. package/docs/api/server/type-aliases/CountWhere.md +1 -1
  73. package/docs/api/server/type-aliases/DataViewListOptions.md +2 -2
  74. package/docs/api/server/type-aliases/DataViewOrderBy.md +1 -1
  75. package/docs/api/server/type-aliases/DataViewOrderDirection.md +1 -1
  76. package/docs/api/server/type-aliases/DataViewResult.md +1 -1
  77. package/docs/api/server/type-aliases/Entity.md +1 -1
  78. package/docs/api/server/type-aliases/FateServer.md +5 -5
  79. package/docs/api/server/type-aliases/FateServerManifest.md +1 -1
  80. package/docs/api/server/type-aliases/FieldSelection.md +3 -3
  81. package/docs/api/server/type-aliases/LiveConnectionEventType.md +1 -1
  82. package/docs/api/server/type-aliases/LiveConnectionSourceEvent.md +1 -1
  83. package/docs/api/server/type-aliases/LiveEventBus.md +1 -1
  84. package/docs/api/server/type-aliases/LiveEventType.md +1 -1
  85. package/docs/api/server/type-aliases/LiveSourceEvent.md +1 -1
  86. package/docs/api/server/type-aliases/NativeFateAPI.md +4 -4
  87. package/docs/api/server/type-aliases/OrderDirection.md +1 -1
  88. package/docs/api/server/type-aliases/SourceConfig.md +6 -6
  89. package/docs/api/server/type-aliases/SourceDefinition.md +6 -6
  90. package/docs/api/server/type-aliases/SourceOrder.md +1 -1
  91. package/docs/api/server/type-aliases/SourceOrderField.md +3 -3
  92. package/docs/api/server/type-aliases/SourcePlan.md +1 -1
  93. package/docs/api/server/type-aliases/SourcePlanNode.md +1 -1
  94. package/docs/api/server/type-aliases/SourceRegistry.md +1 -1
  95. package/docs/api/server/type-aliases/SourceRelation.md +1 -1
  96. package/docs/api/server/type-aliases/SourceRelationConfig.md +1 -1
  97. package/docs/api/server/variables/byIdInput.md +1 -1
  98. package/docs/api/server/variables/connectionArgs.md +1 -1
  99. package/docs/api/type-aliases/ConnectionMetadata.md +1 -1
  100. package/docs/api/type-aliases/ConnectionRef.md +1 -1
  101. package/docs/api/type-aliases/Deferred.md +19 -0
  102. package/docs/api/type-aliases/DeferredMetadata.md +7 -0
  103. package/docs/api/type-aliases/DeferredSelection.md +13 -0
  104. package/docs/api/type-aliases/DeferredSnapshot.md +11 -0
  105. package/docs/api/type-aliases/Entity.md +2 -2
  106. package/docs/api/type-aliases/EntityId.md +1 -1
  107. package/docs/api/type-aliases/FateDehydratedState.md +1 -1
  108. package/docs/api/type-aliases/FateLiveConnectionEvent.md +1 -1
  109. package/docs/api/type-aliases/FateLiveEvent.md +1 -1
  110. package/docs/api/type-aliases/FateMutations.md +1 -1
  111. package/docs/api/type-aliases/FateOperation.md +1 -1
  112. package/docs/api/type-aliases/FateProtocolRequest.md +1 -1
  113. package/docs/api/type-aliases/FateProtocolResponse.md +1 -1
  114. package/docs/api/type-aliases/FateRecord.md +1 -1
  115. package/docs/api/type-aliases/FateRoots.md +1 -1
  116. package/docs/api/type-aliases/GraphQLMutationDefinition.md +1 -1
  117. package/docs/api/type-aliases/GraphQLMutationInput.md +1 -1
  118. package/docs/api/type-aliases/GraphQLMutationMap.md +1 -1
  119. package/docs/api/type-aliases/GraphQLMutationOutput.md +1 -1
  120. package/docs/api/type-aliases/GraphQLTransportOptions.md +11 -11
  121. package/docs/api/type-aliases/HydrateOptions.md +1 -1
  122. package/docs/api/type-aliases/HydrationLimits.md +1 -1
  123. package/docs/api/type-aliases/InferFateAPI.md +1 -1
  124. package/docs/api/type-aliases/List.md +1 -1
  125. package/docs/api/type-aliases/ListEntry.md +1 -1
  126. package/docs/api/type-aliases/ListItem.md +1 -1
  127. package/docs/api/type-aliases/Mask.md +1 -1
  128. package/docs/api/type-aliases/MutationDefinition.md +1 -1
  129. package/docs/api/type-aliases/MutationEntity.md +1 -1
  130. package/docs/api/type-aliases/MutationIdentifier.md +1 -1
  131. package/docs/api/type-aliases/MutationInput.md +1 -1
  132. package/docs/api/type-aliases/MutationResult.md +1 -1
  133. package/docs/api/type-aliases/NodesItem.md +1 -1
  134. package/docs/api/type-aliases/Pagination.md +5 -5
  135. package/docs/api/type-aliases/Request.md +1 -1
  136. package/docs/api/type-aliases/RequestMode.md +1 -1
  137. package/docs/api/type-aliases/RequestOptions.md +1 -1
  138. package/docs/api/type-aliases/RequestResult.md +1 -1
  139. package/docs/api/type-aliases/Selection.md +1 -1
  140. package/docs/api/type-aliases/Snapshot.md +1 -1
  141. package/docs/api/type-aliases/TypeConfig.md +4 -4
  142. package/docs/api/type-aliases/View.md +1 -1
  143. package/docs/api/type-aliases/ViewData.md +1 -1
  144. package/docs/api/type-aliases/ViewEntity.md +1 -1
  145. package/docs/api/type-aliases/ViewEntityName.md +1 -1
  146. package/docs/api/type-aliases/ViewRef.md +1 -1
  147. package/docs/api/type-aliases/ViewSelection.md +1 -1
  148. package/docs/api/type-aliases/ViewSnapshot.md +1 -1
  149. package/docs/api/type-aliases/ViewTag.md +1 -1
  150. package/docs/api/variables/ConnectionTag.md +1 -1
  151. package/docs/api/variables/DeferTag.md +7 -0
  152. package/docs/api/variables/DeferredTag.md +7 -0
  153. package/docs/guide/actions.md +7 -7
  154. package/docs/guide/deferred-views.md +62 -0
  155. package/docs/guide/getting-started.md +21 -3
  156. package/docs/guide/vue.md +256 -0
  157. package/docs/index.md +1 -0
  158. package/docs/{guide/graphql-integration.md → integrations/graphql.md} +53 -6
  159. package/docs/{guide/server-integration.md → integrations/server.md} +93 -7
  160. package/docs/{guide/void-integration.md → integrations/void.md} +94 -12
  161. package/lib/{executor-sLcAqDMs.d.mts → executor-Dh-MLUXc.d.mts} +1 -1
  162. package/lib/{graphqlTransport-DbRHbYtb.d.mts → graphqlTransport-B3cbhvJX.d.mts} +1 -1
  163. package/lib/graphqlTransport.d.mts +1 -1
  164. package/lib/index.d.mts +10 -5
  165. package/lib/index.mjs +119 -3
  166. package/lib/{list-CMQOQGdn.d.mts → list-BrL6PD_6.d.mts} +1 -1
  167. package/lib/list.d.mts +1 -1
  168. package/lib/{record-BtdKzEGI.d.mts → record-BkvZwvFk.d.mts} +2 -2
  169. package/lib/server/drizzle.d.mts +2 -2
  170. package/lib/server/prisma.d.mts +2 -2
  171. package/lib/server.d.mts +3 -3
  172. package/lib/{transport-BTgtSwOM.d.mts → transport-BjGm__3t.d.mts} +36 -3
  173. package/lib/vite.d.mts +1 -1
  174. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  # GraphQL Integration
2
2
 
3
- _fate_ can use an existing GraphQL API as its transport. This keeps the React APIs, view composition, normalized cache, masking, requests, list views, live views, and actions the same while replacing the native or tRPC backend with GraphQL operations.
3
+ _fate_ can use an existing GraphQL API as its transport. This keeps the adapter APIs, view composition, normalized cache, masking, requests, list views, live views, and mutations the same while replacing the native or tRPC backend with GraphQL operations.
4
4
 
5
5
  Use the GraphQL transport when your backend already exposes GraphQL and you want fate's client model without adding fate's native server protocol.
6
6
 
@@ -100,13 +100,15 @@ export const fateGraphQL = {
100
100
  } as const;
101
101
  ```
102
102
 
103
- The data views describe the fields React components are allowed to select. `Root` describes the root operations available to `useRequest`. `fateGraphQL.roots` maps those root names to actual GraphQL fields. If the GraphQL field has the same name as the fate root, the `field` entry can be omitted.
103
+ The data views describe the fields client components are allowed to select. `Root` describes the root operations available to `useRequest`. `fateGraphQL.roots` maps those root names to actual GraphQL fields. If the GraphQL field has the same name as the fate root, the `field` entry can be omitted.
104
104
 
105
105
  ## Vite Plugin
106
106
 
107
107
  Configure the fate Vite plugin with the GraphQL transport and point it at the mapping module:
108
108
 
109
- ```tsx
109
+ ::: code-group
110
+
111
+ ```tsx [React]
110
112
  import { fate } from 'react-fate/vite';
111
113
  import { defineConfig } from 'vite';
112
114
 
@@ -120,13 +122,33 @@ export default defineConfig({
120
122
  });
121
123
  ```
122
124
 
125
+ ```ts [Vue]
126
+ import vue from '@vitejs/plugin-vue';
127
+ import { fate } from 'vue-fate/vite';
128
+ import { defineConfig } from 'vite';
129
+
130
+ export default defineConfig({
131
+ plugins: [
132
+ vue(),
133
+ fate({
134
+ module: './src/fate/graphql.ts',
135
+ transport: 'graphql',
136
+ }),
137
+ ],
138
+ });
139
+ ```
140
+
141
+ :::
142
+
123
143
  The plugin generates a typed `createFateClient` helper from your views, roots, and GraphQL mapping. It also watches the mapping module and the files it imports during development.
124
144
 
125
145
  ## Creating a Client
126
146
 
127
147
  Create the client with your GraphQL endpoint and provide it through the `FateClient` provider:
128
148
 
129
- ```tsx
149
+ ::: code-group
150
+
151
+ ```tsx [React]
130
152
  import { FateClient } from 'react-fate';
131
153
  import { createFateClient } from 'react-fate/client';
132
154
 
@@ -142,6 +164,29 @@ export function App() {
142
164
  }
143
165
  ```
144
166
 
167
+ ```vue [Vue]
168
+ <script setup lang="ts">
169
+ import { FateClient } from 'vue-fate';
170
+ import { createFateClient } from 'vue-fate/client';
171
+ import AppRoutes from './AppRoutes.vue';
172
+
173
+ const fate = createFateClient({
174
+ headers: () => ({
175
+ authorization: `Bearer ${token}`,
176
+ }),
177
+ url: 'https://api.example.com/graphql',
178
+ });
179
+ </script>
180
+
181
+ <template>
182
+ <FateClient :client="fate">
183
+ <AppRoutes />
184
+ </FateClient>
185
+ </template>
186
+ ```
187
+
188
+ :::
189
+
145
190
  Use `fetch` when you need to customize credentials or reuse an application fetch wrapper:
146
191
 
147
192
  ```tsx
@@ -157,6 +202,8 @@ const fate = createFateClient({
157
202
 
158
203
  GraphQL operations issued in the same microtask are batched into a single GraphQL query or mutation document with aliased fields.
159
204
 
205
+ Deferred view fields work with the GraphQL transport through the same normalized cache flow as native HTTP: the eager query omits `defer(...)` fields, and `useView`, `useListView`, or `useLiveListView` fetches the missing selection through `nodes(ids:)` when the deferred handle is read. GraphQL `@defer` is the natural wire format for this feature, but fate's GraphQL transport currently expects one JSON result per operation and does not consume incremental multipart patches yet.
206
+
160
207
  ## Object IDs
161
208
 
162
209
  The transport converts between fate entity IDs and GraphQL node IDs. By default, it sends IDs as `${type}-${id}` and strips that prefix from returned IDs. Override this if your schema uses Relay global IDs, raw database IDs, or another encoding:
@@ -252,7 +299,7 @@ export const fateGraphQL = {
252
299
  } as const;
253
300
  ```
254
301
 
255
- Actions use the same `mutation(...)` and `useActionState` APIs described in the [Actions Guide](actions.md).
302
+ Mutations use the same `mutation(...)` API described in the [Actions Guide](../guide/actions.md). React clients can also expose those mutations as Actions for `useActionState`.
256
303
 
257
304
  ## Live Views
258
305
 
@@ -295,4 +342,4 @@ const fate = createFateClient({
295
342
 
296
343
  The GraphQL transport is intentionally a mapping layer. It does not require `createFateServer`, the Prisma adapter, or the Drizzle adapter. Your GraphQL server remains responsible for authorization, validation, resolver behavior, cursor pagination, and mutation side effects.
297
344
 
298
- Use data views to expose only the fields the client should be able to select, keep GraphQL schema authorization in your server, and treat `src/fate/graphql.ts` as the contract between your GraphQL API and fate's React client.
345
+ Use data views to expose only the fields the client should be able to select, keep GraphQL schema authorization in your server, and treat `src/fate/graphql.ts` as the contract between your GraphQL API and fate's client.
@@ -4,7 +4,7 @@ Until now, we have focused on the client-side API of fate. You'll need a backend
4
4
 
5
5
  - The native fate protocol, which is transport-agnostic and can be hosted by any Fetch-compatible server.
6
6
  - The tRPC adapter, which keeps compatibility with existing tRPC backends.
7
- - The [GraphQL transport](graphql-integration.md), which maps fate views and roots to an existing GraphQL schema.
7
+ - The [GraphQL transport](graphql.md), which maps fate views and roots to an existing GraphQL schema.
8
8
 
9
9
  _fate_ currently provides database adapters for Prisma and Drizzle, but the framework itself is not coupled to a particular ORM. The adapters plug into the same source execution runtime and can be exposed through the native protocol or through tRPC.
10
10
 
@@ -185,7 +185,9 @@ app.post('/fate/live', handler);
185
185
 
186
186
  Configure the Vite plugin with the native transport:
187
187
 
188
- ```tsx
188
+ ::: code-group
189
+
190
+ ```tsx [React]
189
191
  import { fate } from 'react-fate/vite';
190
192
  import { defineConfig } from 'vite';
191
193
 
@@ -199,9 +201,29 @@ export default defineConfig({
199
201
  });
200
202
  ```
201
203
 
204
+ ```ts [Vue]
205
+ import vue from '@vitejs/plugin-vue';
206
+ import { fate } from 'vue-fate/vite';
207
+ import { defineConfig } from 'vite';
208
+
209
+ export default defineConfig({
210
+ plugins: [
211
+ vue(),
212
+ fate({
213
+ module: '@your-org/server/fate.ts',
214
+ transport: 'native',
215
+ }),
216
+ ],
217
+ });
218
+ ```
219
+
220
+ :::
221
+
202
222
  With the native transport, the Vite plugin handles the HTTP transport setup. If you need to create a client manually, use `createFateClient` with the same route:
203
223
 
204
- ```tsx
224
+ ::: code-group
225
+
226
+ ```tsx [React]
205
227
  import { createFateClient } from 'react-fate/client';
206
228
 
207
229
  const client = createFateClient({
@@ -209,6 +231,16 @@ const client = createFateClient({
209
231
  });
210
232
  ```
211
233
 
234
+ ```ts [Vue]
235
+ import { createFateClient } from 'vue-fate/client';
236
+
237
+ const client = createFateClient({
238
+ url: '/fate',
239
+ });
240
+ ```
241
+
242
+ :::
243
+
212
244
  The HTTP transport batches operations issued in the same microtask into one `POST /fate` request. Live views use one `GET /fate/live` SSE stream per fate client and `POST /fate/live` control messages when views subscribe or unsubscribe.
213
245
 
214
246
  ### Custom Queries
@@ -585,7 +617,9 @@ export * from './views.ts';
585
617
 
586
618
  Configure the fate Vite plugin with your server module:
587
619
 
588
- ```tsx
620
+ ::: code-group
621
+
622
+ ```tsx [React]
589
623
  import { fate } from 'react-fate/vite';
590
624
  import { defineConfig } from 'vite';
591
625
 
@@ -598,11 +632,28 @@ export default defineConfig({
598
632
  });
599
633
  ```
600
634
 
635
+ ```ts [Vue]
636
+ import vue from '@vitejs/plugin-vue';
637
+ import { fate } from 'vue-fate/vite';
638
+ import { defineConfig } from 'vite';
639
+
640
+ export default defineConfig({
641
+ plugins: [
642
+ vue(),
643
+ fate({
644
+ module: '@your-org/server/trpc/router.ts',
645
+ }),
646
+ ],
647
+ });
648
+ ```
649
+
650
+ :::
651
+
601
652
  _Note: fate uses the specified server module name to find the server types it needs. Make sure that the module is available to the client package's Vite config._
602
653
 
603
654
  During development, the plugin watches the server module and the files it imports. When one of those files changes, fate updates the internal client wiring and invalidates `@nkzw/fate/client` in Vite's module graph.
604
655
 
605
- For a barebones client without React, import the plugin from `@nkzw/fate/vite` and the client APIs from `@nkzw/fate/client`. The plugin wires the same server types for the selected import path.
656
+ For a barebones client without a framework adapter, import the plugin from `@nkzw/fate/vite` and the client APIs from `@nkzw/fate/client`. The plugin wires the same server types for the selected import path.
606
657
 
607
658
  The plugin writes project-local types under `.fate/`. If your TypeScript config does not already include dot-directories, extend the generated config:
608
659
 
@@ -614,9 +665,11 @@ The plugin writes project-local types under `.fate/`. If your TypeScript config
614
665
 
615
666
  ## Creating a _fate_ Client
616
667
 
617
- Now that the Vite plugin has connected the types, create a fate client instance and provide it to your React app with the `FateClient` context provider:
668
+ Now that the Vite plugin has connected the types, create a fate client instance and provide it to your app with the `FateClient` provider:
618
669
 
619
- ```tsx
670
+ ::: code-group
671
+
672
+ ```tsx [React]
620
673
  import { httpBatchLink } from '@trpc/client';
621
674
  import { FateClient } from 'react-fate';
622
675
  import { createFateClient } from 'react-fate/client';
@@ -642,4 +695,37 @@ export function App() {
642
695
  }
643
696
  ```
644
697
 
698
+ ```vue [Vue]
699
+ <script setup lang="ts">
700
+ import { httpBatchLink } from '@trpc/client';
701
+ import { computed } from 'vue';
702
+ import { FateClient } from 'vue-fate';
703
+ import { createFateClient } from 'vue-fate/client';
704
+ import AppRoutes from './AppRoutes.vue';
705
+
706
+ const fate = computed(() =>
707
+ createFateClient({
708
+ links: [
709
+ httpBatchLink({
710
+ fetch: (input, init) =>
711
+ fetch(input, {
712
+ ...init,
713
+ credentials: 'include',
714
+ }),
715
+ url: `${env('SERVER_URL')}/trpc`,
716
+ }),
717
+ ],
718
+ }),
719
+ );
720
+ </script>
721
+
722
+ <template>
723
+ <FateClient :client="fate">
724
+ <AppRoutes />
725
+ </FateClient>
726
+ </template>
727
+ ```
728
+
729
+ :::
730
+
645
731
  _And you are all set. Happy building!_
@@ -7,15 +7,25 @@ setup without copying its adapter glue.
7
7
 
8
8
  ## Install
9
9
 
10
- ```sh
11
- pnpm add @nkzw/fate react-fate void-fate void
10
+ ::: code-group
11
+
12
+ ```sh [React]
13
+ pnpm add @nkzw/fate react-fate void-fate void @void/react
14
+ ```
15
+
16
+ ```sh [Vue]
17
+ pnpm add @nkzw/fate vue-fate void-fate void @void/vue
12
18
  ```
13
19
 
20
+ :::
21
+
14
22
  ## Vite
15
23
 
16
- Use the regular `react-fate` Vite plugin with the Void transport:
24
+ Use the framework adapter's Vite plugin with the Void transport:
17
25
 
18
- ```tsx
26
+ ::: code-group
27
+
28
+ ```tsx [React]
19
29
  import { voidReact } from '@void/react/plugin';
20
30
  import { fate } from 'react-fate/vite';
21
31
  import { defineConfig } from 'vite-plus';
@@ -33,6 +43,26 @@ export default defineConfig({
33
43
  });
34
44
  ```
35
45
 
46
+ ```ts [Vue]
47
+ import { voidVue } from '@void/vue/plugin';
48
+ import { fate } from 'vue-fate/vite';
49
+ import { defineConfig } from 'vite-plus';
50
+ import { voidPlugin } from 'void';
51
+
52
+ export default defineConfig({
53
+ plugins: [
54
+ voidPlugin(),
55
+ voidVue(),
56
+ fate({
57
+ module: './src/fate/server.ts',
58
+ transport: 'void',
59
+ }),
60
+ ],
61
+ });
62
+ ```
63
+
64
+ :::
65
+
36
66
  The Void transport uses `/fate` for RPC requests and `/fate-live` for live
37
67
  updates by default. In SSR, it calls the exported fate server directly. In the
38
68
  browser, it uses fetch and the SSE live endpoint.
@@ -104,12 +134,14 @@ export const { GET, POST } = defineVoidFateLiveRoute(fateServer, fateLive);
104
134
  The live route handles `GET /fate-live` SSE connections and `POST /fate-live`
105
135
  control messages. `void-fate` does not use WebSockets.
106
136
 
107
- ## React Layout
137
+ ## Layout
108
138
 
109
- Wrap your app with `VoidFateClient` from `void-fate/react`. It creates and
110
- provides the fate client through `react-fate`:
139
+ Wrap your app with the Void fate client for your framework. It creates and
140
+ provides the fate client through the matching adapter.
111
141
 
112
- ```tsx
142
+ ::: code-group
143
+
144
+ ```tsx [React]
113
145
  import { useShared } from '@void/react';
114
146
  import type { ReactNode } from 'react';
115
147
  import { VoidFateClient } from 'void-fate/react';
@@ -128,9 +160,36 @@ export default function Layout({ children }: { children: ReactNode }) {
128
160
  }
129
161
  ```
130
162
 
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.
163
+ ```vue [Vue]
164
+ <script setup lang="ts">
165
+ import { useShared } from '@void/vue';
166
+ import { computed } from 'vue';
167
+ import { FateClient } from 'vue-fate';
168
+ import { createFateClient } from 'vue-fate/client';
169
+ import type { SharedData } from '../src/lib/shared.ts';
170
+
171
+ const shared = useShared<SharedData>();
172
+
173
+ const fate = computed(() =>
174
+ createFateClient({
175
+ origin: typeof window === 'undefined' ? shared.origin : window.location.origin,
176
+ userId: shared.auth.user?.id,
177
+ }),
178
+ );
179
+ </script>
180
+
181
+ <template>
182
+ <FateClient :client="fate">
183
+ <slot />
184
+ </FateClient>
185
+ </template>
186
+ ```
187
+
188
+ :::
189
+
190
+ `userId` is optional, but passing it lets the client be recreated when the
191
+ signed-in user changes. Browser requests include credentials when a `userId` is
192
+ present.
134
193
 
135
194
  ## Custom Paths
136
195
 
@@ -143,12 +202,35 @@ export const fateLive = createVoidFateLive({
143
202
  });
144
203
  ```
145
204
 
146
- ```tsx
205
+ ::: code-group
206
+
207
+ ```tsx [React]
147
208
  <VoidFateClient livePath="/custom-fate-live" origin={origin} rpcPath="/custom-fate" userId={userId}>
148
209
  {children}
149
210
  </VoidFateClient>
150
211
  ```
151
212
 
213
+ ```vue [Vue]
214
+ <script setup lang="ts">
215
+ const fate = computed(() =>
216
+ createFateClient({
217
+ livePath: '/custom-fate-live',
218
+ origin,
219
+ rpcPath: '/custom-fate',
220
+ userId,
221
+ }),
222
+ );
223
+ </script>
224
+
225
+ <template>
226
+ <FateClient :client="fate">
227
+ <slot />
228
+ </FateClient>
229
+ </template>
230
+ ```
231
+
232
+ :::
233
+
152
234
  The route helper does not own the route path. Make sure your Void route filename
153
235
  or router configuration matches the paths you pass to the client.
154
236
 
@@ -1,4 +1,4 @@
1
- import { Z as QueryProcedure, r as AnyRecord } from "./transport-BTgtSwOM.mjs";
1
+ import { r as AnyRecord, rt as QueryProcedure } from "./transport-BjGm__3t.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/server/dataView.d.ts
@@ -1,4 +1,4 @@
1
- import { E as TypeConfig, s as Entity, t as Transport, v as MutationShape } from "./transport-BTgtSwOM.mjs";
1
+ import { C as MutationShape, f as Entity, j as TypeConfig, t as Transport } from "./transport-BjGm__3t.mjs";
2
2
 
3
3
  //#region src/graphqlTransport.d.ts
4
4
  type TransportMutations = Record<string, MutationShape>;
@@ -1,2 +1,2 @@
1
- import { a as GraphQLTransportOptions, i as GraphQLMutationOutput, n as GraphQLMutationInput, o as createGraphQLTransport, r as GraphQLMutationMap, s as graphqlMutation, t as GraphQLMutationDefinition } from "./graphqlTransport-DbRHbYtb.mjs";
1
+ import { a as GraphQLTransportOptions, i as GraphQLMutationOutput, n as GraphQLMutationInput, o as createGraphQLTransport, r as GraphQLMutationMap, s as graphqlMutation, t as GraphQLMutationDefinition } from "./graphqlTransport-B3cbhvJX.mjs";
2
2
  export { GraphQLMutationDefinition, GraphQLMutationInput, GraphQLMutationMap, GraphQLMutationOutput, GraphQLTransportOptions, createGraphQLTransport, graphqlMutation };
package/lib/index.d.mts CHANGED
@@ -1,8 +1,13 @@
1
- import { A as ViewEntity, B as mutation, C as RootDefinition, D as TypeName, E as TypeConfig, F as ViewTag, G as getSelectionPlan, H as RequestMode, I as __FateEntityBrand, J as HydrationLimits, K as FateDehydratedState, L as __FateSelectionBrand, M as ViewRef, N as ViewSelection, O as View, P as ViewSnapshot, R as isViewTag, S as RequestResult, T as Snapshot, U as RequestOptions, V as FateClient, W as createClient, Y as List, _ as MutationResult, a as ConnectionRef, b as Pagination, c as EntityId, d as ListItem, f as Mask, g as MutationInput, h as MutationIdentifier, i as ConnectionMetadata, j as ViewEntityName, k as ViewData, l as FateRoots, m as MutationEntity, n as createTRPCTransport, o as ConnectionTag, p as MutationDefinition, q as HydrateOptions, r as AnyRecord, s as Entity, t as Transport, u as FateThenable, v as MutationShape, w as Selection, x as Request$1, y as NodesItem, z as FateMutations } from "./transport-BTgtSwOM.mjs";
2
- import { a as GraphQLTransportOptions, i as GraphQLMutationOutput, n as GraphQLMutationInput, o as createGraphQLTransport, r as GraphQLMutationMap, s as graphqlMutation, t as GraphQLMutationDefinition } from "./graphqlTransport-DbRHbYtb.mjs";
3
- import { C as liveGlobalConnectionTopic, S as liveEntityTopic, a as FateProtocolRequest, i as FateOperation, n as FateLiveConnectionEvent, o as FateProtocolResponse, r as FateLiveEvent, t as isRecord, u as InferFateAPI, x as liveConnectionTopic } from "./record-BtdKzEGI.mjs";
4
- import { n as getListEntries, t as ListEntry } from "./list-CMQOQGdn.mjs";
1
+ import { $ as HydrateOptions, A as Snapshot, B as ViewTag, C as MutationShape, D as RequestResult, E as Request$1, F as ViewEntity, G as mutation, H as __FateSelectionBrand, I as ViewEntityName, J as RequestMode, K as DeferredSnapshot, L as ViewRef, M as TypeName, N as View, O as RootDefinition, P as ViewData, Q as FateDehydratedState, R as ViewSelection, S as MutationResult, T as Pagination, U as isViewTag, V as __FateEntityBrand, W as FateMutations, X as createClient, Y as RequestOptions, Z as getSelectionPlan, _ as Mask, a as ConnectionRef, b as MutationIdentifier, c as Deferred, d as DeferredTag, et as HydrationLimits, f as Entity, g as ListItem, h as FateThenable, i as ConnectionMetadata, j as TypeConfig, k as Selection, l as DeferredMetadata, m as FateRoots, n as createTRPCTransport, o as ConnectionTag, p as EntityId, q as FateClient, r as AnyRecord, s as DeferTag, t as Transport, tt as List, u as DeferredSelection, v as MutationDefinition, w as NodesItem, x as MutationInput, y as MutationEntity, z as ViewSnapshot } from "./transport-BjGm__3t.mjs";
2
+ import { a as GraphQLTransportOptions, i as GraphQLMutationOutput, n as GraphQLMutationInput, o as createGraphQLTransport, r as GraphQLMutationMap, s as graphqlMutation, t as GraphQLMutationDefinition } from "./graphqlTransport-B3cbhvJX.mjs";
3
+ import { C as liveGlobalConnectionTopic, S as liveEntityTopic, a as FateProtocolRequest, i as FateOperation, n as FateLiveConnectionEvent, o as FateProtocolResponse, r as FateLiveEvent, t as isRecord, u as InferFateAPI, x as liveConnectionTopic } from "./record-BkvZwvFk.mjs";
4
+ import { n as getListEntries, t as ListEntry } from "./list-BrL6PD_6.mjs";
5
5
 
6
+ //#region src/defer.d.ts
7
+ declare function defer<S>(selection: S): DeferredSelection<S>;
8
+ declare const isDeferred: (value: unknown) => value is Deferred<unknown>;
9
+ declare const getDeferredMetadata: <T>(deferred: Deferred<T>) => DeferredMetadata;
10
+ //#endregion
6
11
  //#region src/httpTransport.d.ts
7
12
  type TransportMutations = Record<string, MutationShape>;
8
13
  type EmptyTransportMutations = Record<never, MutationShape>;
@@ -88,4 +93,4 @@ type SelectionValidation<T extends Entity, S extends Selection<T>> = Exclude<key
88
93
  */
89
94
  declare function view<T extends Entity>(): <S extends Selection<T>>(select: S & SelectionValidation<T, S>) => View<T, S>;
90
95
  //#endregion
91
- export { type ConnectionMetadata, type ConnectionRef, ConnectionTag, type Entity, type EntityId, FateClient, type FateDehydratedState, type FateLiveConnectionEvent, type FateLiveEvent, type FateMutations, type FateOperation, type FateProtocolRequest, type FateProtocolResponse, type AnyRecord as FateRecord, type FateRoots, type FateThenable, type GraphQLMutationDefinition, type GraphQLMutationInput, type GraphQLMutationMap, type GraphQLMutationOutput, type GraphQLTransportOptions, type HydrateOptions, type HydrationLimits, type InferFateAPI, type List, type ListEntry, type ListItem, type Mask, type MutationDefinition, type MutationEntity, type MutationIdentifier, type MutationInput, type MutationResult, type NodesItem, type Pagination, type Request$1 as Request, type RequestMode, type RequestOptions, type RequestResult, type Selection, type Snapshot, type Transport, type TypeConfig, type View, type ViewData, type ViewEntity, type ViewEntityName, type ViewRef, type ViewSelection, type ViewSnapshot, type ViewTag, clientRoot, createClient, createGraphQLTransport, createHTTPTransport, createTRPCTransport, getListEntries, getSelectionPlan, graphqlMutation, isRecord, isViewTag, liveConnectionTopic, liveEntityTopic, liveGlobalConnectionTopic, mutation, toEntityId, view };
96
+ export { type ConnectionMetadata, type ConnectionRef, ConnectionTag, DeferTag, type Deferred, type DeferredMetadata, type DeferredSelection, type DeferredSnapshot, DeferredTag, type Entity, type EntityId, FateClient, type FateDehydratedState, type FateLiveConnectionEvent, type FateLiveEvent, type FateMutations, type FateOperation, type FateProtocolRequest, type FateProtocolResponse, type AnyRecord as FateRecord, type FateRoots, type FateThenable, type GraphQLMutationDefinition, type GraphQLMutationInput, type GraphQLMutationMap, type GraphQLMutationOutput, type GraphQLTransportOptions, type HydrateOptions, type HydrationLimits, type InferFateAPI, type List, type ListEntry, type ListItem, type Mask, type MutationDefinition, type MutationEntity, type MutationIdentifier, type MutationInput, type MutationResult, type NodesItem, type Pagination, type Request$1 as Request, type RequestMode, type RequestOptions, type RequestResult, type Selection, type Snapshot, type Transport, type TypeConfig, type View, type ViewData, type ViewEntity, type ViewEntityName, type ViewRef, type ViewSelection, type ViewSnapshot, type ViewTag, clientRoot, createClient, createGraphQLTransport, createHTTPTransport, createTRPCTransport, defer, getDeferredMetadata, getListEntries, getSelectionPlan, graphqlMutation, isDeferred, isRecord, isViewTag, liveConnectionTopic, liveEntityTopic, liveGlobalConnectionTopic, mutation, toEntityId, view };
package/lib/index.mjs CHANGED
@@ -78,6 +78,10 @@ const ViewsTag = Symbol("__fate__views");
78
78
  const NodeRefTag = Symbol("__fate__node-ref");
79
79
  /** Symbol attached to connection results so pagination helpers can find their metadata. */
80
80
  const ConnectionTag = Symbol("__fate__connection");
81
+ /** Symbol used to mark a selection as deferred. */
82
+ const DeferTag = Symbol("__fate__defer");
83
+ /** Symbol attached to deferred values returned from masked views. */
84
+ const DeferredTag = Symbol("__fate__deferred");
81
85
  const viewTag = "__fate-view__";
82
86
  /** Generates a stable view tag for a view definition. */
83
87
  function getViewTag(id) {
@@ -104,6 +108,16 @@ const RootKind = "__fate__root";
104
108
  /** Brand used on mutation definitions to mark their identity in the d.ts output. */
105
109
  const MutationKind = "__fate__mutation";
106
110
  //#endregion
111
+ //#region src/defer.ts
112
+ function defer(selection) {
113
+ return Object.freeze({ [DeferTag]: selection });
114
+ }
115
+ const isDeferredSelection = (value) => typeof value === "object" && value !== null && DeferTag in value;
116
+ const getDeferredSelection = (selection) => selection[DeferTag];
117
+ const createDeferred = (metadata) => Object.freeze({ [DeferredTag]: metadata });
118
+ const isDeferred = (value) => typeof value === "object" && value !== null && DeferredTag in value;
119
+ const getDeferredMetadata = (deferred) => deferred[DeferredTag];
120
+ //#endregion
107
121
  //#region src/node-ref.ts
108
122
  function createNodeRef(id) {
109
123
  const ref = {};
@@ -706,6 +720,7 @@ const getSelectionPlan = (viewComposition, ref) => {
706
720
  if (value) paths.add(path);
707
721
  continue;
708
722
  }
723
+ if (isDeferredSelection(value)) continue;
709
724
  if (isViewTag(key)) {
710
725
  if (!ref || ref[ViewsTag] && ref[ViewsTag].has(key)) walk(value.select, prefix);
711
726
  continue;
@@ -743,6 +758,9 @@ const getSelectionPlan = (viewComposition, ref) => {
743
758
  paths
744
759
  };
745
760
  };
761
+ const getDeferredSelectionPlan = (field, selection) => {
762
+ return getSelectionPlan({ [field]: selection }, null);
763
+ };
746
764
  //#endregion
747
765
  //#region src/mutation.ts
748
766
  /**
@@ -1796,6 +1814,7 @@ var FateClient = class {
1796
1814
  this.parentLists = /* @__PURE__ */ new Map();
1797
1815
  this.rootLists = /* @__PURE__ */ new Map();
1798
1816
  this.pending = /* @__PURE__ */ new Map();
1817
+ this.pendingDeferred = /* @__PURE__ */ new Map();
1799
1818
  this.pendingOptimisticMutations = /* @__PURE__ */ new Map();
1800
1819
  this.optimisticMasks = /* @__PURE__ */ new Map();
1801
1820
  this.optimisticByEntity = /* @__PURE__ */ new Map();
@@ -2095,6 +2114,63 @@ var FateClient = class {
2095
2114
  }
2096
2115
  return resolveSnapshot();
2097
2116
  }
2117
+ readDeferred(deferred) {
2118
+ const metadata = getDeferredMetadata(deferred);
2119
+ const resolvedOwner = this.optimisticEntityResolutions.get(metadata.owner) ?? metadata.owner;
2120
+ const parsedOwner = parseEntityId(resolvedOwner);
2121
+ const ownerRecord = this.store.read(resolvedOwner);
2122
+ const rawOwnerId = ownerRecord && (typeof ownerRecord.id === "string" || typeof ownerRecord.id === "number") ? ownerRecord.id : parsedOwner.id;
2123
+ const ownerType = parsedOwner.type || metadata.type;
2124
+ const plan = getDeferredSelectionPlan(metadata.field, metadata.selection);
2125
+ const selectedPaths = plan.paths;
2126
+ const missing = this.store.missingForSelection(resolvedOwner, selectedPaths);
2127
+ const hasMissingList = () => this.hasMissingDeferredList(resolvedOwner, ownerType, metadata.field, plan);
2128
+ const listMissing = hasMissingList();
2129
+ const fetchPaths = listMissing ? selectedPaths : missing;
2130
+ const resolveSnapshot = () => {
2131
+ const snapshot = this.readViewSelection({ [metadata.field]: metadata.selection }, this.stableRefWithViewNames(ownerType, rawOwnerId, /* @__PURE__ */ new Set()), resolvedOwner, plan);
2132
+ const resolved = {
2133
+ coverage: snapshot.coverage,
2134
+ data: snapshot.data[metadata.field]
2135
+ };
2136
+ return {
2137
+ status: "fulfilled",
2138
+ then: (onfulfilled, onrejected) => Promise.resolve(resolved).then(onfulfilled, onrejected),
2139
+ value: resolved
2140
+ };
2141
+ };
2142
+ if (missing.size === 0 && !listMissing) {
2143
+ this.clearStalledRequestsForEntity(resolvedOwner);
2144
+ return resolveSnapshot();
2145
+ }
2146
+ const key = this.deferredPendingKey(resolvedOwner, fetchPaths, plan, this.deferredSelectionSignature(metadata.selection));
2147
+ if (this.stalledRequests.has(key)) return resolveSnapshot();
2148
+ const pendingOptimistic = this.getPendingOptimisticMutations(resolvedOwner);
2149
+ if (pendingOptimistic) {
2150
+ const pending = this.pendingDeferred.get(key);
2151
+ if (pending) return pending;
2152
+ const promise = Promise.all(pendingOptimistic).then(() => this.readDeferred(deferred)).finally(() => this.pendingDeferred.delete(key));
2153
+ this.pendingDeferred.set(key, promise);
2154
+ return promise;
2155
+ }
2156
+ const pendingPromise = this.pendingDeferred.get(key) || null;
2157
+ if (pendingPromise) return pendingPromise;
2158
+ const promise = this.trackPendingRequest(async () => {
2159
+ try {
2160
+ await this.fetchByIdAndNormalize(ownerType, [rawOwnerId], fetchPaths, plan);
2161
+ if (this.store.missingForSelection(resolvedOwner, selectedPaths).size > 0 || hasMissingList()) {
2162
+ this.stalledRequests.add(key);
2163
+ return resolveSnapshot().value;
2164
+ }
2165
+ this.stalledRequests.delete(key);
2166
+ return this.readDeferred(deferred).value;
2167
+ } finally {
2168
+ this.pendingDeferred.delete(key);
2169
+ }
2170
+ });
2171
+ this.pendingDeferred.set(key, promise);
2172
+ return promise;
2173
+ }
2098
2174
  assertLiveViewSupport() {
2099
2175
  if (!this.transport.subscribeById) throw new Error(`fate: transport does not support live views. Please provide a 'subscribeById' implementation in your transport.`);
2100
2176
  }
@@ -3138,8 +3214,20 @@ var FateClient = class {
3138
3214
  target[ViewsTag].add(key);
3139
3215
  continue;
3140
3216
  }
3141
- coverageById.set(parentId, (coverageById.get(parentId) ?? /* @__PURE__ */ new Set()).add(key));
3142
3217
  const fieldPath = prefix ? `${prefix}.${key}` : key;
3218
+ if (isDeferredSelection(selectionKind)) {
3219
+ const { id, type } = parseEntityId(parentId);
3220
+ coverageById.set(parentId, (coverageById.get(parentId) ?? /* @__PURE__ */ new Set()).add(key));
3221
+ target[key] = createDeferred({
3222
+ field: key,
3223
+ id,
3224
+ owner: parentId,
3225
+ selection: getDeferredSelection(selectionKind),
3226
+ type
3227
+ });
3228
+ continue;
3229
+ }
3230
+ coverageById.set(parentId, (coverageById.get(parentId) ?? /* @__PURE__ */ new Set()).add(key));
3143
3231
  const selectionType = typeof selectionKind;
3144
3232
  if (selectionType === "boolean" && selectionKind) target[key] = record[key];
3145
3233
  else if (selectionKind && selectionType === "object") {
@@ -3258,7 +3346,9 @@ var FateClient = class {
3258
3346
  }
3259
3347
  };
3260
3348
  const data = { __typename: parseEntityId(entityId).type };
3261
- for (const viewPayload of getViewPayloads(viewComposition, ref)) walk(viewPayload.select, record, data, entityId, pathPrefix);
3349
+ const payloads = getViewPayloads(viewComposition, ref);
3350
+ if (payloads.length === 0 && isRecord(viewComposition)) walk(viewComposition, record, data, entityId, pathPrefix);
3351
+ else for (const viewPayload of payloads) walk(viewPayload.select, record, data, entityId, pathPrefix);
3262
3352
  return {
3263
3353
  coverage: [...coverageById.entries()],
3264
3354
  data
@@ -3274,6 +3364,32 @@ var FateClient = class {
3274
3364
  pendingKey(entityId, missingFields) {
3275
3365
  return `${this.pendingPrefix(entityId)}${[...missingFields].sort().join("|")}`;
3276
3366
  }
3367
+ deferredPendingKey(entityId, fields, plan, selectionSignature) {
3368
+ const args = [...plan.args.entries()].map(([path, entry]) => `${path}:${entry.hash}`).sort().join("|");
3369
+ return `${this.pendingKey(entityId, new Set(fields))}|${args}|${selectionSignature}`;
3370
+ }
3371
+ deferredSelectionSignature(selection) {
3372
+ const seen = /* @__PURE__ */ new Set();
3373
+ const serialize = (value) => {
3374
+ if (value === null || typeof value !== "object") return `${typeof value}:${String(value)}`;
3375
+ if (seen.has(value)) return "[Circular]";
3376
+ seen.add(value);
3377
+ if (Array.isArray(value)) return `[${value.map((item) => serialize(item)).join(",")}]`;
3378
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => isViewTag(key) ? `view:${key}` : `${key}:${serialize(entry)}`).join(",")}}`;
3379
+ };
3380
+ return serialize(selection);
3381
+ }
3382
+ hasMissingDeferredList(owner, type, field, plan) {
3383
+ const descriptor = this.types.get(type)?.fields?.[field];
3384
+ if (!descriptor || descriptor === "scalar" || !("listOf" in descriptor)) return false;
3385
+ const fieldArgs = plan.args.get(field);
3386
+ const listState = this.store.getListState(getListKey(owner, field, fieldArgs?.hash));
3387
+ if (!listState) return true;
3388
+ const args = fieldArgs?.value;
3389
+ const paginationArgs = getPaginationArgsInfo(args);
3390
+ if (paginationArgs.hasCursorArg) return true;
3391
+ return !hasConnectionPageCoverage(listState, args, paginationArgs.direction);
3392
+ }
3277
3393
  liveSubscriptionKey(entityId, plan) {
3278
3394
  return `${entityId}|${[...plan.paths].sort().join("|")}|${[...plan.args.entries()].map(([path, entry]) => `${path}:${entry.hash}`).sort().join("|")}`;
3279
3395
  }
@@ -3808,4 +3924,4 @@ function clientRoot(type) {
3808
3924
  });
3809
3925
  }
3810
3926
  //#endregion
3811
- export { ConnectionTag, FateClient, clientRoot, createClient, createGraphQLTransport, createHTTPTransport, createTRPCTransport, getListEntries, getSelectionPlan, graphqlMutation, isRecord, isViewTag, liveConnectionTopic, liveEntityTopic, liveGlobalConnectionTopic, mutation, toEntityId, view };
3927
+ export { ConnectionTag, DeferTag, DeferredTag, FateClient, clientRoot, createClient, createGraphQLTransport, createHTTPTransport, createTRPCTransport, defer, getDeferredMetadata, getListEntries, getSelectionPlan, graphqlMutation, isDeferred, isRecord, isViewTag, liveConnectionTopic, liveEntityTopic, liveGlobalConnectionTopic, mutation, toEntityId, view };
@@ -1,4 +1,4 @@
1
- import { Y as List, c as EntityId } from "./transport-BTgtSwOM.mjs";
1
+ import { p as EntityId, tt as List } from "./transport-BjGm__3t.mjs";
2
2
 
3
3
  //#region src/list.d.ts
4
4
  type ListEntry = Readonly<{