/** * React Context & Provider for Eden TanStack Query * * Provides React context and hooks for sharing Eden client across components. * Following tRPC's pattern of factory functions for type safety. */ import type { Treaty } from "@elysiajs/eden" import type { QueryClient } from "@tanstack/react-query" import type { AnyElysia } from "elysia" import * as React from "react" import { type CreateEdenOptionsProxyOptions, createEdenOptionsProxy, } from "./proxy/createOptionsProxy" import type { EdenOptionsProxy } from "./types/decorators" // ============================================================================ // Provider Props // ============================================================================ /** Props for EdenProvider component */ export interface EdenProviderProps { /** Eden Treaty client instance */ client: Treaty.Create /** TanStack QueryClient instance */ queryClient: QueryClient /** React children */ children: React.ReactNode } // ============================================================================ // Context Creation Result // ============================================================================ /** Result of createEdenContext */ export interface CreateEdenContextResult { /** Provider component for wrapping app */ EdenProvider: React.FC> /** Hook to get the options proxy */ useEden: () => EdenOptionsProxy /** Hook to get the raw Eden client */ useEdenClient: () => Treaty.Create } // ============================================================================ // Context Factory // ============================================================================ /** * Creates a set of type-safe provider and consumer hooks for Eden. * * @example * ```tsx * import { createEdenContext } from 'eden-tanstack-react-query' * import type { App } from './server' * * const { EdenProvider, useEden, useEdenClient } = createEdenContext() * * function App() { * return ( * * * * * * ) * } * * function UserList() { * const eden = useEden() * const { data } = useQuery(eden.api.users.get.queryOptions()) * return
    {data?.map(u =>
  • {u.name}
  • )}
* } * ``` */ export function createEdenContext< TApp extends AnyElysia, >(): CreateEdenContextResult { // Create contexts with null defaults // Using unknown to allow type-safe access via hooks const EdenClientContext = React.createContext | null>( null, ) const EdenProxyContext = React.createContext | null>( null, ) // Provider component const EdenProvider: React.FC> = (props) => { const { client, queryClient, children } = props // Memoize proxy to prevent recreating on every render const proxy = React.useMemo( () => createEdenOptionsProxy({ client, queryClient, } as CreateEdenOptionsProxyOptions), [client, queryClient], ) return ( {children} ) } EdenProvider.displayName = "EdenProvider" // Hook to get options proxy function useEden(): EdenOptionsProxy { const proxy = React.useContext(EdenProxyContext) if (!proxy) { throw new Error( "useEden must be used within an EdenProvider. " + "Make sure to wrap your app with .", ) } return proxy } // Hook to get raw Eden client function useEdenClient(): Treaty.Create { const client = React.useContext(EdenClientContext) if (!client) { throw new Error( "useEdenClient must be used within an EdenProvider. " + "Make sure to wrap your app with .", ) } return client } return { EdenProvider, useEden, useEdenClient, } }