react-fate 1.2.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/docs/api/functions/FateClient.md +1 -1
- package/docs/api/functions/useFateClient.md +1 -1
- package/docs/api/functions/useListView.md +1 -1
- package/docs/api/functions/useLiveListView.md +1 -1
- package/docs/api/functions/useLiveView.md +2 -2
- package/docs/api/functions/useRequest.md +1 -1
- package/docs/api/functions/useView.md +3 -3
- package/docs/integrations/cloudflare.md +143 -0
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **FateClient**(`__namedParameters`): `Element`
|
|
4
4
|
|
|
5
|
-
Defined in: [packages/react-fate/src/context.tsx:17](https://github.com/nkzw-tech/fate/blob/
|
|
5
|
+
Defined in: [packages/react-fate/src/context.tsx:17](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/context.tsx#L17)
|
|
6
6
|
|
|
7
7
|
Provider component that supplies a configured `FateClient` to React hooks.
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **useFateClient**\<`T`\>(): `FateClient`\<`T`\[`0`\], `T`\[`1`\]\>
|
|
4
4
|
|
|
5
|
-
Defined in: [packages/react-fate/src/context.tsx:30](https://github.com/nkzw-tech/fate/blob/
|
|
5
|
+
Defined in: [packages/react-fate/src/context.tsx:30](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/context.tsx#L30)
|
|
6
6
|
|
|
7
7
|
Returns the nearest `FateClient` from context.
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **useListView**\<`C`\>(`selection`, `connection`): \[`ConnectionItems`\<`ResolvedConnection`\<`C`\>\>, `LoadMoreFn` \| `null`, `LoadMoreFn` \| `null`\]
|
|
4
4
|
|
|
5
|
-
Defined in: [packages/react-fate/src/useListView.tsx:19](https://github.com/nkzw-tech/fate/blob/
|
|
5
|
+
Defined in: [packages/react-fate/src/useListView.tsx:19](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useListView.tsx#L19)
|
|
6
6
|
|
|
7
7
|
Subscribes to a connection field, returning the current items and pagination
|
|
8
8
|
helpers to load the next or previous page.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **useLiveListView**\<`C`\>(`selection`, `connection`): \[`ConnectionItems`\<`ResolvedConnection`\<`C`\>\>, `LoadMoreFn` \| `null`, `LoadMoreFn` \| `null`\]
|
|
4
4
|
|
|
5
|
-
Defined in: [packages/react-fate/src/useLiveListView.tsx:19](https://github.com/nkzw-tech/fate/blob/
|
|
5
|
+
Defined in: [packages/react-fate/src/useLiveListView.tsx:19](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useLiveListView.tsx#L19)
|
|
6
6
|
|
|
7
7
|
Subscribes to a connection field, returning live-updating items and pagination
|
|
8
8
|
helpers to load the next or previous page.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> **useLiveView**\<`V`, `R`\>(`view`, `ref`): `R` *extends* `null` ? `null` : `Readonly`\<`ViewSelection`\<`V`\> *extends* `Selection`\<`ViewEntityWithTypename`\<`V`\>\> ? `Mask`\<`ViewEntityWithTypename`\<`V`\>, \{ \[K in string \| number \| symbol as K extends "\_\_typename" ? never : K\]?: DeferrableSelectionFieldValue\<ViewEntityWithTypename\<V\>, K\> \} & `object` & `SelectionViewSpread`\<`ViewEntityWithTypename`\<`V`\>\> & `ViewSelection`\<`V`\>\> : `ViewEntityWithTypename`\<`V`\> & `object`\>
|
|
6
6
|
|
|
7
|
-
Defined in: [packages/react-fate/src/useLiveView.tsx:27](https://github.com/nkzw-tech/fate/blob/
|
|
7
|
+
Defined in: [packages/react-fate/src/useLiveView.tsx:27](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useLiveView.tsx#L27)
|
|
8
8
|
|
|
9
9
|
Resolves a reference against a view and subscribes to live server updates for
|
|
10
10
|
that selection.
|
|
@@ -43,7 +43,7 @@ const post = useLiveView(PostView, postRef);
|
|
|
43
43
|
|
|
44
44
|
> **useLiveView**\<`V`, `R`\>(`view`, `ref`): `R` *extends* `null` ? `null` : `Readonly`\<`ViewSelection`\<`V`\> *extends* `Selection`\<`ViewEntityWithTypename`\<`V`\>\> ? `Mask`\<`ViewEntityWithTypename`\<`V`\>, \{ \[K in string \| number \| symbol as K extends "\_\_typename" ? never : K\]?: DeferrableSelectionFieldValue\<ViewEntityWithTypename\<V\>, K\> \} & `object` & `SelectionViewSpread`\<`ViewEntityWithTypename`\<`V`\>\> & `ViewSelection`\<`V`\>\> : `ViewEntityWithTypename`\<`V`\> & `object`\>
|
|
45
45
|
|
|
46
|
-
Defined in: [packages/react-fate/src/useLiveView.tsx:31](https://github.com/nkzw-tech/fate/blob/
|
|
46
|
+
Defined in: [packages/react-fate/src/useLiveView.tsx:31](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useLiveView.tsx#L31)
|
|
47
47
|
|
|
48
48
|
Resolves a reference against a view and subscribes to live server updates for
|
|
49
49
|
that selection.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **useRequest**\<`R`, `O`\>(`request`, `options?`): `RequestResult`\<`O`, `R`\>
|
|
4
4
|
|
|
5
|
-
Defined in: [packages/react-fate/src/useRequest.tsx:25](https://github.com/nkzw-tech/fate/blob/
|
|
5
|
+
Defined in: [packages/react-fate/src/useRequest.tsx:25](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useRequest.tsx#L25)
|
|
6
6
|
|
|
7
7
|
Declares the data a screen needs and kicks off fetching, suspending while the
|
|
8
8
|
request resolves.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> **useView**\<`V`, `R`\>(`view`, `ref`): `R` *extends* `null` ? `null` : `Readonly`\<`ViewSelection`\<`V`\> *extends* `Selection`\<`ViewEntityWithTypename`\<`V`\>\> ? `Mask`\<`ViewEntityWithTypename`\<`V`\>, \{ \[K in string \| number \| symbol as K extends "\_\_typename" ? never : K\]?: DeferrableSelectionFieldValue\<ViewEntityWithTypename\<V\>, K\> \} & `object` & `SelectionViewSpread`\<`ViewEntityWithTypename`\<`V`\>\> & `ViewSelection`\<`V`\>\> : `ViewEntityWithTypename`\<`V`\> & `object`\>
|
|
6
6
|
|
|
7
|
-
Defined in: [packages/react-fate/src/useView.tsx:40](https://github.com/nkzw-tech/fate/blob/
|
|
7
|
+
Defined in: [packages/react-fate/src/useView.tsx:40](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useView.tsx#L40)
|
|
8
8
|
|
|
9
9
|
Resolves a reference against a view and subscribes to updates for that selection.
|
|
10
10
|
|
|
@@ -42,7 +42,7 @@ const post = useView(PostView, postRef);
|
|
|
42
42
|
|
|
43
43
|
> **useView**\<`V`, `R`\>(`view`, `ref`): `R` *extends* `null` ? `null` : `Readonly`\<`ViewSelection`\<`V`\> *extends* `Selection`\<`ViewEntityWithTypename`\<`V`\>\> ? `Mask`\<`ViewEntityWithTypename`\<`V`\>, \{ \[K in string \| number \| symbol as K extends "\_\_typename" ? never : K\]?: DeferrableSelectionFieldValue\<ViewEntityWithTypename\<V\>, K\> \} & `object` & `SelectionViewSpread`\<`ViewEntityWithTypename`\<`V`\>\> & `ViewSelection`\<`V`\>\> : `ViewEntityWithTypename`\<`V`\> & `object`\>
|
|
44
44
|
|
|
45
|
-
Defined in: [packages/react-fate/src/useView.tsx:44](https://github.com/nkzw-tech/fate/blob/
|
|
45
|
+
Defined in: [packages/react-fate/src/useView.tsx:44](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useView.tsx#L44)
|
|
46
46
|
|
|
47
47
|
Resolves a reference against a view and subscribes to updates for that selection.
|
|
48
48
|
|
|
@@ -80,7 +80,7 @@ const post = useView(PostView, postRef);
|
|
|
80
80
|
|
|
81
81
|
> **useView**\<`V`\>(`view`, `ref`): `Readonly`\<`ViewSelection`\<`V`\> *extends* `Selection`\<`ViewEntityWithTypename`\<`V`\>\> ? `Mask`\<`ViewEntityWithTypename`\<`V`\>, \{ \[K in string \| number \| symbol as K extends "\_\_typename" ? never : K\]?: DeferrableSelectionFieldValue\<ViewEntityWithTypename\<V\>, K\> \} & `object` & `SelectionViewSpread`\<`ViewEntityWithTypename`\<`V`\>\> & `ViewSelection`\<`V`\>\> : `ViewEntityWithTypename`\<`V`\> & `object`\> \| `null`
|
|
82
82
|
|
|
83
|
-
Defined in: [packages/react-fate/src/useView.tsx:48](https://github.com/nkzw-tech/fate/blob/
|
|
83
|
+
Defined in: [packages/react-fate/src/useView.tsx:48](https://github.com/nkzw-tech/fate/blob/4876b00b02cd1ef9ae7fd82b8a3c27d82fc6c232/packages/react-fate/src/useView.tsx#L48)
|
|
84
84
|
|
|
85
85
|
Resolves a reference against a view and subscribes to updates for that selection.
|
|
86
86
|
|
|
@@ -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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-fate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "fate is a modern data client for React.",
|
|
5
5
|
"homepage": "https://github.com/nkzw-tech/fate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@nkzw/fate": "^1.
|
|
43
|
+
"@nkzw/fate": "^1.3.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/react": "^19.2.16",
|