react-fate 1.5.2 → 1.6.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 (32) hide show
  1. package/README.md +51 -155
  2. package/docs/api/functions/FateClient.md +1 -1
  3. package/docs/api/functions/createClient.md +1 -1
  4. package/docs/api/functions/createGraphQLTransport.md +1 -1
  5. package/docs/api/functions/createTRPCTransport.md +1 -1
  6. package/docs/api/functions/graphqlMutation.md +1 -1
  7. package/docs/api/functions/mutation.md +1 -1
  8. package/docs/api/functions/useFateClient.md +1 -1
  9. package/docs/api/functions/useListView.md +1 -1
  10. package/docs/api/functions/useLiveListView.md +1 -1
  11. package/docs/api/functions/useLiveView.md +2 -2
  12. package/docs/api/functions/useRequest.md +1 -1
  13. package/docs/api/functions/useView.md +3 -3
  14. package/docs/api/interfaces/Persistence.md +1 -1
  15. package/docs/api/interfaces/PersistenceSession.md +9 -9
  16. package/docs/api/type-aliases/ConnectionRef.md +1 -1
  17. package/docs/api/type-aliases/Deferred.md +1 -1
  18. package/docs/api/type-aliases/FateDehydratedState.md +1 -1
  19. package/docs/api/type-aliases/GraphQLMutationDefinition.md +1 -1
  20. package/docs/api/type-aliases/GraphQLMutationInput.md +1 -1
  21. package/docs/api/type-aliases/GraphQLMutationMap.md +1 -1
  22. package/docs/api/type-aliases/GraphQLMutationOutput.md +1 -1
  23. package/docs/api/type-aliases/GraphQLTransportOptions.md +12 -12
  24. package/docs/api/type-aliases/HydrateOptions.md +1 -1
  25. package/docs/api/type-aliases/HydrationLimits.md +1 -1
  26. package/docs/api/type-aliases/InferFateAPI.md +1 -1
  27. package/docs/api/type-aliases/Pagination.md +5 -5
  28. package/docs/api/type-aliases/PersistenceSnapshot.md +1 -1
  29. package/docs/api/type-aliases/ViewRef.md +1 -1
  30. package/docs/integrations/cloudflare.md +21 -139
  31. package/docs/integrations/void.md +33 -19
  32. package/package.json +6 -6
package/README.md CHANGED
@@ -2995,7 +2995,7 @@ _And you are all set. Happy building!_
2995
2995
 
2996
2996
  ## Void Integration
2997
2997
 
