@nkzw/fate 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +745 -24
- package/docs/api/classes/FateClient.md +63 -39
- package/docs/api/functions/clientRoot.md +1 -1
- package/docs/api/functions/createClient.md +1 -1
- package/docs/api/functions/createGraphQLTransport.md +1 -1
- package/docs/api/functions/createHTTPTransport.md +1 -1
- package/docs/api/functions/createTRPCTransport.md +1 -1
- package/docs/api/functions/defer.md +21 -0
- package/docs/api/functions/getDeferredMetadata.md +21 -0
- package/docs/api/functions/getListEntries.md +1 -1
- package/docs/api/functions/getSelectionPlan.md +1 -1
- package/docs/api/functions/graphqlMutation.md +1 -1
- package/docs/api/functions/isDeferred.md +15 -0
- package/docs/api/functions/isRecord.md +1 -1
- package/docs/api/functions/isViewTag.md +1 -1
- package/docs/api/functions/liveConnectionTopic.md +1 -1
- package/docs/api/functions/liveEntityTopic.md +1 -1
- package/docs/api/functions/liveGlobalConnectionTopic.md +1 -1
- package/docs/api/functions/mutation.md +1 -1
- package/docs/api/functions/toEntityId.md +1 -1
- package/docs/api/functions/view.md +1 -1
- package/docs/api/index.md +9 -0
- package/docs/api/interfaces/FateThenable.md +3 -3
- package/docs/api/interfaces/Transport.md +7 -7
- package/docs/api/server/classes/FateRequestError.md +5 -5
- package/docs/api/server/drizzle/functions/createDrizzleFate.md +1 -1
- package/docs/api/server/drizzle/functions/createDrizzleSourceAdapter.md +1 -1
- package/docs/api/server/drizzle/functions/createDrizzleSourceRegistry.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyConfig.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyInput.md +1 -1
- package/docs/api/server/drizzle/type-aliases/DrizzleQueryExtra.md +3 -3
- package/docs/api/server/drizzle/type-aliases/DrizzleSourceAdapter.md +9 -9
- package/docs/api/server/drizzle/type-aliases/DrizzleViewConfig.md +1 -1
- package/docs/api/server/functions/bindSourceProcedures.md +1 -1
- package/docs/api/server/functions/computed.md +1 -1
- package/docs/api/server/functions/count.md +1 -1
- package/docs/api/server/functions/createFateFetchHandler.md +1 -1
- package/docs/api/server/functions/createFateServer.md +1 -1
- package/docs/api/server/functions/createHonoFateHandler.md +1 -1
- package/docs/api/server/functions/createLiveEventBus.md +1 -1
- package/docs/api/server/functions/createNestedSourcePlan.md +1 -1
- package/docs/api/server/functions/createResolver.md +1 -1
- package/docs/api/server/functions/createSourcePlan.md +1 -1
- package/docs/api/server/functions/createSourceProcedures.md +1 -1
- package/docs/api/server/functions/dataView.md +1 -1
- package/docs/api/server/functions/field.md +1 -1
- package/docs/api/server/functions/getNestedSelection.md +1 -1
- package/docs/api/server/functions/getScopedArgs.md +1 -1
- package/docs/api/server/functions/hasNestedSelection.md +1 -1
- package/docs/api/server/functions/list.md +1 -1
- package/docs/api/server/functions/refetchSourceById.md +1 -1
- package/docs/api/server/functions/resolveSourceById.md +1 -1
- package/docs/api/server/functions/resolveSourceByIds.md +1 -1
- package/docs/api/server/functions/resolveSourceConnection.md +1 -1
- package/docs/api/server/functions/resolver.md +1 -1
- package/docs/api/server/functions/toPrismaSelect.md +1 -1
- package/docs/api/server/functions/withConnection.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaFate.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaSourceAdapter.md +1 -1
- package/docs/api/server/prisma/functions/createPrismaSourceRegistry.md +1 -1
- package/docs/api/server/prisma/functions/prismaConnectionArgs.md +1 -1
- package/docs/api/server/prisma/type-aliases/PrismaDelegate.md +4 -4
- package/docs/api/server/prisma/type-aliases/PrismaQueryExtra.md +1 -1
- package/docs/api/server/prisma/type-aliases/PrismaSourceAdapter.md +9 -9
- package/docs/api/server/prisma/type-aliases/PrismaViewConfig.md +1 -1
- package/docs/api/server/type-aliases/ComputedField.md +5 -5
- package/docs/api/server/type-aliases/ComputedSelection.md +1 -1
- package/docs/api/server/type-aliases/ConnectionItem.md +3 -3
- package/docs/api/server/type-aliases/ConnectionPagination.md +5 -5
- package/docs/api/server/type-aliases/ConnectionResult.md +3 -3
- package/docs/api/server/type-aliases/CountSelection.md +4 -4
- package/docs/api/server/type-aliases/CountWhere.md +1 -1
- package/docs/api/server/type-aliases/DataViewListOptions.md +2 -2
- package/docs/api/server/type-aliases/DataViewOrderBy.md +1 -1
- package/docs/api/server/type-aliases/DataViewOrderDirection.md +1 -1
- package/docs/api/server/type-aliases/DataViewResult.md +1 -1
- package/docs/api/server/type-aliases/Entity.md +1 -1
- package/docs/api/server/type-aliases/FateServer.md +5 -5
- package/docs/api/server/type-aliases/FateServerManifest.md +1 -1
- package/docs/api/server/type-aliases/FieldSelection.md +3 -3
- package/docs/api/server/type-aliases/LiveConnectionEventType.md +1 -1
- package/docs/api/server/type-aliases/LiveConnectionSourceEvent.md +1 -1
- package/docs/api/server/type-aliases/LiveEventBus.md +1 -1
- package/docs/api/server/type-aliases/LiveEventType.md +1 -1
- package/docs/api/server/type-aliases/LiveSourceEvent.md +1 -1
- package/docs/api/server/type-aliases/NativeFateAPI.md +4 -4
- package/docs/api/server/type-aliases/OrderDirection.md +1 -1
- package/docs/api/server/type-aliases/SourceConfig.md +6 -6
- package/docs/api/server/type-aliases/SourceDefinition.md +6 -6
- package/docs/api/server/type-aliases/SourceOrder.md +1 -1
- package/docs/api/server/type-aliases/SourceOrderField.md +3 -3
- package/docs/api/server/type-aliases/SourcePlan.md +1 -1
- package/docs/api/server/type-aliases/SourcePlanNode.md +1 -1
- package/docs/api/server/type-aliases/SourceRegistry.md +1 -1
- package/docs/api/server/type-aliases/SourceRelation.md +1 -1
- package/docs/api/server/type-aliases/SourceRelationConfig.md +1 -1
- package/docs/api/server/variables/byIdInput.md +1 -1
- package/docs/api/server/variables/connectionArgs.md +1 -1
- package/docs/api/type-aliases/ConnectionMetadata.md +1 -1
- package/docs/api/type-aliases/ConnectionRef.md +1 -1
- package/docs/api/type-aliases/Deferred.md +19 -0
- package/docs/api/type-aliases/DeferredMetadata.md +7 -0
- package/docs/api/type-aliases/DeferredSelection.md +13 -0
- package/docs/api/type-aliases/DeferredSnapshot.md +11 -0
- package/docs/api/type-aliases/Entity.md +2 -2
- package/docs/api/type-aliases/EntityId.md +1 -1
- package/docs/api/type-aliases/FateDehydratedState.md +1 -1
- package/docs/api/type-aliases/FateLiveConnectionEvent.md +1 -1
- package/docs/api/type-aliases/FateLiveEvent.md +1 -1
- package/docs/api/type-aliases/FateMutations.md +1 -1
- package/docs/api/type-aliases/FateOperation.md +1 -1
- package/docs/api/type-aliases/FateProtocolRequest.md +1 -1
- package/docs/api/type-aliases/FateProtocolResponse.md +1 -1
- package/docs/api/type-aliases/FateRecord.md +1 -1
- package/docs/api/type-aliases/FateRoots.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationDefinition.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationInput.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationMap.md +1 -1
- package/docs/api/type-aliases/GraphQLMutationOutput.md +1 -1
- package/docs/api/type-aliases/GraphQLTransportOptions.md +11 -11
- package/docs/api/type-aliases/HydrateOptions.md +1 -1
- package/docs/api/type-aliases/HydrationLimits.md +1 -1
- package/docs/api/type-aliases/InferFateAPI.md +1 -1
- package/docs/api/type-aliases/List.md +1 -1
- package/docs/api/type-aliases/ListEntry.md +1 -1
- package/docs/api/type-aliases/ListItem.md +1 -1
- package/docs/api/type-aliases/Mask.md +1 -1
- package/docs/api/type-aliases/MutationDefinition.md +1 -1
- package/docs/api/type-aliases/MutationEntity.md +1 -1
- package/docs/api/type-aliases/MutationIdentifier.md +1 -1
- package/docs/api/type-aliases/MutationInput.md +1 -1
- package/docs/api/type-aliases/MutationResult.md +1 -1
- package/docs/api/type-aliases/NodesItem.md +1 -1
- package/docs/api/type-aliases/Pagination.md +5 -5
- package/docs/api/type-aliases/Request.md +1 -1
- package/docs/api/type-aliases/RequestMode.md +1 -1
- package/docs/api/type-aliases/RequestOptions.md +1 -1
- package/docs/api/type-aliases/RequestResult.md +1 -1
- package/docs/api/type-aliases/Selection.md +1 -1
- package/docs/api/type-aliases/Snapshot.md +1 -1
- package/docs/api/type-aliases/TypeConfig.md +4 -4
- package/docs/api/type-aliases/View.md +1 -1
- package/docs/api/type-aliases/ViewData.md +1 -1
- package/docs/api/type-aliases/ViewEntity.md +1 -1
- package/docs/api/type-aliases/ViewEntityName.md +1 -1
- package/docs/api/type-aliases/ViewRef.md +1 -1
- package/docs/api/type-aliases/ViewSelection.md +1 -1
- package/docs/api/type-aliases/ViewSnapshot.md +1 -1
- package/docs/api/type-aliases/ViewTag.md +1 -1
- package/docs/api/variables/ConnectionTag.md +1 -1
- package/docs/api/variables/DeferTag.md +7 -0
- package/docs/api/variables/DeferredTag.md +7 -0
- package/docs/guide/actions.md +7 -7
- package/docs/guide/deferred-views.md +62 -0
- package/docs/guide/getting-started.md +21 -3
- package/docs/guide/vue.md +256 -0
- package/docs/index.md +1 -0
- package/docs/integrations/cloudflare.md +143 -0
- package/docs/{guide/graphql-integration.md → integrations/graphql.md} +53 -6
- package/docs/{guide/server-integration.md → integrations/server.md} +93 -7
- package/docs/{guide/void-integration.md → integrations/void.md} +94 -12
- package/lib/{executor-sLcAqDMs.d.mts → executor-Dh-MLUXc.d.mts} +1 -1
- package/lib/{graphqlTransport-DbRHbYtb.d.mts → graphqlTransport-B3cbhvJX.d.mts} +1 -1
- package/lib/graphqlTransport.d.mts +1 -1
- package/lib/index.d.mts +10 -5
- package/lib/index.mjs +119 -3
- package/lib/{list-CMQOQGdn.d.mts → list-BrL6PD_6.d.mts} +1 -1
- package/lib/list.d.mts +1 -1
- package/lib/{record-BtdKzEGI.d.mts → record-BkvZwvFk.d.mts} +2 -2
- package/lib/server/drizzle.d.mts +2 -2
- package/lib/server/prisma.d.mts +2 -2
- package/lib/server.d.mts +3 -3
- package/lib/{transport-BTgtSwOM.d.mts → transport-BjGm__3t.d.mts} +36 -3
- package/lib/vite.d.mts +2 -2
- package/lib/vite.mjs +27 -7
- package/package.json +1 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Cloudflare Integration
|
|
2
|
+
|
|
3
|
+
`cf-fate` is the first-class Cloudflare Workers adapter for Fate native HTTP transport and live views.
|
|
4
|
+
|
|
5
|
+
Use it when your backend runs directly on Cloudflare Workers and you want fate live views without adopting the Void platform.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @nkzw/fate react-fate cf-fate drizzle-orm
|
|
11
|
+
pnpm add -D wrangler
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Server Setup
|
|
15
|
+
|
|
16
|
+
Create a Cloudflare live stream and pass its Fate live facade to `createFateServer`.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// src/fate/live.ts
|
|
20
|
+
import { defineCloudflareFateLiveStream } from 'cf-fate/server';
|
|
21
|
+
|
|
22
|
+
export const fateStream = defineCloudflareFateLiveStream({
|
|
23
|
+
allowAnonymousControl: true,
|
|
24
|
+
binding: 'FATE_LIVE',
|
|
25
|
+
id: 'fate',
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// src/fate/server.ts
|
|
31
|
+
import { createFateServer } from '@nkzw/fate/server';
|
|
32
|
+
import { createCloudflareFateLive } from 'cf-fate/server';
|
|
33
|
+
|
|
34
|
+
export const fateLive = createCloudflareFateLive();
|
|
35
|
+
export const { live } = fateLive;
|
|
36
|
+
|
|
37
|
+
export const fateServer = createFateServer({
|
|
38
|
+
live,
|
|
39
|
+
// context,
|
|
40
|
+
// roots,
|
|
41
|
+
// sources,
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Publish from mutations through the normal Fate live bus:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
live.update('Post', postId, { changed: ['likes'] });
|
|
49
|
+
live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Worker Routes
|
|
53
|
+
|
|
54
|
+
Expose one route for Fate RPC and one route for the SSE live stream.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
createCloudflareFateLiveDurableObject,
|
|
59
|
+
defineCloudflareFateLiveRoute,
|
|
60
|
+
defineCloudflareFateRoute,
|
|
61
|
+
} from 'cf-fate/server';
|
|
62
|
+
import { fateStream } from './fate/live';
|
|
63
|
+
import { fateLive, fateServer } from './fate/server';
|
|
64
|
+
|
|
65
|
+
const fateRoute = defineCloudflareFateRoute(fateServer, fateLive, { stream: fateStream });
|
|
66
|
+
const fateLiveRoute = defineCloudflareFateLiveRoute(fateStream);
|
|
67
|
+
|
|
68
|
+
export const FateLiveDurableObject = createCloudflareFateLiveDurableObject({
|
|
69
|
+
binding: 'FATE_LIVE',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export default {
|
|
73
|
+
fetch(request, env, ctx) {
|
|
74
|
+
const url = new URL(request.url);
|
|
75
|
+
if (url.pathname === '/fate') {
|
|
76
|
+
return fateRoute.fetch(request, env, ctx);
|
|
77
|
+
}
|
|
78
|
+
if (url.pathname === '/fate-live') {
|
|
79
|
+
return fateLiveRoute.fetch(request, env, ctx);
|
|
80
|
+
}
|
|
81
|
+
return new Response('Not Found', { status: 404 });
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Wrangler
|
|
87
|
+
|
|
88
|
+
Add a Durable Object binding and migration. `cf-fate` uses `node:async_hooks`, so the Worker must enable Node compatibility.
|
|
89
|
+
|
|
90
|
+
```jsonc
|
|
91
|
+
{
|
|
92
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
93
|
+
"durable_objects": {
|
|
94
|
+
"bindings": [
|
|
95
|
+
{
|
|
96
|
+
"name": "FATE_LIVE",
|
|
97
|
+
"class_name": "FateLiveDurableObject",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
"migrations": [
|
|
102
|
+
{
|
|
103
|
+
"tag": "fate-live-v1",
|
|
104
|
+
"new_sqlite_classes": ["FateLiveDurableObject"],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Client
|
|
111
|
+
|
|
112
|
+
Use the Cloudflare transport in the Fate Vite plugin:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { fate } from 'react-fate/vite';
|
|
116
|
+
|
|
117
|
+
fate({
|
|
118
|
+
module: './src/fate/server.ts',
|
|
119
|
+
transport: 'cloudflare',
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Then point the generated client at the Worker endpoints:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { FateClient } from 'react-fate';
|
|
127
|
+
import { createFateClient } from 'react-fate/client';
|
|
128
|
+
|
|
129
|
+
const fate = createFateClient({
|
|
130
|
+
liveUrl: 'http://localhost:8787/fate-live',
|
|
131
|
+
url: 'http://localhost:8787/fate',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export function App({ children }) {
|
|
135
|
+
return <FateClient client={fate}>{children}</FateClient>;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Semantics
|
|
140
|
+
|
|
141
|
+
`cf-fate` uses one browser `EventSource` per Fate client and multiplexes entity and connection topics over that stream. Durable Objects keep connection and topic subscription state so later requests, mutations, scheduled handlers, and queue consumers can publish to already-connected clients.
|
|
142
|
+
|
|
143
|
+
Delivery is at-most-once. Events are ordered within one topic, but events are not durably replayed after a disconnect. Use authoritative refetching or application-owned replay storage if missed events must be recovered.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GraphQL Integration
|
|
2
2
|
|
|
3
|
-
_fate_ can use an existing GraphQL API as its transport. This keeps the
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
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
|
|
24
|
+
Use the framework adapter's Vite plugin with the Void transport:
|
|
17
25
|
|
|
18
|
-
|
|
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
|
-
##
|
|
137
|
+
## Layout
|
|
108
138
|
|
|
109
|
-
Wrap your app with
|
|
110
|
-
provides the fate client through
|
|
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
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
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 {
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
4
|
-
import { n as getListEntries, t as ListEntry } from "./list-
|
|
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 };
|