### Install Dependencies Source: https://eden-query.xkel.me/docs Install the required packages for Eden TanStack Query and its peer dependencies. ```bash npm i eden-tanstack-react-query @tanstack/react-query @elysiajs/eden elysia ``` -------------------------------- ### Install Eden TanStack Query (yarn) Source: https://eden-query.xkel.me/docs/getting-started Install the package and its peer dependencies using yarn. ```bash yarn add eden-tanstack-react-query @tanstack/react-query @elysiajs/eden elysia ``` -------------------------------- ### Setup Provider Source: https://eden-query.xkel.me/docs/comparisons Configure the EdenProvider and QueryClientProvider for the application. ```typescript const { EdenProvider, useEden } = createEdenTanStackQuery() const edenClient = treaty('http://localhost:3000') ``` -------------------------------- ### Install Testing Dependencies Source: https://eden-query.xkel.me/docs/guides/testing Install necessary testing libraries including Vitest, Testing Library, and jsdom. ```bash bun add -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom @vitejs/plugin-react ``` -------------------------------- ### Setup Test Environment Source: https://eden-query.xkel.me/docs/guides/testing Set up the testing environment by importing necessary libraries and cleaning up mocks after each test. ```typescript import '@testing-library/jest-dom/vitest' import { afterEach, vi } from 'vitest' import { cleanup } from '@testing-library/react' afterEach(() => { cleanup() vi.restoreAllMocks() }) ``` -------------------------------- ### Install Eden TanStack Query (npm) Source: https://eden-query.xkel.me/docs/getting-started Install the package and its peer dependencies using npm. ```bash npm install eden-tanstack-react-query @tanstack/react-query @elysiajs/eden elysia ``` -------------------------------- ### Install Eden TanStack Query (pnpm) Source: https://eden-query.xkel.me/docs/getting-started Install the package and its peer dependencies using pnpm. ```bash pnpm add eden-tanstack-react-query @tanstack/react-query @elysiajs/eden elysia ``` -------------------------------- ### Mutation Key Example Source: https://eden-query.xkel.me/docs/guides/query-keys Shows how to generate a mutation key for a mutation route using `mutationKey()`. ```javascript eden.users.post.mutationKey() // => [['users', 'post']] ``` -------------------------------- ### Infinite Query Key Example Source: https://eden-query.xkel.me/docs/guides/query-keys Shows how to generate a query key specifically for infinite queries using `infiniteQueryKey()`. ```javascript eden.posts.get.infiniteQueryKey({ limit: 10 }) // => [['posts', 'get'], { input: { limit: 10 }, type: 'infinite' }] ``` -------------------------------- ### Query Key Structure and Examples Source: https://eden-query.xkel.me/docs/guides/query-keys Demonstrates the structure of query keys generated by Eden TanStack Query and provides examples for different scenarios, including regular queries and infinite queries. ```APIDOC ## Query Key Structure Query keys follow this structure: ``` // queryKey() returns: [['path', 'segments', 'method'], { input: { ... }, type: 'query' }] // Examples: eden.users.get.queryKey() // => [['users', 'get'], { type: 'query' }] eden.users.get.queryKey({ role: 'admin' }) // => [['users', 'get'], { input: { role: 'admin' }, type: 'query' }] eden.users({ id: '1' }).get.queryKey() // => [['users', 'get'], { input: { id: '1' }, type: 'query' }] ``` The `type` field differentiates regular queries from infinite queries: ``` eden.posts.get.infiniteQueryKey({ limit: 10 }) // => [['posts', 'get'], { input: { limit: 10 }, type: 'infinite' }] ``` ``` -------------------------------- ### Install Peer Dependencies Source: https://eden-query.xkel.me/docs/troubleshooting Required packages for Eden TanStack Query integration. ```bash bun add eden-tanstack-react-query @tanstack/react-query @elysiajs/eden elysia ``` -------------------------------- ### Monorepo Setup: Import App Type Source: https://eden-query.xkel.me/docs/getting-started Import the exported `App` type from the server package into your client package to enable type-safe Eden client setup. ```typescript import type { App } from '@myorg/server' ``` -------------------------------- ### Configure Basic Eden TanStack Setup Source: https://eden-query.xkel.me/docs/api-reference/create-eden-tanstack-query Initialize the typed hooks and the Eden Treaty client for use in the application. ```typescript import { createEdenTanStackQuery } from 'eden-tanstack-react-query' import { treaty } from '@elysiajs/eden' import type { App } from './server' // Create typed hooks and provider export const { EdenProvider, useEden, useEdenClient } = createEdenTanStackQuery() // Create the Eden client export const edenClient = treaty('http://localhost:3000') ``` -------------------------------- ### Use EdenOptionsProxy Source: https://eden-query.xkel.me/docs/api-reference/types Example usage of the decorated options proxy for an Elysia app. ```typescript // Usage type Proxy = EdenOptionsProxy // Proxy.users.get.queryOptions(...) // Proxy.users({ id: '1' }).get.queryOptions(...) // Proxy.users.post.mutationOptions(...) ``` -------------------------------- ### Query Key Structure Examples Source: https://eden-query.xkel.me/docs/guides/query-keys Demonstrates the structure of query keys generated by Eden TanStack Query, including variations with and without input parameters. ```javascript eden.users.get.queryKey() // => [['users', 'get'], { type: 'query' }] ``` ```javascript eden.users.get.queryKey({ role: 'admin' }) // => [['users', 'get'], { input: { role: 'admin' }, type: 'query' }] ``` ```javascript eden.users({ id: '1' }).get.queryKey() // => [['users', 'get'], { input: { id: '1' }, type: 'query' }] ``` -------------------------------- ### Combining Path Parameters with Infinite Queries Source: https://eden-query.xkel.me/docs/guides/infinite-queries Example of using `useInfiniteQuery` with dynamic route parameters, such as fetching posts for a specific user ID. ```javascript // GET /users/:id/posts function UserPosts({ userId }: { userId: string }) { const eden = useEden() const { data } = useInfiniteQuery( eden.users({ id: userId }).posts.get.infiniteQueryOptions( { limit: 10 }, { getNextPageParam: (page) => page.nextCursor ?? undefined, initialCursor: null, } ) ) } ``` -------------------------------- ### Configure Vitest Source: https://eden-query.xkel.me/docs/guides/testing Configure Vitest for a React project using jsdom environment and specify setup files. ```typescript import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', setupFiles: ['./test/setup.ts'], globals: true } }) ``` -------------------------------- ### Server Route for Cursor-Based Pagination Source: https://eden-query.xkel.me/docs/guides/infinite-queries A typical server route setup for handling cursor-based pagination requests, expecting 'limit' and 'cursor' query parameters. ```javascript app.get('/posts', ({ query }) => { const { limit, cursor } = query const posts = getPosts({ limit, after: cursor }) return { items: posts, nextCursor: posts.length === limit ? posts[posts.length - 1].id : null, } }, { query: t.Object({ limit: t.Number({ default: 10 }), cursor: t.Optional(t.String()), }) }) ``` -------------------------------- ### Monorepo Setup: Export App Type Source: https://eden-query.xkel.me/docs/getting-started In a monorepo, export the `App` type from your server package to make it available for client-side type inference. ```typescript export type App = typeof app ``` -------------------------------- ### Set Up QueryClientProvider and EdenProvider Source: https://eden-query.xkel.me/docs/getting-started Wrap your application with `QueryClientProvider` and `EdenProvider` to make the clients available throughout your app. ```typescript import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { EdenProvider, edenClient } from './lib/eden' const queryClient = new QueryClient() export default function App() { return ( ) } ``` -------------------------------- ### Basic Infinite Query Usage with useInfiniteQuery Source: https://eden-query.xkel.me/docs/guides/infinite-queries Demonstrates the basic implementation of `useInfiniteQuery` for fetching paginated data, including loading states and a 'Load More' button. ```javascript import { useInfiniteQuery } from '@tanstack/react-query' import { useEden } from './lib/eden' function PostList() { const eden = useEden() const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, } = useInfiniteQuery( eden.posts.get.infiniteQueryOptions( { limit: 10 }, { getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined, initialCursor: null, } ) ) if (isLoading) return
Loading...
return (
{data?.pages.map((page) => page.items.map((post) => (

{post.title}

)) )}
) } ``` -------------------------------- ### Basic Query with useQuery Source: https://eden-query.xkel.me/docs/guides/queries Use `useQuery` with `queryOptions()` to fetch data. Handles loading and error states. ```javascript import { useQuery } from '@tanstack/react-query' import { useEden } from './lib/eden' function UserList() { const eden = useEden() const { data, isLoading, error } = useQuery( eden.users.get.queryOptions() ) if (isLoading) return
Loading...
if (error) return
Error: {error.message}
return (
    {data?.map(user => (
  • {user.name}
  • ))}
) } ``` -------------------------------- ### Create Eden TanStack Query Instance Source: https://eden-query.xkel.me/docs/getting-started Set up the Eden TanStack Query instance and treaty client. Ensure the `App` type is imported from your server. ```typescript import { createEdenTanStackQuery } from 'eden-tanstack-react-query' import { treaty } from '@elysiajs/eden' import type { App } from '../../server' export const { EdenProvider, useEden } = createEdenTanStackQuery() export const edenClient = treaty('http://localhost:3000') ``` -------------------------------- ### Query Routes API Source: https://eden-query.xkel.me/docs/api-reference Methods available on query routes (GET, HEAD, OPTIONS) for managing data fetching, cache operations, and invalidation. ```APIDOC ## Query Routes (GET, HEAD, OPTIONS) ### Description Provides methods to generate query options, keys, and filters for TanStack Query hooks. ### Methods - **queryOptions(input?, opts?)**: Generates options for `useQuery`. - **queryKey(input?)**: Generates a query key for cache operations. - **queryFilter(input?, filters?)**: Generates filters for cache invalidation. - **infiniteQueryOptions(input, opts)**: Generates options for `useInfiniteQuery` (for paginated data). - **infiniteQueryKey(input?)**: Generates a query key for infinite query cache operations. ### Usage Example ```typescript const eden = useEden(); // Standard query eden.users.get.queryOptions(input, opts); // Infinite query eden.posts.get.infiniteQueryOptions(input, opts); ``` ``` -------------------------------- ### Using infiniteQueryKey and infiniteQueryFilter for Cache Operations Source: https://eden-query.xkel.me/docs/guides/infinite-queries Demonstrates how to obtain the infinite query key and invalidate queries using `infiniteQueryKey` and `infiniteQueryFilter` with `useQueryClient`. ```javascript const queryClient = useQueryClient() const eden = useEden() // Get the infinite query key const key = eden.posts.get.infiniteQueryKey({ limit: 10 }) // Invalidate infinite query queryClient.invalidateQueries({ queryKey: eden.posts.get.infiniteQueryKey() }) // Using infiniteQueryFilter queryClient.invalidateQueries( eden.posts.get.infiniteQueryFilter({ category: 'tech' }) ) ``` -------------------------------- ### Prefetch Multiple Queries Source: https://eden-query.xkel.me/docs/guides/ssr Demonstrates how to prefetch multiple queries concurrently on the server. ```typescript export default async function DashboardPage() { const queryClient = getQueryClient() const eden = createEdenOptionsProxy({ client: getServerEdenClient(), queryClient }) await Promise.all([ queryClient.prefetchQuery(eden.users.get.queryOptions()), queryClient.prefetchQuery(eden.stats.get.queryOptions()), ]) return ( ) } ``` -------------------------------- ### Invalidate All Users Queries After Mutation Source: https://eden-query.xkel.me/docs/guides/query-keys This example shows how to invalidate all user-related queries after a successful user creation mutation, ensuring the UI reflects the latest data. ```javascript const createUser = useMutation({ ...eden.users.post.mutationOptions(), onSuccess: () => { // Invalidates all users queries (list, filtered, by id, etc.) queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey() }) }, }) ``` -------------------------------- ### Compare Basic Query Implementation Source: https://eden-query.xkel.me/docs/comparisons Shows the difference in syntax for fetching data between eden-tanstack-query and @elysiajs/eden-query. ```typescript const eden = useEden() const { data } = useQuery(eden.users.get.queryOptions()) ``` ```typescript const { data } = eden.users.get.useQuery() ``` -------------------------------- ### Multiple API Instances Source: https://eden-query.xkel.me/docs/api-reference/create-eden-tanstack-query Demonstrates how to create and use multiple independent instances of Eden TanStack Query for different backends. ```APIDOC ## Multiple API Instances You can create multiple instances for different backends: ```typescript // Internal API const internalApi = createEdenTanStackQuery() // External API const externalApi = createEdenTanStackQuery() ``` Then use separate providers (or nest them): ```typescript ``` ``` -------------------------------- ### Configure Next.js App Router Layout Source: https://eden-query.xkel.me/docs/guides/ssr Sets up the root layout to wrap the application with necessary providers. ```typescript import { Providers } from './providers' export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ) } ``` -------------------------------- ### Create Eden TanStack Query Instance Source: https://eden-query.xkel.me/docs Initialize the typed providers and hooks for the application. ```typescript const { EdenProvider, useEden, useEdenClient } = createEdenTanStackQuery() ``` -------------------------------- ### Configure QueryClientProvider Source: https://eden-query.xkel.me/docs/troubleshooting Wraps the application with QueryClientProvider to ensure proper state management. ```tsx function App() { return ( ) } ``` -------------------------------- ### queryOptions Source: https://eden-query.xkel.me/docs/api-reference/use-eden Creates type-safe options for useQuery, useSuspenseQuery, and prefetchQuery. ```APIDOC ## GET queryOptions ### Description Creates type-safe options for useQuery, useSuspenseQuery, prefetchQuery, and other TanStack Query functions. ### Parameters #### Request Body - **input** (TInput | SkipToken) - Optional - Query parameters or skipToken to disable. - **opts** (EdenQueryOptionsIn) - Optional - TanStack Query options (excluding reserved). ### Returns - **queryKey** (DataTag) - Unique key based on path and input. - **queryFn** (QueryFunction) - Fetch function via Eden client. - **eden** (Object) - Route metadata. ### Request Example { "input": { "role": "admin" }, "opts": { "staleTime": 300000 } } ``` -------------------------------- ### Create a Basic Mutation Source: https://eden-query.xkel.me/docs/guides/mutations Use mutationOptions() to integrate Eden procedures with TanStack Query's useMutation hook. ```typescript import { useMutation } from '@tanstack/react-query' import { useEden } from './lib/eden' function CreateUserForm() { const eden = useEden() const createUser = useMutation( eden.users.post.mutationOptions() ) const handleSubmit = (e: React.FormEvent) => { e.preventDefault() const formData = new FormData(e.currentTarget) createUser.mutate({ name: formData.get('name') as string, email: formData.get('email') as string, }) } return (
) } ``` -------------------------------- ### Create Eden Options Proxy Source: https://eden-query.xkel.me/docs/guides/ssr Initializes a server-side proxy to generate query options compatible with the client-side useEden hook. ```typescript import { createEdenOptionsProxy } from 'eden-tanstack-react-query' const eden = createEdenOptionsProxy({ client: serverClient, queryClient }) // Use the same API as useEden() await queryClient.prefetchQuery(eden.users.get.queryOptions()) ``` -------------------------------- ### infiniteQueryOptions Source: https://eden-query.xkel.me/docs/api-reference/use-eden Creates type-safe options for useInfiniteQuery with cursor-based pagination. ```APIDOC ## GET infiniteQueryOptions ### Description Creates type-safe options for useInfiniteQuery with cursor-based pagination. ### Parameters #### Request Body - **input** (TInput | SkipToken) - Required - Query params (excluding cursor) or skipToken. - **opts.getNextPageParam** (Function) - Required - Returns next page cursor. - **opts.initialCursor** (TCursor) - Optional - Initial cursor value. - **opts.getPreviousPageParam** (Function) - Optional - For bi-directional pagination. - **opts.maxPages** (number) - Optional - Max pages to keep in memory. ``` -------------------------------- ### Handle Multiple API Instances Source: https://eden-query.xkel.me/docs/api-reference/create-eden-tanstack-query Create and provide multiple API instances to support different backends within the same application. ```typescript // Internal API const internalApi = createEdenTanStackQuery() // External API const externalApi = createEdenTanStackQuery() ``` ```tsx ``` -------------------------------- ### Query with Input Parameters Source: https://eden-query.xkel.me/docs/guides/queries Pass query parameters to `queryOptions()` to filter results. Additional TanStack Query options can be passed as the second argument. ```javascript // GET /users?role=admin&status=active const { data } = useQuery( eden.users.get.queryOptions({ role: 'admin', status: 'active' }) ) ``` ```javascript const { data } = useQuery( eden.users.get.queryOptions( { role: 'admin' }, { staleTime: 5 * 60 * 1000 } ) ) ``` -------------------------------- ### Fetch Data with useQuery Source: https://eden-query.xkel.me/docs/getting-started Use the `useQuery` hook from `@tanstack/react-query` along with `useEden` to fetch data. The `queryOptions()` method generates the necessary query configuration. ```typescript import { useQuery } from '@tanstack/react-query' import { useEden } from '../lib/eden' export function UserList() { const eden = useEden() const { data: users, isLoading } = useQuery( eden.users.get.queryOptions() ) if (isLoading) return
Loading...
return (
    {users?.map((user) => (
  • {user.name} ({user.email})
  • ))}
) } ``` -------------------------------- ### Read and Write Cache Data Source: https://eden-query.xkel.me/docs/guides/query-keys Demonstrates how to directly read cached data using `getQueryData` and write or update cached data using `setQueryData` with a specific query key. ```javascript // Read cached data const user = queryClient.getQueryData( eden.users({ id: '1' }).get.queryKey() ) ``` ```javascript // Write to cache queryClient.setQueryData( eden.users({ id: '1' }).get.queryKey(), { id: '1', name: 'Updated Name', email: 'updated@example.com' } ) ``` -------------------------------- ### Compare Mutation Implementation Source: https://eden-query.xkel.me/docs/comparisons Demonstrates how mutations and cache invalidation are handled in both libraries. ```typescript const createUser = useMutation({ ...eden.users.post.mutationOptions(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey() }) } }) ``` ```typescript const createUser = eden.users.post.useMutation({ onSuccess: () => { // Query invalidation is less explicit } }) ``` -------------------------------- ### Create Infinite Query Options with infiniteQueryOptions Source: https://eden-query.xkel.me/docs/api-reference/use-eden Use `infiniteQueryOptions` for cursor-based pagination with `useInfiniteQuery`. It requires `getNextPageParam` and supports `initialCursor` and `getPreviousPageParam`. ```typescript eden.route.get.infiniteQueryOptions(input, opts): InfiniteQueryOptions ``` ```typescript const eden = useEden() const { data, fetchNextPage, hasNextPage } = useInfiniteQuery( eden.posts.get.infiniteQueryOptions( { limit: 10 }, { getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined, initialCursor: null, } ) ) ``` -------------------------------- ### Create Test Wrapper Component Source: https://eden-query.xkel.me/docs/guides/testing Provides a wrapper component for testing that includes QueryClientProvider and EdenProvider. ```typescript import { ReactNode } from 'react' import { QueryClientProvider } from '@tanstack/react-query' import { createEdenTanStackQuery } from 'eden-tanstack-react-query' import type { App } from '@/lib/server' export function createTestWrapper(mockClient: any) { const queryClient = createTestQueryClient() const { EdenProvider } = createEdenTanStackQuery() function Wrapper({ children }: { children: ReactNode }) { return ( {children} ) } return { Wrapper, queryClient } } ``` -------------------------------- ### Available Query Key Methods Source: https://eden-query.xkel.me/docs/guides/query-keys Details the methods available for generating query keys and filters, including `queryKey`, `queryFilter`, `infiniteQueryKey`, `infiniteQueryFilter`, and `mutationKey`. ```APIDOC ## Available Methods ### queryKey() Returns the query key for a specific route. Optionally accepts input for more specific targeting: ``` eden.users.get.queryKey() // all users queries eden.users.get.queryKey({ role: 'admin' }) // specific input eden.users({ id: '1' }).get.queryKey() // specific path params ``` ### queryFilter() Returns a filter object (including `queryKey`) for use with TanStack Query's filter-based methods: ``` eden.users.get.queryFilter() eden.users.get.queryFilter({ role: 'admin' }) eden.users.get.queryFilter(undefined, { exact: true, stale: true }) ``` `queryKey()` generates keys with `type: "query"`, which only matches regular queries. `queryFilter()` uses `type: "any"`, which matches both regular and infinite queries — making it better suited for broad cache invalidation. ### infiniteQueryKey() Returns the query key for infinite queries: ``` eden.posts.get.infiniteQueryKey() eden.posts.get.infiniteQueryKey({ limit: 10 }) ``` ### infiniteQueryFilter() Returns a filter object for infinite queries: ``` eden.posts.get.infiniteQueryFilter() eden.posts.get.infiniteQueryFilter({ category: 'tech' }) ``` ### mutationKey() Returns the mutation key for a mutation route: ``` eden.users.post.mutationKey() // => [['users', 'post']] ``` ``` -------------------------------- ### Query Key and Filter Usage Source: https://eden-query.xkel.me/docs/guides/query-keys Illustrates how to obtain query keys and filter objects for different query types. `queryFilter()` is suitable for broad cache invalidation as it matches both regular and infinite queries. ```javascript eden.users.get.queryKey() // all users queries ``` ```javascript eden.users.get.queryKey({ role: 'admin' }) // specific input ``` ```javascript eden.users({ id: '1' }).get.queryKey() // specific path params ``` ```javascript eden.users.get.queryFilter() ``` ```javascript eden.users.get.queryFilter({ role: 'admin' }) ``` ```javascript eden.users.get.queryFilter(undefined, { exact: true, stale: true }) ``` -------------------------------- ### Compare Server Definitions Source: https://eden-query.xkel.me/docs/comparisons Contrast Elysia server definition with tRPC router definition. ```typescript const app = new Elysia() .get('/users', () => db.users.findMany()) .get('/users/:id', ({ params }) => db.users.findUnique({ where: { id: params.id } })) .post('/users', ({ body }) => db.users.create({ data: body }), { body: t.Object({ name: t.String(), email: t.String({ format: 'email' }) }) }) export type App = typeof app ``` ```typescript const appRouter = t.router({ users: t.router({ list: t.procedure.query(() => db.users.findMany()), get: t.procedure .input(z.object({ id: z.string() })) .query(({ input }) => db.users.findUnique({ where: { id: input.id } })), create: t.procedure .input(z.object({ name: z.string(), email: z.string().email() })) .mutation(({ input }) => db.users.create({ data: input })) }) }) export type AppRouter = typeof appRouter ``` -------------------------------- ### Query with Path Parameters Source: https://eden-query.xkel.me/docs/guides/queries For routes with dynamic segments (e.g., `/users/:id`), call the path segment as a function with the parameter. ```javascript // GET /users/:id const { data } = useQuery( eden.users({ id: userId }).get.queryOptions() ) ``` -------------------------------- ### Create Typed Hooks Source: https://eden-query.xkel.me/docs Initialize the Eden TanStack Query hooks and client using the exported App type. ```typescript import { createEdenTanStackQuery } from 'eden-tanstack-react-query' import { treaty } from '@elysiajs/eden' import type { App } from './server' export const { EdenProvider, useEden, useEdenClient } = createEdenTanStackQuery() export const edenClient = treaty('http://localhost:3000') ``` -------------------------------- ### Path Parameters Handling Source: https://eden-query.xkel.me/docs/api-reference How to handle routes containing path parameters using the Eden proxy. ```APIDOC ## Path Parameters ### Description Routes with path parameters are handled by passing an object to the route segment. ### Usage Example ```typescript // Single path param: /users/:id eden.users({ id: '123' }).get.queryOptions(); // Nested path params: /posts/:postId/comments/:commentId eden.posts({ postId: '1' }).comments({ commentId: '2' }).get.queryOptions(); ``` ``` -------------------------------- ### Implement EdenProvider in React Source: https://eden-query.xkel.me/docs/api-reference/create-eden-tanstack-query Wrap the application with the EdenProvider to supply the Eden and Query clients to the component tree. ```tsx import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { EdenProvider, edenClient } from './lib/eden' const queryClient = new QueryClient() function App() { return ( ) } ``` -------------------------------- ### Compare Client Usage Source: https://eden-query.xkel.me/docs/comparisons Contrast client-side data fetching and mutation patterns between eden-tanstack-query and tRPC. ```typescript const eden = useEden() const { data } = useQuery(eden.users.get.queryOptions()) const createUser = useMutation({ ...eden.users.post.mutationOptions(), onSuccess: () => queryClient.invalidateQueries(eden.users.get.queryFilter()) }) ``` ```typescript const { data } = trpc.users.list.useQuery() const utils = trpc.useUtils() const createUser = trpc.users.create.useMutation({ onSuccess: () => utils.users.list.invalidate() }) ``` -------------------------------- ### Server-Side Prefetching with ensureQueryData Source: https://eden-query.xkel.me/docs/guides/ssr Use `ensureQueryData` in route loaders for server-side prefetching. Ensure your router and QueryClient are set up correctly. ```typescript import { createFileRoute } from '@tanstack/react-router' import { createEdenOptionsProxy } from 'eden-tanstack-react-query' import { treaty } from '@elysiajs/eden' import type { App } from '@/lib/server' export const Route = createFileRoute('/users')({ loader: async ({ context: { queryClient } }) => { const serverClient = treaty(import.meta.env.VITE_API_URL) const eden = createEdenOptionsProxy({ client: serverClient, queryClient }) await queryClient.ensureQueryData(eden.users.get.queryOptions()) }, component: UsersPage }) ``` -------------------------------- ### mutationOptions Source: https://eden-query.xkel.me/docs/api-reference/use-eden Creates type-safe options for useMutation. ```APIDOC ## POST mutationOptions ### Description Creates type-safe options for useMutation. ### Parameters #### Request Body - **opts** (EdenMutationOptionsIn) - Optional - TanStack Query mutation options (excluding reserved). ### Returns - **mutationKey** (EdenMutationKey) - Unique key based on route path. - **mutationFn** (MutationFunction) - Mutation function via Eden client. - **eden** (Object) - Route metadata. ``` -------------------------------- ### Implement Providers for App Router Source: https://eden-query.xkel.me/docs/guides/ssr Creates a client-side provider component to manage the QueryClient and Eden client lifecycle. ```typescript 'use client' import { useState } from 'react' import { QueryClientProvider } from '@tanstack/react-query' import { getQueryClient } from '@/lib/query-client' import { EdenProvider, edenClient } from '@/lib/eden' export function Providers({ children }: { children: React.ReactNode }) { const [queryClient] = useState(() => getQueryClient()) return ( {children} ) } ``` -------------------------------- ### Define Basic Path Parameters in Elysia Source: https://eden-query.xkel.me/docs/guides/path-parameters Define a route with a single path parameter using Elysia's type system. ```typescript import { Elysia, t } from 'elysia' const app = new Elysia() .get('/users/:id', ({ params }) => ({ id: params.id, name: `User ${params.id}`, email: `user${params.id}@example.com` }), { params: t.Object({ id: t.String() }) }) .listen(3000) export type App = typeof app ``` -------------------------------- ### Define Elysia Server with Typed Routes Source: https://eden-query.xkel.me/docs/getting-started Create an Elysia server with typed routes. The `export type App = typeof app` line is crucial for enabling type inference on the client. ```typescript import { Elysia, t } from 'elysia' import { cors } from '@elysiajs/cors' const app = new Elysia() .use(cors()) .get('/hello', () => ({ message: 'Hello from Elysia!' })) .get('/users', () => [ { id: '1', name: 'Alice', email: 'alice@example.com' }, { id: '2', name: 'Bob', email: 'bob@example.com' }, ]) .get('/users/:id', ({ params }) => ({ id: params.id, name: `User ${params.id}`, email: `user${params.id}@example.com`, })) .post( '/users', ({ body }) => ({ id: String(Date.now()), ...body }), { body: t.Object({ name: t.String(), email: t.String(), }), } ) .listen(3000) // This type export is what enables type inference on the client export type App = typeof app ``` -------------------------------- ### Infinite Query Filter Usage Source: https://eden-query.xkel.me/docs/guides/query-keys Demonstrates how to generate filter objects specifically for infinite queries using `infiniteQueryFilter()`. ```javascript eden.posts.get.infiniteQueryFilter() ``` ```javascript eden.posts.get.infiniteQueryFilter({ category: 'tech' }) ``` -------------------------------- ### Create Query Options with queryOptions Source: https://eden-query.xkel.me/docs/api-reference/use-eden Use `queryOptions` to generate type-safe options for TanStack Query functions like `useQuery`. It accepts query parameters and optional TanStack Query configurations. ```typescript eden.route.get.queryOptions(input?, opts?): QueryOptions ``` ```typescript const { data } = useQuery(eden.users.get.queryOptions()) const { data } = useQuery( eden.users.get.queryOptions( { role: 'admin' }, { staleTime: 5 * 60 * 1000 } ) ) const { data } = useQuery( eden.users({ id: '123' }).get.queryOptions() ) const { data } = useQuery( eden.users({ id: userId ?? '' }).get.queryOptions( userId ? undefined : skipToken ) ) ``` -------------------------------- ### Cache Operations with TanStack Query Source: https://eden-query.xkel.me/docs/guides/query-keys Illustrates how to perform various cache operations using Eden TanStack Query's generated keys with TanStack Query's client methods. ```APIDOC ## Cache Operations ### invalidateQueries Mark queries as stale and trigger a refetch: ```javascript const queryClient = useQueryClient() const eden = useEden() // Invalidate all users queries (partial matching) queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey() }) // Invalidate with queryFilter queryClient.invalidateQueries( eden.users.get.queryFilter() ) // Invalidate a specific user queryClient.invalidateQueries({ queryKey: eden.users({ id: '1' }).get.queryKey() }) ``` ### cancelQueries Cancel in-flight queries (useful for optimistic updates): ```javascript await queryClient.cancelQueries({ queryKey: eden.todos.get.queryKey() }) ``` ### getQueryData / setQueryData Read and write the cache directly: ```javascript // Read cached data const user = queryClient.getQueryData( eden.users({ id: '1' }).get.queryKey() ) // Write to cache queryClient.setQueryData( eden.users({ id: '1' }).get.queryKey(), { id: '1', name: 'Updated Name', email: 'updated@example.com' } ) ``` ### removeQueries Remove queries from the cache entirely: ```javascript queryClient.removeQueries({ queryKey: eden.users({ id: '1' }).get.queryKey() }) ``` ``` -------------------------------- ### Verify Query Keys for Path Params Source: https://eden-query.xkel.me/docs/troubleshooting Logs query keys to ensure unique identification for different path parameters. ```typescript console.log(eden.users({ id: '1' }).get.queryKey()) // [['users', 'get'], { input: { id: '1' }, type: 'query' }] console.log(eden.users({ id: '2' }).get.queryKey()) // [['users', 'get'], { input: { id: '2' }, type: 'query' }] ``` -------------------------------- ### Create Test Query Client Source: https://eden-query.xkel.me/docs/guides/testing Utility function to create a new QueryClient instance for testing with disabled retries and garbage collection. ```typescript import { QueryClient } from '@tanstack/react-query' export function createTestQueryClient() { return new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 }, mutations: { retry: false } } }) } ``` -------------------------------- ### Create Mock Eden Client Source: https://eden-query.xkel.me/docs/guides/testing Factory function to create a mock Eden client with mocked 'users' endpoint for testing. ```typescript import { vi } from 'vitest' export function createMockEdenClient() { return { users: Object.assign( (params: { id: string }) => ({ get: vi.fn().mockResolvedValue({ data: { id: params.id, name: 'User', email: 'user@example.com' }, error: null }), }), { get: vi.fn().mockResolvedValue({ data: [ { id: '1', name: 'Alice', email: 'alice@example.com' }, { id: '2', name: 'Bob', email: 'bob@example.com' } ], error: null }), post: vi.fn().mockResolvedValue({ data: { id: '3', name: 'New User', email: 'new@example.com' }, error: null }), } ) } } ``` -------------------------------- ### Handle Path Parameters as Strings Source: https://eden-query.xkel.me/docs/troubleshooting Ensures path parameters are passed as strings to match URL requirements. ```typescript // Error: number not assignable to string eden.users({ id: 123 }).get.queryOptions() // Correct eden.users({ id: String(userId) }).get.queryOptions() ``` -------------------------------- ### Create Data with useMutation Source: https://eden-query.xkel.me/docs/getting-started Use the `useMutation` hook to create or update data. The `mutationOptions()` method provides the configuration, and `queryClient.invalidateQueries` can be used in `onSuccess` to refetch data. ```typescript import { useMutation, useQueryClient } from '@tanstack/react-query' import { useEden } from '../lib/eden' export function CreateUser() { const eden = useEden() const queryClient = useQueryClient() const createUser = useMutation({ ...eden.users.post.mutationOptions(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey(), }) }, }) return ( ) } ``` -------------------------------- ### Path Parameter Handling Source: https://eden-query.xkel.me/docs/api-reference Syntax for accessing routes that contain dynamic path parameters. ```typescript // For routes with path params like /users/:id eden.users({ id: '123' }).get.queryOptions() // Nested params: /posts/:postId/comments/:commentId eden.posts({ postId: '1' }).comments({ commentId: '2' }).get.queryOptions() ``` -------------------------------- ### Test User List Component Source: https://eden-query.xkel.me/docs/guides/testing Renders a UserList component and asserts that user data is displayed after loading. ```typescript import { describe, it, expect } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import { useQuery } from '@tanstack/react-query' import { useEden } from '@/lib/eden' import { createTestWrapper, createMockEdenClient } from '../utils' function UserList() { const eden = useEden() const { data: users, isPending } = useQuery(eden.users.get.queryOptions()) if (isPending) return
Loading...
return (
    {users?.map(user =>
  • {user.name}
  • )}
) } describe('UserList', () => { it('renders users after loading', async () => { const mockClient = createMockEdenClient() const { Wrapper } = createTestWrapper(mockClient) render(, { wrapper: Wrapper }) expect(screen.getByText('Loading...')).toBeInTheDocument() await waitFor(() => { expect(screen.getByText('Alice')).toBeInTheDocument() expect(screen.getByText('Bob')).toBeInTheDocument() }) }) }) ``` -------------------------------- ### Implement Infinite Queries Source: https://eden-query.xkel.me/docs Use infiniteQueryOptions for paginated data fetching. ```typescript import { useInfiniteQuery } from '@tanstack/react-query' const { data, fetchNextPage, hasNextPage } = useInfiniteQuery( eden.posts.get.infiniteQueryOptions( { limit: 10 }, { getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined, initialPageParam: null, } ) ) ``` -------------------------------- ### Update Queries and Mutations Source: https://eden-query.xkel.me/docs/comparisons Syntax changes for queries and mutations during migration. ```typescript // Before: eden.users.get.useQuery() // After: const eden = useEden() const { data } = useQuery(eden.users.get.queryOptions()) ``` ```typescript // Before: eden.users.post.useMutation() // After: const mutation = useMutation(eden.users.post.mutationOptions()) ``` -------------------------------- ### initialCursor Option for Infinite Queries Source: https://eden-query.xkel.me/docs/guides/infinite-queries Sets the cursor value for the initial page fetch. The appropriate value depends on your API's cursor implementation (e.g., `null`, `0`, or `''`). ```javascript { initialCursor: null // or 0, '', depending on your API } ``` -------------------------------- ### Define Combined Path and Query Parameters in Elysia Source: https://eden-query.xkel.me/docs/guides/path-parameters Define a route that utilizes both path parameters and optional query parameters. ```typescript const app = new Elysia() .get('/users/:id/posts', ({ params, query }) => ({ userId: params.id, posts: [], page: query.page ?? 1, limit: query.limit ?? 10 }), { params: t.Object({ id: t.String() }), query: t.Object({ page: t.Optional(t.Number()), limit: t.Optional(t.Number()) }) }) ``` -------------------------------- ### Query with Input Parameters Source: https://eden-query.xkel.me/docs Pass query parameters or request body to the query options factory. ```typescript // Query params: GET /users?role=admin eden.users.get.queryOptions({ role: 'admin' }) // With TanStack Query options eden.users.get.queryOptions( { role: 'admin' }, { staleTime: 5 * 60 * 1000 } ) ``` -------------------------------- ### Import App Type Source: https://eden-query.xkel.me/docs/troubleshooting Uses import type to ensure proper type availability. ```typescript import type { App } from '../server' ``` -------------------------------- ### Define base Eden query options Source: https://eden-query.xkel.me/docs/api-reference/types Interface for base options used in Eden requests. ```typescript interface EdenQueryBaseOptions { eden?: { /** Abort request on component unmount */ abortOnUnmount?: boolean } } ``` -------------------------------- ### Define Elysia Server Source: https://eden-query.xkel.me/docs Define the server routes and export the App type for type inference. ```typescript import { Elysia, t } from 'elysia' const app = new Elysia() .get('/users', () => [ { id: '1', name: 'Alice' }, { id: '2', name: 'Bob' } ]) .get('/users/:id', ({ params }) => ({ id: params.id, name: `User ${params.id}` })) .post('/users', ({ body }) => ({ id: String(Date.now()), ...body }), { body: t.Object({ name: t.String() }) }) .listen(3000) export type App = typeof app ``` -------------------------------- ### Partial Matching for Invalidation Source: https://eden-query.xkel.me/docs/guides/query-keys Illustrates how partial matching with query keys can be used for broad invalidation. A key without input matches all queries for that route. ```javascript // Invalidates ALL users queries, regardless of input queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey() }) ``` ```javascript // Only invalidates the specific query with role='admin' queryClient.invalidateQueries({ queryKey: eden.users.get.queryKey({ role: 'admin' }) }) ``` -------------------------------- ### Handle Path Parameters Source: https://eden-query.xkel.me/docs Access routes with dynamic path parameters using function calls. ```typescript // Route: /users/:id eden.users({ id: '123' }).get.queryOptions() // Nested: /posts/:postId/comments/:commentId eden.posts({ postId: '1' }).comments({ commentId: '2' }).get.queryOptions() ``` -------------------------------- ### Fetch Data with Path Parameters Source: https://eden-query.xkel.me/docs/getting-started For routes with path parameters like `/users/:id`, call the route segment as a function, passing the parameter values. ```typescript const { data: user } = useQuery( eden.users({ id: userId }).get.queryOptions() ) ``` -------------------------------- ### Define Query and Mutation Keys Source: https://eden-query.xkel.me/docs/api-reference/types Structures for TanStack Query cache keys and associated metadata. ```typescript type EdenQueryKey = | [path: string[]] | [path: string[], meta: EdenQueryKeyMeta] // Examples: [['users', 'get']] [['users', 'get'], { input: { role: 'admin' } }] [['posts', 'get'], { input: { limit: 10 }, type: 'infinite' }] ``` ```typescript type EdenMutationKey = [path: string[]] // Example: [['users', 'post']] ``` ```typescript type EdenQueryKeyMeta = { input?: TInput type?: 'query' | 'infinite' } ``` ```typescript type QueryType = 'query' | 'infinite' | 'any' ``` -------------------------------- ### Define QueryClient Factory Source: https://eden-query.xkel.me/docs/guides/ssr Ensures a singleton QueryClient instance is used on the client while creating a fresh instance per request on the server. ```typescript import { QueryClient } from '@tanstack/react-query' function makeQueryClient() { return new QueryClient({ defaultOptions: { queries: { staleTime: 60 * 1000, } } }) } let browserQueryClient: QueryClient | undefined export function getQueryClient() { if (typeof window === 'undefined') { return makeQueryClient() } if (!browserQueryClient) { browserQueryClient = makeQueryClient() } return browserQueryClient } ```