2998
- `void-fate` is the first-class [Void](https://void.cloud) adapter for fate to ease integration with the Void SDK and for deploying to the Void platform.
2998
+ `void-fate` is the [Void](https://void.cloud) adapter for fate. Deploy your app directly to your own Cloudflare account or to the Void platform with the same integration.
2999
2999
 
3000
3000
  Use this integration when your app runs on Void and you want the example app's
3001
3001
  setup without copying its adapter glue.
@@ -3122,14 +3122,29 @@ live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId
3122
3122
 
3123
3123
  ### Routes
3124
3124
 
3125
+ Define a live stream once in a server-only module:
3126
+
3127
+ ```ts
3128
+ // src/fate/live.ts
3129
+ import { defineLiveStream } from 'void/live';
3130
+
3131
+ export const fateStream = defineLiveStream({
3132
+ allowAnonymousControl: true,
3133
+ id: 'fate',
3134
+ });
3135
+ ```
3136
+
3125
3137
  Add one route for fate RPC requests:
3126
3138
 
3127
3139
  ```tsx
3128
3140
  // routes/fate.ts
3129
3141
  import { defineVoidFateRoute } from 'void-fate/server';
3142
+ import { fateStream } from '../src/fate/live.ts';
3130
3143
  import { fateLive, fateServer } from '../src/fate/server.ts';
3131
3144
 
3132
- export const { GET, POST } = defineVoidFateRoute(fateServer, fateLive);
3145
+ export const { GET, POST } = defineVoidFateRoute(fateServer, fateLive, {
3146
+ stream: fateStream,
3147
+ });
3133
3148
  ```
3134
3149
 
3135
3150
  Add a second route for the live SSE transport:
@@ -3137,9 +3152,9 @@ Add a second route for the live SSE transport:
3137
3152
  ```tsx
3138
3153
  // routes/fate-live.ts
3139
3154
  import { defineVoidFateLiveRoute } from 'void-fate/server';
3140
- import { fateLive, fateServer } from '../src/fate/server.ts';
3155
+ import { fateStream } from '../src/fate/live.ts';
3141
3156
 
3142
- export const { GET, POST } = defineVoidFateLiveRoute(fateServer, fateLive);
3157
+ export const { GET, POST } = defineVoidFateLiveRoute(fateStream);
3143
3158
  ```
3144
3159
 
3145
3160
  The live route handles `GET /fate-live` SSE connections and `POST /fate-live`
@@ -3205,13 +3220,7 @@ present.
3205
3220
  ### Custom Paths
3206
3221
 
3207
3222
  The default route pair is `/fate` and `/fate-live`. If your Void app uses
3208
- different paths, configure the same values on the live adapter and client.
3209
-
3210
- ```tsx
3211
- export const fateLive = createVoidFateLive({
3212
- livePath: '/custom-fate-live',
3213
- });
3214
- ```
3223
+ different paths, update your route filenames and configure the matching client paths.
3215
3224
 
3216
3225
  ::: code-group
3217
3226
 
@@ -3247,179 +3256,66 @@ or router configuration matches the paths you pass to the client.
3247
3256
 
3248
3257
  ### Live Transport
3249
3258
 
3250
- Void can run separate request handlers for mutations and long-lived SSE
3251
- connections. `createVoidFateLive` bridges those handlers by publishing live
3252
- events from the request that changed data to the live route.
3253
-
3254
- In local development, `void-fate` uses a development token for that internal
3255
- publish request. Outside local development, Void must provide `__VOID_PROXY_TOKEN`
3256
- in the route environment. If no internal publish token is available, the adapter
3257
- falls back to the in-memory live bus for the current request context.
3259
+ `createVoidFateLive` publishes entity and connection events through the `void/live`
3260
+ stream associated with the current request. Void manages the Durable Object
3261
+ transport that distributes events to connected clients across requests.
3258
3262
 
3259
3263
  The live transport is best-effort and does not replay missed events after a
3260
3264
  client reconnects. This matches fate's default in-memory live event bus.
3261
3265
 
3262
- ## Cloudflare Integration
3263
-
3264
- `cf-fate` is the first-class Cloudflare Workers adapter for Fate native HTTP transport and live views.
3265
-
3266
- Use it when your backend runs directly on Cloudflare Workers and you want fate live views without adopting the Void platform.
3267
-
3268
- ### New Project
3266
+ ### Cloudflare Deployment
3269
3267
 
3270
- For a new Cloudflare Workers app, start from the Cloudflare template. It includes the client, Worker server, D1 migrations, Wrangler config, Durable Object live transport, auth wiring, and generated fate client setup.
3268
+ From your project root, run:
3271
3269
 
3272
3270
  ```sh
3273
- vp create fate my-app --template cloudflare
3271
+ vp exec void deploy --platform cloudflare
3274
3272
  ```
3275
3273
 
3276
- Use Vue instead of React with:
3274
+ Void provisions resources and deploys directly to your Cloudflare account. See the [Cloudflare integration](/docs/integrations/cloudflare.md) for setup and migration instructions.
3277
3275
 
3278
- ```sh
3279
- vp create fate my-app --template cloudflare --framework vue
3280
- ```
3276
+ ## Cloudflare Integration
3281
3277
 
3282
- ### Existing Project
3278
+ Deploy fate directly to your own Cloudflare account with [Void](/docs/integrations/void.md). The Void template includes the app, D1 database, Drizzle migrations, Better Auth, and live updates through `void-fate` and `void/live`.
3283
3279
 
3284
- For an existing Cloudflare Workers project, add the packages directly:
3280
+ ### New Project
3285
3281
 
3286
3282
  ```sh
3287
- pnpm add @nkzw/fate react-fate cf-fate drizzle-orm
3288
- pnpm add -D wrangler
3289
- ```
3290
-
3291
- For Vue clients, replace `react-fate` with `vue-fate`.
3292
-
3293
- ### Server Setup
3294
-
3295
- Create a Cloudflare live stream and pass its Fate live facade to `createFateServer`.
3296
-
3297
- ```ts
3298
- // src/fate/live.ts
3299
- import { defineCloudflareFateLiveStream } from 'cf-fate/server';
3300
-
3301
- export const fateStream = defineCloudflareFateLiveStream({
3302
- allowAnonymousControl: true,
3303
- binding: 'FATE_LIVE',
3304
- id: 'fate',
3305
- });
3306
- ```
3307
-
3308
- ```ts
3309
- // src/fate/server.ts
3310
- import { createFateServer } from '@nkzw/fate/server';
3311
- import { createCloudflareFateLive } from 'cf-fate/server';
3312
-
3313
- export const fateLive = createCloudflareFateLive();
3314
- export const { live } = fateLive;
3315
-
3316
- export const fateServer = createFateServer({
3317
- live,
3318
- // context,
3319
- // roots,
3320
- // sources,
3321
- });
3322
- ```
3323
-
3324
- Publish from mutations through the normal Fate live bus:
3325
-
3326
- ```ts
3327
- live.update('Post', postId, { changed: ['likes'] });
3328
- live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId);
3283
+ vp create fate my-app --template void
3284
+ cd my-app
3285
+ vp run dev:setup
3286
+ vp run dev
3329
3287
  ```
3330
3288
 
3331
- ### Worker Routes
3332
-
3333
- Expose one route for Fate RPC and one route for the SSE live stream.
3334
-
3335
- ```ts
3336
- import {
3337
- createCloudflareFateLiveDurableObject,
3338
- defineCloudflareFateLiveRoute,
3339
- defineCloudflareFateRoute,
3340
- } from 'cf-fate/server';
3341
- import { fateStream } from './fate/live';
3342
- import { fateLive, fateServer } from './fate/server';
3343
-
3344
- const fateRoute = defineCloudflareFateRoute(fateServer, fateLive, { stream: fateStream });
3345
- const fateLiveRoute = defineCloudflareFateLiveRoute(fateStream);
3346
-
3347
- export const FateLiveDurableObject = createCloudflareFateLiveDurableObject({
3348
- binding: 'FATE_LIVE',
3349
- });
3350
-
3351
- export default {
3352
- fetch(request, env, ctx) {
3353
- const url = new URL(request.url);
3354
- if (url.pathname === '/fate') {
3355
- return fateRoute.fetch(request, env, ctx);
3356
- }
3357
- if (url.pathname === '/fate-live') {
3358
- return fateLiveRoute.fetch(request, env, ctx);
3359
- }
3360
- return new Response('Not Found', { status: 404 });
3361
- },
3362
- };
3363
- ```
3289
+ Add `--framework vue` to the create command to use Vue instead of React.
3364
3290
 
3365
- ### Wrangler
3291
+ ### Deploy
3366
3292
 
3367
- Add a Durable Object binding and migration. `cf-fate` uses `node:async_hooks`, so the Worker must enable Node compatibility.
3293
+ From the project root:
3368
3294
 
3369
- ```jsonc
3370
- {
3371
- "compatibility_flags": ["nodejs_compat"],
3372
- "durable_objects": {
3373
- "bindings": [
3374
- {
3375
- "name": "FATE_LIVE",
3376
- "class_name": "FateLiveDurableObject",
3377
- },
3378
- ],
3379
- },
3380
- "migrations": [
3381
- {
3382
- "tag": "fate-live-v1",
3383
- "new_sqlite_classes": ["FateLiveDurableObject"],
3384
- },
3385
- ],
3386
- }
3295
+ ```sh
3296
+ vp exec void deploy --platform cloudflare
3387
3297
  ```
3388
3298
 
3389
- ### Client
3299
+ Void signs you into Cloudflare when needed, lets you select your account, provisions resources, applies checked-in database migrations, and deploys the app. It saves resource IDs in the root `wrangler.jsonc`; commit that updated config for subsequent deployments. A Void platform account is not required.
3390
3300
 
3391
- Use the Cloudflare transport in the Fate Vite plugin:
3301
+ The template includes the `VOID_LIVE` Durable Object binding and its class migration. Keep them in `wrangler.jsonc` so live subscriptions can receive updates across requests. RPC requests use `/fate`, and live updates use `/fate-live`.
3392
3302
 
3393
- ```ts
3394
- import { fate } from 'react-fate/vite';
3303
+ After changing your database schema or auth configuration, run `vp run db:generate`, review and commit the generated migrations, then deploy. The migrations must include the Better Auth schema used in production.
3395
3304
 
3396
- fate({
3397
- module: './src/fate/server.ts',
3398
- transport: 'cloudflare',
3399
- });
3400
- ```
3401
-
3402
- Then point the generated client at the Worker endpoints:
3403
-
3404
- ```tsx
3405
- import { FateClient } from 'react-fate';
3406
- import { createFateClient } from 'react-fate/client';
3305
+ See [Void's Cloudflare deployment guide](https://void.cloud/integrations/cloudflare) for custom domains, secrets, and CI configuration.
3407
3306
 
3408
- const fate = createFateClient({
3409
- liveUrl: 'http://localhost:8787/fate-live',
3410
- url: 'http://localhost:8787/fate',
3411
- });
3307
+ ### Migrating from cf-fate
3412
3308
 
3413
- export function App({ children }) {
3414
- return <FateClient client={fate}>{children}</FateClient>;
3415
- }
3416
- ```
3309
+ Fate 1.6 replaces the standalone Cloudflare adapter and template with the Void integration. Use `--template void` for new projects and `transport: 'void'` in the fate Vite plugin.
3417
3310
 
3418
- ### Semantics
3311
+ For an existing app, move the Worker routes into Void's `routes/` directory and follow the [Void integration](/docs/integrations/void.md) for the complete setup:
3419
3312
 
3420
- `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.
3313
+ - Define the live stream with `defineLiveStream` from `void/live`.
3314
+ - Use `createVoidFateLive`, `defineVoidFateRoute`, and `defineVoidFateLiveRoute` from `void-fate/server`.
3315
+ - Let the generated client use `void/live/client` for live connections.
3316
+ - Remove the `cf-fate` dependency and the custom Worker entry point.
3421
3317
 
3422
- 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.
3318
+ Deploy the Void app as a new Worker with its `VOID_LIVE` binding and class migration. The old `FATE_LIVE` Durable Object class and its active connections are not migrated. Preserve existing database IDs and migration history when reusing your database, and reconnect clients to the new app after deployment.
3423
3319
 
3424
3320
  ## Frequently Asked Questions
3425
3321
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **FateClient**(`__namedParameters`): `Element`
4
4
 
5
- Defined in: [react-fate/src/context.tsx:17](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/context.tsx#L17)
5
+ Defined in: [react-fate/src/context.tsx:17](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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
  > **createClient**\<`T`, `HydrationScope`\>(`options`): `FateClient`\<`T`\[`0`\], `T`\[`1`\], `HydrationScope`\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1457
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1457
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **createGraphQLTransport**\<`Mutations`\>(`__namedParameters`): `Transport`\<`Mutations`\>
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:62
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:62
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **createTRPCTransport**\<`AppRouter`, `Mutations`\>(`__namedParameters`): `Transport`\<`MutationMapFromResolvers`\<`Mutations`\>\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1606
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1606
6
6
 
7
7
  Builds a `Transport` backed by a tRPC client using the configured resolvers
8
8
  for by-id queries, lists, and mutations.
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **graphqlMutation**\<`T`, `Input`, `Output`\>(`entity`, `options`): [`GraphQLMutationDefinition`](../type-aliases/GraphQLMutationDefinition.md)\<`T`, `Input`, `Output`\>
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:58
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:58
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **mutation**\<`T`, `I`, `R`\>(`entity`): `MutationDefinition`\<`T`, `I`, `R`\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:563
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:563
6
6
 
7
7
  Defines a mutation for a given entity type, preserving the input and output
8
8
  types for transports.
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **useFateClient**\<`T`\>(): `FateClient`\<`T`\[`0`\], `T`\[`1`\]\>
4
4
 
5
- Defined in: [react-fate/src/context.tsx:30](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/context.tsx#L30)
5
+ Defined in: [react-fate/src/context.tsx:30](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useListView.tsx:19](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useListView.tsx#L19)
5
+ Defined in: [react-fate/src/useListView.tsx:19](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useLiveListView.tsx:19](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useLiveListView.tsx#L19)
5
+ Defined in: [react-fate/src/useLiveListView.tsx:19](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useLiveView.tsx:27](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useLiveView.tsx#L27)
7
+ Defined in: [react-fate/src/useLiveView.tsx:27](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useLiveView.tsx:31](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useLiveView.tsx#L31)
46
+ Defined in: [react-fate/src/useLiveView.tsx:31](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useRequest.tsx:25](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useRequest.tsx#L25)
5
+ Defined in: [react-fate/src/useRequest.tsx:25](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useView.tsx:40](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useView.tsx#L40)
7
+ Defined in: [react-fate/src/useView.tsx:40](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useView.tsx:44](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useView.tsx#L44)
45
+ Defined in: [react-fate/src/useView.tsx:44](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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: [react-fate/src/useView.tsx:48](https://github.com/nkzw-tech/fate/blob/ce96828d183f5fe6e334dff531abed295a9ec24d/packages/react-fate/src/useView.tsx#L48)
83
+ Defined in: [react-fate/src/useView.tsx:48](https://github.com/nkzw-tech/fate/blob/affa9937a4bbf38447b9faf2621c79005aff82c6/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
 
@@ -1,5 +1,5 @@
1
1
  # Interface: Persistence
2
2
 
3
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1468
3
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1468
4
4
 
5
5
  A persistence integration. Implementations are imported separately from Fate core.
@@ -1,6 +1,6 @@
1
1
  # Interface: PersistenceSession
2
2
 
3
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1488
3
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1488
4
4
 
5
5
  User-facing observability and lifecycle of an attached persistence integration.
6
6
 
@@ -10,7 +10,7 @@ User-facing observability and lifecycle of an attached persistence integration.
10
10
 
11
11
  > `readonly` **ready**: `Promise`\<`void`\>
12
12
 
13
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1494
13
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1494
14
14
 
15
15
  ## Methods
16
16
 
@@ -18,7 +18,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1494
18
18
 
19
19
  > **clearCache**(): `Promise`\<`void`\>
20
20
 
21
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1489
21
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1489
22
22
 
23
23
  #### Returns
24
24
 
@@ -30,7 +30,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1489
30
30
 
31
31
  > **discard**(`id`): `Promise`\<`void`\>
32
32
 
33
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1490
33
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1490
34
34
 
35
35
  #### Parameters
36
36
 
@@ -48,7 +48,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1490
48
48
 
49
49
  > **dispose**(): `void`
50
50
 
51
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1491
51
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1491
52
52
 
53
53
  #### Returns
54
54
 
@@ -60,7 +60,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1491
60
60
 
61
61
  > **flush**(): `Promise`\<`void`\>
62
62
 
63
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1492
63
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1492
64
64
 
65
65
  #### Returns
66
66
 
@@ -72,7 +72,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1492
72
72
 
73
73
  > **getSnapshot**(): [`PersistenceSnapshot`](../type-aliases/PersistenceSnapshot.md)
74
74
 
75
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1493
75
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1493
76
76
 
77
77
  #### Returns
78
78
 
@@ -84,7 +84,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1493
84
84
 
85
85
  > **retry**(): `void`
86
86
 
87
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1495
87
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1495
88
88
 
89
89
  #### Returns
90
90
 
@@ -96,7 +96,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:1495
96
96
 
97
97
  > **subscribe**(`listener`): () => `void`
98
98
 
99
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1496
99
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1496
100
100
 
101
101
  #### Parameters
102
102
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **ConnectionRef**\<`TName`\> = `Readonly`\<\{ `items`: `ReadonlyArray`\<\{ `cursor?`: `string`; `node`: [`ViewRef`](ViewRef.md)\<`TName`\>; \}\>; `pagination?`: [`Pagination`](Pagination.md); \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:743
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:743
6
6
 
7
7
  Ref for a connection, including pagination metadata.
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Deferred**\<`T`\> = `Readonly`\<\{ `[DeferredTag]`: `DeferredMetadata`; \}\> & `object`
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:763
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:763
6
6
 
7
7
  A deferred value returned from a masked view. Existing view hooks resolve it when read.
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **FateDehydratedState**\<`Scope`\> = `Readonly`\<\{ `[hydrationScopeBrand]?`: `Scope`; `data`: `FateSerializedValue`; `scope`: `Scope`; `version`: `1`; \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1174
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1174
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **GraphQLMutationDefinition**\<`T`, `Input`, `Output`\> = `Readonly`\<\{ `__fateGraphQLMutation?`: \{ `input`: `Input`; `output`: `Output`; \}; `entity`: `T`\[`"__typename"`\]; `field`: `string`; `inputArg?`: `false` \| `string`; \}\>
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:19
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:19
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **GraphQLMutationInput**\<`Definition`\> = `Definition` *extends* [`GraphQLMutationDefinition`](GraphQLMutationDefinition.md)\<`any`, infer Input, `any`\> ? `Input` : `never`
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:28
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:28
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **GraphQLMutationMap**\<`Mutations`\> = `Mutations` *extends* `Record`\<`string`, [`GraphQLMutationDefinition`](GraphQLMutationDefinition.md)\> ? `{ [K in keyof Mutations]: { input: GraphQLMutationInput<Mutations[K]>; output: GraphQLMutationOutput<Mutations[K]> } }` : `EmptyTransportMutations`
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:30
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:30
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **GraphQLMutationOutput**\<`Definition`\> = `Definition` *extends* [`GraphQLMutationDefinition`](GraphQLMutationDefinition.md)\<`any`, `any`, infer Output\> ? `Output` : `never`
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:29
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:29
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **GraphQLTransportOptions**\<`Mutations`\> = `object`
4
4
 
5
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:45
5
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:45
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -16,7 +16,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:45
16
16
 
17
17
  > `optional` **decodeNodeId?**: (`type`, `id`) => `string` \| `number`
18
18
 
19
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:46
19
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:46
20
20
 
21
21
  #### Parameters
22
22
 
@@ -38,7 +38,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:46
38
38
 
39
39
  > `optional` **encodeNodeId?**: (`type`, `id`) => `string` \| `number`
40
40
 
41
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:47
41
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:47
42
42
 
43
43
  #### Parameters
44
44
 
@@ -60,7 +60,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:47
60
60
 
61
61
  > `optional` **eventSource?**: `EventSourceConstructor`
62
62
 
63
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:48
63
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:48
64
64
 
65
65
  ***
66
66
 
@@ -68,7 +68,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:48
68
68
 
69
69
  > `optional` **fetch?**: `FetchLike`
70
70
 
71
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:49
71
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:49
72
72
 
73
73
  ***
74
74
 
@@ -76,7 +76,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:49
76
76
 
77
77
  > `optional` **headers?**: `HeadersFactory`
78
78
 
79
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:50
79
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:50
80
80
 
81
81
  ***
82
82
 
@@ -84,7 +84,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:50
84
84
 
85
85
  > `optional` **live?**: `boolean` \| `GraphQLLiveOptions`
86
86
 
87
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:51
87
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:51
88
88
 
89
89
  ***
90
90
 
@@ -92,7 +92,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:51
92
92
 
93
93
  > `optional` **mutateDurably?**: `Transport`\<`Mutations`\>\[`"mutateDurably"`\]
94
94
 
95
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:52
95
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:52
96
96
 
97
97
  ***
98
98
 
@@ -100,7 +100,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:52
100
100
 
101
101
  > `optional` **mutations?**: `Record`\<`Extract`\<keyof `Mutations`, `string`\>, `GraphQLMutationRuntimeConfig`\>
102
102
 
103
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:53
103
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:53
104
104
 
105
105
  ***
106
106
 
@@ -108,7 +108,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:53
108
108
 
109
109
  > `optional` **roots?**: `Record`\<`string`, `GraphQLRootConfig`\>
110
110
 
111
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:54
111
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:54
112
112
 
113
113
  ***
114
114
 
@@ -116,7 +116,7 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:54
116
116
 
117
117
  > **types**: `ReadonlyArray`\<`Omit`\<`TypeConfig`, `"getId"`\> & `Partial`\<`Pick`\<`TypeConfig`, `"getId"`\>\>\>
118
118
 
119
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:55
119
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:55
120
120
 
121
121
  ***
122
122
 
@@ -124,4 +124,4 @@ Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:55
124
124
 
125
125
  > **url**: `string` \| `URL`
126
126
 
127
- Defined in: fate/lib/graphqlTransport-CGYE4NdD.d.mts:56
127
+ Defined in: fate/lib/graphqlTransport-D7IPm9wQ.d.mts:56
@@ -2,6 +2,6 @@
2
2
 
3
3
  > **HydrateOptions** = `Readonly`\<\{ `merge?`: `"preserve-existing"` \| `"replace"`; \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1181
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1181
6
6
 
7
7
  Controls how `FateClient.hydrate()` reconciles a snapshot with browser cache state.
@@ -2,6 +2,6 @@
2
2
 
3
3
  > **HydrationLimits** = `Readonly`\<\{ `maxCollectionLength`: `number`; `maxNodes`: `number`; `maxStringLength`: `number`; \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1191
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1191
6
6
 
7
7
  Resource limits applied while encoding and decoding hydration snapshots.
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **InferFateAPI**\<`Server`\> = `Server` *extends* `object` ? `API` : `never`
4
4
 
5
- Defined in: fate/lib/record-Dxjvpsep.d.mts:208
5
+ Defined in: fate/lib/record-DmyMlWdZ.d.mts:208
6
6
 
7
7
  ## Type Parameters
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Pagination** = `object`
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:736
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:736
6
6
 
7
7
  Pagination state returned alongside connection lists.
8
8
 
@@ -12,7 +12,7 @@ Pagination state returned alongside connection lists.
12
12
 
13
13
  > **hasNext**: `boolean`
14
14
 
15
- Defined in: fate/lib/transport-DR0fwleU.d.mts:737
15
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:737
16
16
 
17
17
  ***
18
18
 
@@ -20,7 +20,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:737
20
20
 
21
21
  > **hasPrevious**: `boolean`
22
22
 
23
- Defined in: fate/lib/transport-DR0fwleU.d.mts:738
23
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:738
24
24
 
25
25
  ***
26
26
 
@@ -28,7 +28,7 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:738
28
28
 
29
29
  > `optional` **nextCursor?**: `string`
30
30
 
31
- Defined in: fate/lib/transport-DR0fwleU.d.mts:739
31
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:739
32
32
 
33
33
  ***
34
34
 
@@ -36,4 +36,4 @@ Defined in: fate/lib/transport-DR0fwleU.d.mts:739
36
36
 
37
37
  > `optional` **previousCursor?**: `string`
38
38
 
39
- Defined in: fate/lib/transport-DR0fwleU.d.mts:740
39
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:740
@@ -2,4 +2,4 @@
2
2
 
3
3
  > **PersistenceSnapshot** = `Readonly`\<\{ `error?`: `Error`; `mutations`: `ReadonlyArray`\<`PersistedMutationStatus`\>; `status`: `"restoring"` \| `"ready"` \| `"error"` \| `"disposed"`; \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:1479
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:1479
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **ViewRef**\<`TName`\> = `Readonly`\<\{ `__typename`: `TName`; `[ViewsTag]`: `Set`\<`string`\>; `id`: `string` \| `number`; \}\>
4
4
 
5
- Defined in: fate/lib/transport-DR0fwleU.d.mts:712
5
+ Defined in: fate/lib/transport-c5vvbtDC.d.mts:712
6
6
 
7
7
  Reference to a normalized entity instance that can be resolved against one or more view tags.
8
8
 
@@ -1,161 +1,43 @@
1
1
  # Cloudflare Integration
2
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.
3
+ Deploy fate directly to your own Cloudflare account with [Void](void.md). The Void template includes the app, D1 database, Drizzle migrations, Better Auth, and live updates through `void-fate` and `void/live`.
6
4
 
7
5
  ## New Project
8
6
 
9
- For a new Cloudflare Workers app, start from the Cloudflare template. It includes the client, Worker server, D1 migrations, Wrangler config, Durable Object live transport, auth wiring, and generated fate client setup.
10
-
11
7
  ```sh
12
- vp create fate my-app --template cloudflare
8
+ vp create fate my-app --template void
9
+ cd my-app
10
+ vp run dev:setup
11
+ vp run dev
13
12
  ```
14
13
 
15
- Use Vue instead of React with:
14
+ Add `--framework vue` to the create command to use Vue instead of React.
16
15
 
17
- ```sh
18
- vp create fate my-app --template cloudflare --framework vue
19
- ```
16
+ ## Deploy
20
17
 
21
- ## Existing Project
22
-
23
- For an existing Cloudflare Workers project, add the packages directly:
18
+ From the project root:
24
19
 
25
20
  ```sh
26
- pnpm add @nkzw/fate react-fate cf-fate drizzle-orm
27
- pnpm add -D wrangler
28
- ```
29
-
30
- For Vue clients, replace `react-fate` with `vue-fate`.
31
-
32
- ## Server Setup
33
-
34
- Create a Cloudflare live stream and pass its Fate live facade to `createFateServer`.
35
-
36
- ```ts
37
- // src/fate/live.ts
38
- import { defineCloudflareFateLiveStream } from 'cf-fate/server';
39
-
40
- export const fateStream = defineCloudflareFateLiveStream({
41
- allowAnonymousControl: true,
42
- binding: 'FATE_LIVE',
43
- id: 'fate',
44
- });
45
- ```
46
-
47
- ```ts
48
- // src/fate/server.ts
49
- import { createFateServer } from '@nkzw/fate/server';
50
- import { createCloudflareFateLive } from 'cf-fate/server';
51
-
52
- export const fateLive = createCloudflareFateLive();
53
- export const { live } = fateLive;
54
-
55
- export const fateServer = createFateServer({
56
- live,
57
- // context,
58
- // roots,
59
- // sources,
60
- });
21
+ vp exec void deploy --platform cloudflare
61
22
  ```
62
23
 
63
- Publish from mutations through the normal Fate live bus:
64
-
65
- ```ts
66
- live.update('Post', postId, { changed: ['likes'] });
67
- live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId);
68
- ```
24
+ Void signs you into Cloudflare when needed, lets you select your account, provisions resources, applies checked-in database migrations, and deploys the app. It saves resource IDs in the root `wrangler.jsonc`; commit that updated config for subsequent deployments. A Void platform account is not required.
69
25
 
70
- ## Worker Routes
71
-
72
- Expose one route for Fate RPC and one route for the SSE live stream.
73
-
74
- ```ts
75
- import {
76
- createCloudflareFateLiveDurableObject,
77
- defineCloudflareFateLiveRoute,
78
- defineCloudflareFateRoute,
79
- } from 'cf-fate/server';
80
- import { fateStream } from './fate/live';
81
- import { fateLive, fateServer } from './fate/server';
82
-
83
- const fateRoute = defineCloudflareFateRoute(fateServer, fateLive, { stream: fateStream });
84
- const fateLiveRoute = defineCloudflareFateLiveRoute(fateStream);
85
-
86
- export const FateLiveDurableObject = createCloudflareFateLiveDurableObject({
87
- binding: 'FATE_LIVE',
88
- });
89
-
90
- export default {
91
- fetch(request, env, ctx) {
92
- const url = new URL(request.url);
93
- if (url.pathname === '/fate') {
94
- return fateRoute.fetch(request, env, ctx);
95
- }
96
- if (url.pathname === '/fate-live') {
97
- return fateLiveRoute.fetch(request, env, ctx);
98
- }
99
- return new Response('Not Found', { status: 404 });
100
- },
101
- };
102
- ```
103
-
104
- ## Wrangler
105
-
106
- Add a Durable Object binding and migration. `cf-fate` uses `node:async_hooks`, so the Worker must enable Node compatibility.
107
-
108
- ```jsonc
109
- {
110
- "compatibility_flags": ["nodejs_compat"],
111
- "durable_objects": {
112
- "bindings": [
113
- {
114
- "name": "FATE_LIVE",
115
- "class_name": "FateLiveDurableObject",
116
- },
117
- ],
118
- },
119
- "migrations": [
120
- {
121
- "tag": "fate-live-v1",
122
- "new_sqlite_classes": ["FateLiveDurableObject"],
123
- },
124
- ],
125
- }
126
- ```
26
+ The template includes the `VOID_LIVE` Durable Object binding and its class migration. Keep them in `wrangler.jsonc` so live subscriptions can receive updates across requests. RPC requests use `/fate`, and live updates use `/fate-live`.
127
27
 
128
- ## Client
28
+ After changing your database schema or auth configuration, run `vp run db:generate`, review and commit the generated migrations, then deploy. The migrations must include the Better Auth schema used in production.
129
29
 
130
- Use the Cloudflare transport in the Fate Vite plugin:
30
+ See [Void's Cloudflare deployment guide](https://void.cloud/integrations/cloudflare) for custom domains, secrets, and CI configuration.
131
31
 
132
- ```ts
133
- import { fate } from 'react-fate/vite';
32
+ ## Migrating from cf-fate
134
33
 
135
- fate({
136
- module: './src/fate/server.ts',
137
- transport: 'cloudflare',
138
- });
139
- ```
140
-
141
- Then point the generated client at the Worker endpoints:
142
-
143
- ```tsx
144
- import { FateClient } from 'react-fate';
145
- import { createFateClient } from 'react-fate/client';
146
-
147
- const fate = createFateClient({
148
- liveUrl: 'http://localhost:8787/fate-live',
149
- url: 'http://localhost:8787/fate',
150
- });
151
-
152
- export function App({ children }) {
153
- return <FateClient client={fate}>{children}</FateClient>;
154
- }
155
- ```
34
+ Fate 1.6 replaces the standalone Cloudflare adapter and template with the Void integration. Use `--template void` for new projects and `transport: 'void'` in the fate Vite plugin.
156
35
 
157
- ## Semantics
36
+ For an existing app, move the Worker routes into Void's `routes/` directory and follow the [Void integration](void.md) for the complete setup:
158
37
 
159
- `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.
38
+ - Define the live stream with `defineLiveStream` from `void/live`.
39
+ - Use `createVoidFateLive`, `defineVoidFateRoute`, and `defineVoidFateLiveRoute` from `void-fate/server`.
40
+ - Let the generated client use `void/live/client` for live connections.
41
+ - Remove the `cf-fate` dependency and the custom Worker entry point.
160
42
 
161
- 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.
43
+ Deploy the Void app as a new Worker with its `VOID_LIVE` binding and class migration. The old `FATE_LIVE` Durable Object class and its active connections are not migrated. Preserve existing database IDs and migration history when reusing your database, and reconnect clients to the new app after deployment.
@@ -1,6 +1,6 @@
1
1
  # Void Integration
2
2
 
3
- `void-fate` is the first-class [Void](https://void.cloud) adapter for fate to ease integration with the Void SDK and for deploying to the Void platform.
3
+ `void-fate` is the [Void](https://void.cloud) adapter for fate. Deploy your app directly to your own Cloudflare account or to the Void platform with the same integration.
4
4
 
5
5
  Use this integration when your app runs on Void and you want the example app's
6
6
  setup without copying its adapter glue.
@@ -127,14 +127,29 @@ live.connection('Post.comments', { id: postId }).appendNode('Comment', commentId
127
127
 
128
128
  ## Routes
129
129
 
130
+ Define a live stream once in a server-only module:
131
+
132
+ ```ts
133
+ // src/fate/live.ts
134
+ import { defineLiveStream } from 'void/live';
135
+
136
+ export const fateStream = defineLiveStream({
137
+ allowAnonymousControl: true,
138
+ id: 'fate',
139
+ });
140
+ ```
141
+
130
142
  Add one route for fate RPC requests:
131
143
 
132
144
  ```tsx
133
145
  // routes/fate.ts
134
146
  import { defineVoidFateRoute } from 'void-fate/server';
147
+ import { fateStream } from '../src/fate/live.ts';
135
148
  import { fateLive, fateServer } from '../src/fate/server.ts';
136
149
 
137
- export const { GET, POST } = defineVoidFateRoute(fateServer, fateLive);
150
+ export const { GET, POST } = defineVoidFateRoute(fateServer, fateLive, {
151
+ stream: fateStream,
152
+ });
138
153
  ```
139
154
 
140
155
  Add a second route for the live SSE transport:
@@ -142,9 +157,9 @@ Add a second route for the live SSE transport:
142
157
  ```tsx
143
158
  // routes/fate-live.ts
144
159
  import { defineVoidFateLiveRoute } from 'void-fate/server';
145
- import { fateLive, fateServer } from '../src/fate/server.ts';
160
+ import { fateStream } from '../src/fate/live.ts';
146
161
 
147
- export const { GET, POST } = defineVoidFateLiveRoute(fateServer, fateLive);
162
+ export const { GET, POST } = defineVoidFateLiveRoute(fateStream);
148
163
  ```
149
164
 
150
165
  The live route handles `GET /fate-live` SSE connections and `POST /fate-live`
@@ -210,13 +225,7 @@ present.
210
225
  ## Custom Paths
211
226
 
212
227
  The default route pair is `/fate` and `/fate-live`. If your Void app uses
213
- different paths, configure the same values on the live adapter and client.
214
-
215
- ```tsx
216
- export const fateLive = createVoidFateLive({
217
- livePath: '/custom-fate-live',
218
- });
219
- ```
228
+ different paths, update your route filenames and configure the matching client paths.
220
229
 
221
230
  ::: code-group
222
231
 
@@ -252,14 +261,19 @@ or router configuration matches the paths you pass to the client.
252
261
 
253
262
  ## Live Transport
254
263
 
255
- Void can run separate request handlers for mutations and long-lived SSE
256
- connections. `createVoidFateLive` bridges those handlers by publishing live
257
- events from the request that changed data to the live route.
258
-
259
- In local development, `void-fate` uses a development token for that internal
260
- publish request. Outside local development, Void must provide `__VOID_PROXY_TOKEN`
261
- in the route environment. If no internal publish token is available, the adapter
262
- falls back to the in-memory live bus for the current request context.
264
+ `createVoidFateLive` publishes entity and connection events through the `void/live`
265
+ stream associated with the current request. Void manages the Durable Object
266
+ transport that distributes events to connected clients across requests.
263
267
 
264
268
  The live transport is best-effort and does not replay missed events after a
265
269
  client reconnects. This matches fate's default in-memory live event bus.
270
+
271
+ ## Cloudflare Deployment
272
+
273
+ From your project root, run:
274
+
275
+ ```sh
276
+ vp exec void deploy --platform cloudflare
277
+ ```
278
+
279
+ Void provisions resources and deploys directly to your Cloudflare account. See the [Cloudflare integration](cloudflare.md) for setup and migration instructions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-fate",
3
- "version": "1.5.2",
3
+ "version": "1.6.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,13 +40,13 @@
40
40
  }
41
41
  },
42
42
  "dependencies": {
43
- "@nkzw/fate": "^1.5.2"
43
+ "@nkzw/fate": "1.6.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@types/react": "^19.3.0",
47
- "@types/react-dom": "^19.3.0",
48
- "react": "^19.3.0",
49
- "react-dom": "^19.3.0"
46
+ "@types/react": "19.3.0",
47
+ "@types/react-dom": "19.3.0",
48
+ "react": "19.3.0",
49
+ "react-dom": "19.3.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": "^19.2.0",