/** * Type declarations for @farm.js/core/client * * Provides stable exports for Link, useRouter, and API client so TypeScript * and IDEs resolve them even when the build output omits them. The generated * farm.d.ts in your app augments LinkDefaultRoute for typed href. */ import type { AnchorHTMLAttributes, ComponentType, FormEvent, FormHTMLAttributes, ReactElement, ReactNode, RefObject, RefAttributes, } from "react"; import type { DefinedCacheKey, InferCacheKeyData, RouteDataCacheKey } from "@farm.js/core/cache"; import type { ServerFn } from "@farm.js/core/server-fn"; import type { createAPIClient as coreCreateAPIClient, RouteAPIClient as CoreRouteAPIClient, APIClientOptions as CoreAPIClientOptions, ClientHeaders as CoreClientHeaders, ClientLifecycleHooks as CoreClientLifecycleHooks, ClientRequestEvent as CoreClientRequestEvent, ClientResponseEvent as CoreClientResponseEvent, ApiClients as CoreApiClients, APIClientWithoutIntegrationsOptions as CoreAPIClientWithoutIntegrationsOptions, } from "../dist/client"; declare global { namespace FarmJS { /** @internal Application route patterns registered by generated types. */ interface RouteRegistry {} } } declare module "@farm.js/core/client" { export interface MiddlewareProps { data: Map; } export interface PluginContextProps { data: Map; } export type AppRoutePattern = FarmJS.RouteRegistry extends { pattern: infer TPattern extends string; } ? TPattern : string; type FarmRoutePropsDefault = never; type FarmRoutePropsTarget = AppRoutePattern; type StripPageRouteSuffix = TRoute extends `${infer TPath}?${string}` ? StripPageRouteSuffix : TRoute extends `${infer TPath}#${string}` ? StripPageRouteSuffix : TRoute; type SimplifyPageRouteParams = { [TKey in keyof TValue]: TValue[TKey] } & {}; type PageRouteSegmentParams = TSegment extends `[[...${infer TParam}]]` ? { [TKey in TParam]?: string } : TSegment extends `[...${infer TParam}]` ? { [TKey in TParam]: string } : TSegment extends `[${infer TParam}]` ? { [TKey in TParam]: string } : {}; type ExtractPageRouteParams = TRoute extends `${infer TSegment}/${infer TRest}` ? PageRouteSegmentParams & ExtractPageRouteParams : PageRouteSegmentParams; export type PageRouteParams = string extends TRoute ? Record : TRoute extends string ? SimplifyPageRouteParams>> : never; type ResolvePageRouteParams = [TRoute] extends [never] ? Record : TRoute extends string ? PageRouteParams : Record; export interface PageProps { params: ResolvePageRouteParams; searchParams: Promise>; path: string; middleware?: MiddlewareProps; context?: PluginContextProps; } export interface LoadingProps { params: ResolvePageRouteParams; searchParams: Promise>; search?: Record; path: string; middleware?: MiddlewareProps; context?: PluginContextProps; } export interface ErrorProps< TRoute extends FarmRoutePropsTarget = FarmRoutePropsDefault, > extends LoadingProps { error: unknown; reset: () => void; } export interface LayoutProps { children: ReactNode; params: ResolvePageRouteParams; } export type MetadataProps = PageProps; export interface LayoutMetadataProps< TRoute extends FarmRoutePropsTarget = FarmRoutePropsDefault, > { params: ResolvePageRouteParams; } export type StaticPathPrimitive = string | number | boolean; export type StaticPathParams = Record< string, StaticPathPrimitive | readonly StaticPathPrimitive[] >; type StaticRouteSegmentParams = TSegment extends `[[...${infer TParam}]]` ? { [TKey in TParam]?: readonly StaticPathPrimitive[] } : TSegment extends `[...${infer TParam}]` ? { [TKey in TParam]: readonly StaticPathPrimitive[] } : TSegment extends `[${infer TParam}]` ? { [TKey in TParam]: StaticPathPrimitive } : {}; type ExtractStaticRouteParams = TRoute extends `${infer TSegment}/${infer TRest}` ? StaticRouteSegmentParams & ExtractStaticRouteParams : StaticRouteSegmentParams; export type StaticRouteParams = string extends TRoute ? StaticPathParams : TRoute extends string ? SimplifyPageRouteParams>> : never; type ResolveStaticRouteParams = [TRoute] extends [never] ? StaticPathParams : TRoute extends string ? StaticRouteParams : StaticPathParams; export type GenerateStaticParams = () => | Array> | Promise>>; export interface Metadata { title?: string | { default?: string; template?: string }; description?: string; keywords?: string | string[]; authors?: Array<{ name: string; url?: string }>; creator?: string; publisher?: string; robots?: string | { index?: boolean; follow?: boolean }; openGraph?: Record; twitter?: Record; alternates?: Record; icons?: Record; manifest?: string; } export type StoreState = Record; export type StoreValueUpdater = T | ((previous: T) => T); export type StorePatch = Partial | ((state: T) => Partial); export type StoreListener = (state: T, previousState: T) => void; export type StoreKeyListener = ( value: T[K], previousValue: T[K], ) => void; export type StoreKeysListener = ( value: Pick, previousValue: Pick, ) => void; export type StoreFields = { [K in keyof T]: { (): T[K]; get(): T[K]; set(value: StoreValueUpdater): T[K]; subscribe(listener: StoreKeyListener): () => void; }; }; export interface StoreApi { use(): T; use(key: K): T[K]; use(keys: readonly K[]): Pick; get(): T; get(key: K): T[K]; set(key: K, value: StoreValueUpdater): T[K]; set(patch: StorePatch): T; replace(nextState: T | ((state: T) => T)): T; reset(): T; subscribe(listener: StoreListener): () => void; subscribe(key: K, listener: StoreKeyListener): () => void; subscribe(keys: readonly K[], listener: StoreKeysListener): () => void; } export type Store = {}> = StoreApi & StoreFields & TMethods; export function createStore = {}>( initialState: T, extend?: (store: Store) => TMethods, ): Store; export type PrefetchBehavior = false | "intent" | "viewport" | "render" | "none"; /** URI schemes recognized as typed external Link targets. Apps may augment this interface. */ export interface LinkExternalUriSchemes { about: true; blob: true; data: true; file: true; ftp: true; ftps: true; geo: true; git: true; http: true; https: true; im: true; intent: true; irc: true; ircs: true; magnet: true; mailto: true; market: true; sms: true; ssh: true; tel: true; urn: true; vscode: true; webcal: true; ws: true; wss: true; } type ExternalUriScheme = Extract; type UriSchemeLetter = | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"; type UriSchemeStart = UriSchemeLetter | Uppercase; type UriSchemeCharacter = | UriSchemeStart | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "+" | "-" | "."; type IsUriSchemeTail = TValue extends "" ? true : TValue extends `${infer First}${infer Rest}` ? First extends UriSchemeCharacter ? IsUriSchemeTail : false : false; type IsUriScheme = TValue extends `${infer First}${infer Rest}` ? First extends UriSchemeStart ? IsUriSchemeTail : false : false; type KnownExternalHref = `//${string}` | `${ExternalUriScheme}:${string}`; /** External URLs are never type-checked as routes; use for http/https/mailto etc. */ export type ExternalHref = string extends THref ? KnownExternalHref : THref extends `//${string}` ? THref : THref extends `${infer Scheme}:${string}` ? IsUriScheme extends true ? THref : never : never; export interface LinkDefaultRoute {} export type DefaultRoutePath = LinkDefaultRoute extends { _: infer TRoute extends string } ? TRoute : string; export type DefaultRoutePattern = LinkDefaultRoute extends { pattern: infer TRoute extends string; } ? TRoute : DefaultRoutePath; export type DefaultRouteHref = DefaultRoutePath | DefaultRoutePattern; export type RouteHref = | TRoute | `${TRoute}?${string}` | `${TRoute}#${string}` | `${TRoute}?${string}#${string}`; /** A generated route with params already filled into its pathname. */ export type ResolvedRouteHref = RouteHref; export type RouteParamPrimitive = string | number | boolean; export type RouteParamValue = RouteParamPrimitive | readonly RouteParamPrimitive[]; export type RouteOptionalParamValue = RouteParamValue | null | undefined; export type RouteQueryValue = | RouteParamPrimitive | readonly RouteParamPrimitive[] | null | undefined; export type RouteParams = string extends TRoute ? Record : ExtractRouteParams>; export type StripRouteSuffix = TRoute extends `${infer Path}?${string}` ? StripRouteSuffix : TRoute extends `${infer Path}#${string}` ? StripRouteSuffix : TRoute; export type ExtractRouteParams = Simplify< ExtractOptionalCatchAllParams & ExtractCatchAllParams & ExtractDynamicParams >; export type ExtractOptionalCatchAllParams = TRoute extends `${string}[[...${infer Param}]]${infer Rest}` ? { [Key in Param]?: RouteOptionalParamValue } & ExtractOptionalCatchAllParams : {}; export type ExtractCatchAllParams = TRoute extends `${string}[...${infer Param}]${infer Rest}` ? Param extends `[...${string}` ? ExtractCatchAllParams : { [Key in Param]: RouteParamValue } & ExtractCatchAllParams : {}; export type ExtractDynamicParams = TRoute extends `${string}[${infer Param}]${infer Rest}` ? Param extends `...${string}` | `[...${string}` ? ExtractDynamicParams : { [Key in Param]: RouteParamValue } & ExtractDynamicParams : {}; export type Simplify = { [Key in keyof T]: T[Key] } & {}; export type LinkRouteParamsProps = string extends TRoute ? { params?: Record } : keyof RouteParams extends never ? { params?: Record } : { params: RouteParams }; export type RoutesWithRequiredParams = TRoute extends string ? keyof RouteParams extends never ? never : TRoute : never; export type LinkRouteTargetProps = [ RoutesWithRequiredParams, ] extends [never] ? { href: RouteHref; params?: Record; } : TRoute extends string ? { href: RouteHref; } & LinkRouteParamsProps : never; export type LinkExternalTargetProps = { href: ExternalHref; params?: never; }; export type LinkProps< TRoute extends string = DefaultRouteHref, THref extends string = string, > = Omit, "href"> & (LinkExternalTargetProps | LinkRouteTargetProps) & { /** Internal route path (typed when route types are generated) or external URL (never raises route-type errors). */ prefetch?: PrefetchBehavior | boolean | "hover" | "viewport" | "none"; query?: URLSearchParams | Record; hash?: string; trailingSlash?: boolean; prefetchDelay?: number; replace?: boolean; scroll?: boolean; viewTransition?: FarmViewTransitionMode; }; export type LinkComponent = < TRoute extends string = DefaultRouteHref, THref extends string = string, >( props: LinkProps & RefAttributes, ) => ReactElement; export const Link: LinkComponent; export interface FarmNavigationBlockerContext { from: string; to: string; action: "push" | "replace" | "pop"; } export type FarmNavigationBlocker = ( context: FarmNavigationBlockerContext, ) => boolean | void | Promise; export type FarmViewTransitionMode = boolean | "auto"; export interface FarmNavigateOptions { replace?: boolean; scroll?: boolean; state?: unknown; viewTransition?: FarmViewTransitionMode; } export interface FarmNavigationLocation { href: string; pathname: string; search: string; hash: string; } export interface FarmNavigationState { state: "idle" | "loading"; pending: boolean; from: string | null; to: FarmNavigationLocation | null; action: FarmNavigationBlockerContext["action"] | null; startedAt: number | null; } export type FarmNavigationListener = (state: FarmNavigationState) => void; export interface RouterOptions { prefetchTimeout?: number; cacheMaxAge?: number; scrollRestoration?: boolean; shouldUseDocumentNavigation?: (pathname: string) => boolean; deploymentId?: string; } export class SPARouter { constructor(options?: RouterOptions); setNavigationHandler(handler: (data: Record) => Promise): void; navigate(href: string, options?: FarmNavigateOptions): Promise; prefetch(href: string): Promise; observeForPrefetch(element: HTMLAnchorElement): void; unobserveForPrefetch(element: HTMLAnchorElement): void; addBlocker(blocker: FarmNavigationBlocker): () => void; getNavigationState(): FarmNavigationState; subscribeNavigation(listener: FarmNavigationListener): () => void; registerScrollElement(key: string, element: HTMLElement): () => void; pushState(state: unknown, href?: string): void; replaceState(state: unknown, href?: string): void; clearCache(): void; } export function getRouter(): SPARouter; export interface FarmChunkRecoveryOptions { maxAgeMs?: number; storageKey?: string; onRecover?: (error: unknown) => void; reload?: () => void; storage?: Pick | null; location?: Pick; now?: () => number; } export interface UseRouterOptions { basePath?: string; routes?: Array; } export interface UseBlockerOptions { when: boolean | ((context: FarmNavigationBlockerContext) => boolean); message?: string; shouldBlock?: (context: FarmNavigationBlockerContext) => boolean | Promise; } export interface UseBlockerReturn { active: boolean; } export function useRouter(options?: UseRouterOptions): { pathname: string; searchParams: URLSearchParams; params: Record; pageState: unknown; push: (path: string) => void; replace: (path: string) => void; pushState: (state: TState, href?: string) => void; replaceState: (state: TState, href?: string) => void; back: () => void; forward: () => void; }; export function usePageState(): TState | null; export function useNavigation(): FarmNavigationState; export function useBlocker(options: UseBlockerOptions): UseBlockerReturn; export function useScrollRestoration( key: string, ): RefObject; export function navigateTo(href: string, options?: FarmNavigateOptions): Promise; export function prefetch(href: string): Promise; export function pushState(state: TState, href?: string): void; export function replaceState(state: TState, href?: string): void; export function readPageState(): TState | null; export function isChunkLoadError(errorLike: unknown): boolean; export function installChunkErrorRecovery(options?: FarmChunkRecoveryOptions): () => void; export type ClientHeaders = CoreClientHeaders; export type ClientLifecycleHooks = CoreClientLifecycleHooks; export type ClientRequestEvent = CoreClientRequestEvent; export type ClientResponseEvent = CoreClientResponseEvent; export interface APIClientOptions extends CoreAPIClientOptions { baseURL?: string; headers?: ClientHeaders; cacheDefaults?: CacheOptions; } export type StatusPhase = | "idle" | "pending" | "success" | "error" | "revalidating" | "invalidated"; export type StatusEvent = { phase: StatusPhase; requestId: string; method: "GET" | "HEAD" | "QUERY" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS"; key: string; input?: unknown; data?: TData; error?: TError; isBackground?: boolean; timestamp: number; }; export type CacheKey = string & { readonly __farmCacheData?: TData; }; export type APIResult = { data: TData | undefined; error: TError | null; key: CacheKey; }; export interface FarmAPIStream extends AsyncIterable { readonly response: Response; cancel(reason?: unknown): Promise; } export class APIClientError< TCode extends string = string, TData = unknown, TStatus extends number = number, > extends Error { readonly code: TCode; readonly data: TData; readonly status: TStatus; readonly response?: Response; constructor( code: TCode, data: TData, options: { status: TStatus; message: string; response?: Response; }, ); } export type APIClientSystemError = | APIClientError<"http_error", unknown, number> | APIClientError<"aborted" | "timeout", unknown, 0> | APIClientError<"network_error", unknown, 0>; export type RequestEvent = { requestId: string; method: StatusEvent["method"]; key: string; path: string; input?: unknown; attempt: number; timestamp: number; }; export type ResponseEvent = { requestId: string; method: StatusEvent["method"]; key: string; path: string; input?: unknown; attempt: number; timestamp: number; response?: Response; data?: TData; error?: TError; ok?: boolean; status?: number; }; export type CachePolicy = "cache-first" | "network-only" | "stale-while-revalidate"; export type CacheOptions = { key?: RouteDataCacheKey; policy?: CachePolicy; staleTime?: number; gcTime?: number; dedupeMs?: number; /** Allow the configured client cache persistence adapter to store this read. */ persist?: boolean; }; export type RetryOptions = { count?: number; delay?: number | ((attempt: number) => number); }; export type InvalidateTarget = | RouteDataCacheKey | { key: RouteDataCacheKey; } | { path: string; method?: "GET" | "HEAD" | "QUERY" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS"; input?: unknown; } | [CallableRouteRef, unknown?]; export type InvalidateOptions = | InvalidateTarget[] | { targets: InvalidateTarget[]; refetch?: boolean; }; export const FARM_CACHE_INVALIDATION_CHANNEL: "farm:cache-invalidation"; export type CrossTabCacheInvalidationOptions = { /** Override the BroadcastChannel name, e.g. to isolate multiple apps on one origin. */ channelName?: string; }; export function enableCrossTabCacheInvalidation( options?: CrossTabCacheInvalidationOptions, ): () => void; export const FARM_CLIENT_CACHE_PERSIST_VERSION: string; export type PersistedEntry = { data: unknown; updatedAt: number; staleAt: number; gcAt?: number; version: string; }; export type FarmClientCacheAdapter = { keys(): Promise; get(key: string): Promise; set(key: string, entry: PersistedEntry): Promise; delete(key: string): Promise; clear(): Promise; getMany?(keys: string[]): Promise>; setMany?(entries: Array<[string, PersistedEntry]>): Promise; }; export type FarmClientCacheStorage = { getItem(key: string): Promise; setItem(key: string, value: T): Promise; removeItem(key: string): Promise; getKeys?(base?: string): Promise; keys?(base?: string): Promise; clear?(base?: string): Promise; }; export type ClientCachePersistenceOptions = { version?: string; persistKey?: (key: string) => boolean; flushDelayMs?: number; }; export function defineClientCacheAdapter(adapter: FarmClientCacheAdapter): FarmClientCacheAdapter; export function storageClientCacheAdapter( storage: FarmClientCacheStorage, options?: { base?: string }, ): FarmClientCacheAdapter; export function clearPersistedCache(): Promise; /** @internal Wired by the generated client entry from `cache.client.adapter`. */ export function initPersistedClientCache( adapter: FarmClientCacheAdapter, options?: ClientCachePersistenceOptions, ): () => void; /** @internal Entry point used by generated client entries. */ export function initConfiguredClientCachePersistence( adapterModule: unknown, options?: ClientCachePersistenceOptions, ): void; export type OptimisticUpdate = | [CallableRouteRef, unknown, (prev: any) => any] | [CacheKey | DefinedCacheKey | string, (prev: any) => any]; export type OptimisticOptions = { update: TUpdates & NormalizeOptimisticUpdates; rollbackOnError?: boolean; }; export type ClientOptions< TData = unknown, TError = unknown, TUpdates extends readonly unknown[] = readonly OptimisticUpdate[], > = { key?: CacheKey | RouteDataCacheKey; signal?: AbortSignal; timeoutMs?: number; cache?: CacheOptions; retry?: RetryOptions; invalidate?: InvalidateOptions; optimistic?: OptimisticOptions; onRequest?: (event: RequestEvent) => void; onResponse?: ( data: TData | undefined, error: TError | null, event: ResponseEvent, ) => void; onSuccess?: (data: TData) => void; onError?: (err: TError) => void; onSettled?: (data?: TData, err?: TError | null) => void; onStatus?: (event: StatusEvent) => void; }; type AnyRouteRef = (...args: any[]) => any; type RouteRef = { readonly __farmRouteInput: TInput; readonly __farmRouteData: TData; }; type CallableRouteRef = AnyRouteRef & RouteRef; type InferRouteInput = TRoute extends { readonly __farmRouteInput: infer TInput } ? TInput : never; type InferRouteData = TRoute extends { readonly __farmRouteData: infer TData } ? TData : never; type NormalizeOptimisticUpdate = TUpdate extends readonly [ infer TRoute, unknown, (prev: any) => any, ] ? TRoute extends RouteRef ? [ TRoute, InferRouteInput | undefined, (prev: InferRouteData | undefined) => InferRouteData, ] : never : TUpdate extends readonly [infer TKey, (prev: any) => any] ? TKey extends DefinedCacheKey ? [TKey, (prev: InferCacheKeyData | undefined) => InferCacheKeyData] : TKey extends CacheKey ? [TKey, (prev: TData | undefined) => TData] : TKey extends string ? [TKey, (prev: unknown) => unknown] : never : never; type NormalizeOptimisticUpdates = { [K in keyof TUpdates]: NormalizeOptimisticUpdate; }; /** * Minimal structural type for Farm.js endpoints used for client inference. * This avoids depending on build-hash-based type files. */ type TypedEndpointLike = { __types: { body: any; inputBody?: any; query: any; response: any; errors?: any; }; }; type SimplifyEndpointInput = { [K in keyof T]: T[K]; } & {}; type IsNever = [T] extends [never] ? true : false; type IsAny = 0 extends 1 & T ? true : false; type RequiredKeys = T extends object ? { [K in keyof T]-?: {} extends Pick ? never : K; }[keyof T] : never; type BodyInputProp = IsNever extends true ? {} : IsAny extends true ? { body?: TValue } : undefined extends TValue ? { body?: TValue } : { body: TValue }; type QueryInputProp = IsNever extends true ? {} : IsAny extends true ? { query?: TValue } : undefined extends TValue ? { query?: TValue } : RequiredKeys extends never ? { query?: TValue } : { query: TValue }; type HasRequiredKeys = RequiredKeys extends never ? false : true; // Type utilities to extract endpoint input/output types type InferEndpointBody = T extends { __types: { inputBody: infer TInputBody; }; } ? TInputBody : T extends { __types: { body: infer TBody; }; } ? TBody : never; type InferEndpointInput = T extends { __types: { query: infer TQuery; }; } ? SimplifyEndpointInput< BodyInputProp> & QueryInputProp > : {}; type InferEndpointOutput = T extends { __types: { response: infer R; }; } ? R extends { readonly __farmStreamItem: infer TItem } ? FarmAPIStream : R : any; type InferEndpointError = T extends { __types: { errors: infer TErrors; }; } ? keyof TErrors extends never ? Error : | { [TCode in keyof TErrors]: TErrors[TCode] extends { data: infer TData; status: infer TStatus extends number; } ? APIClientError : never; }[keyof TErrors] | APIClientSystemError : Error; type EndpointMethod = (< TUpdates extends readonly unknown[] = readonly OptimisticUpdate[], >( ...args: HasRequiredKeys> extends true ? [ options: InferEndpointInput, clientOptions?: ClientOptions, InferEndpointError, TUpdates>, ] : [ options?: InferEndpointInput, clientOptions?: ClientOptions, InferEndpointError, TUpdates>, ] ) => Promise, InferEndpointError>>) & RouteRef, InferEndpointInput>; export type MutationStatus = "idle" | "pending" | "success" | "error"; export type ServerFnActionStatus = "idle" | "pending" | "success" | "error"; export type ServerFnSubmit = [unknown] extends [TInput] ? (input?: TInput | FormData) => Promise : (input: TInput | FormData) => Promise; export type ServerFnOptimisticContext = { input: TInput | FormData | undefined; formData?: FormData; current: TResult | null; }; export type UseServerFnOptions = { initialResult?: TResult | null; resetOnSubmit?: boolean; throwOnFormError?: boolean; optimistic?: ( context: ServerFnOptimisticContext, ) => TResult | null | undefined; rollbackOnError?: boolean; /** Retry failed submissions with the API client's retry shape. Defaults to no retries. */ retry?: RetryOptions; onSuccess?: (result: TResult) => void; onError?: (error: TError) => void; onSettled?: (result: TResult | null, error: TError | null) => void; }; export type UseActionFormProps = Omit, "action">; export type RouteActionTarget> = { readonly action: TServerFn; }; export type UseActionReturn = ServerFnSubmit< TInput, TResult > & { pending: boolean; status: ServerFnActionStatus; data: TResult | null; result: TResult | null; error: TError | null; formAction: (formData: FormData) => Promise; Form: ComponentType; reset: () => void; }; export function useAction( route: RouteActionTarget>, options?: UseServerFnOptions, ): UseActionReturn; export function useAction( serverFn: ServerFn, options?: UseServerFnOptions, ): UseActionReturn; export type AnyMutationTarget = (...args: any[]) => Promise; export type InferMutationVariables = Parameters extends [] ? undefined : Parameters[0]; export type InferMutationData = TTarget extends { readonly __farmRouteData: infer TData; } ? TData : Awaited>; export type InferMutationError = TTarget extends { readonly __farmServerFnError: infer TError; } ? TError : TTarget extends (...args: any[]) => Promise> ? TError : Error; export type MutationOptimisticContext = { variables: TVariables | undefined; current: TData | null; }; export type UseMutationOptions = { initialData?: TData | null; resetOnMutate?: boolean; /** * `"always"` (default) dispatches regardless of connectivity. `"online"` * pauses a submission while the browser is offline and resumes it on the * `online` event instead of failing it. */ networkMode?: MutationNetworkMode; optimistic?: ( context: MutationOptimisticContext, ) => TData | null | undefined; rollbackOnError?: boolean; request?: ClientOptions; onSuccess?: (data: TData, variables: TVariables | undefined) => void; onError?: (error: TError, variables: TVariables | undefined) => void; onSettled?: ( data: TData | null, error: TError | null, variables: TVariables | undefined, ) => void; }; export type MutationAsync> = [] extends Parameters ? (variables?: InferMutationVariables) => Promise : (variables: InferMutationVariables) => Promise; export type MutationTrigger = [] extends Parameters ? (variables?: InferMutationVariables) => void : (variables: InferMutationVariables) => void; export type MutationNetworkMode = "always" | "online"; export type UseMutationReturn< TTarget extends AnyMutationTarget, TData = InferMutationData, TError = InferMutationError, > = { pending: boolean; /** True while a submission is waiting for the browser to come back online. */ paused: boolean; status: MutationStatus; data: TData | null; error: TError | null; variables: InferMutationVariables | undefined; mutate: MutationTrigger; mutateAsync: MutationAsync; reset: () => void; }; export function useMutation( target: TTarget, options?: UseMutationOptions< InferMutationVariables, InferMutationData, InferMutationError >, ): UseMutationReturn; export type FetcherState = "idle" | "submitting"; export class FetcherInputError extends Error { readonly name: "FetcherInputError"; readonly code: "input_error"; readonly status: 0; readonly data: undefined; readonly cause: unknown; constructor(cause: unknown); } export type FetcherFormDataContext = { form: HTMLFormElement | null; submitter: HTMLElement | null; }; export type UseFetcherOptions = Omit< UseMutationOptions< InferMutationVariables, InferMutationData, InferMutationError | FetcherInputError >, "request" > & { request?: UseMutationOptions< InferMutationVariables, InferMutationData, InferMutationError >["request"]; mapFormData?: ( formData: FormData, context: FetcherFormDataContext, ) => InferMutationVariables; }; export type FetcherFormProps = Omit< FormHTMLAttributes, "action" | "onSubmit" > & { action?: string | ((formData: FormData) => void | Promise); onSubmit?: (event: FormEvent) => void; }; type FetcherInput = InferMutationVariables | FormData; export type FetcherSubmitAsync = [] extends Parameters ? (input?: FetcherInput) => Promise> : (input: FetcherInput) => Promise>; export type FetcherSubmit = [] extends Parameters ? (input?: FetcherInput) => void : (input: FetcherInput) => void; export type UseFetcherReturn = { state: FetcherState; status: MutationStatus; pending: boolean; /** True while a submission is waiting for the browser to come back online. */ paused: boolean; data: InferMutationData | null; error: InferMutationError | FetcherInputError | null; variables: InferMutationVariables | undefined; formData: FormData | null; submit: FetcherSubmit; submitAsync: FetcherSubmitAsync; Form: ComponentType; reset: () => void; }; export function useFetcher( target: TTarget, options?: UseFetcherOptions, ): UseFetcherReturn; type RouterToClient = { [K in keyof T]: T[K] extends TypedEndpointLike ? EndpointMethod : T[K] extends Record ? RouterToClient : EndpointMethod; }; // Keep all overloads and integration inference tied to the implementation. export const createAPIClient: typeof coreCreateAPIClient; export type ApiClients< TRouter extends Record, TIntegrations extends Record = {}, > = CoreApiClients; export function createApiClients>( options: CoreAPIClientWithoutIntegrationsOptions, ): { api: CoreRouteAPIClient; apiClient: CoreRouteAPIClient }; export function createApiClients< TRouter extends Record, TIntegrations extends Record = {}, >(options?: APIClientOptions): ApiClients; export function createServerAPIClient>( endpoints: TEndpoints, ): TEndpoints; export type FarmIntegrationAPIMethod = | "GET" | "QUERY" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD"; export type FarmIntegrationAPIBodyFormat = "json" | "form" | "none"; export type FarmIntegrationAPIResponseFormat = "json" | "text" | "response"; export interface FarmIntegrationAPIOperation< TBody = never, TQuery = never, TResponse = unknown, TServer extends boolean = false, TMethod extends FarmIntegrationAPIMethod = FarmIntegrationAPIMethod, > { readonly kind: "farm-integration-api-operation"; path: string; method: TMethod; bodyFormat?: FarmIntegrationAPIBodyFormat; responseFormat?: FarmIntegrationAPIResponseFormat; headers?: Record; credentials?: RequestCredentials; isServer?: TServer; __pathless?: boolean; __types?: { body: TBody; query: TQuery; response: TResponse; }; } export type FarmIntegrationAPI = { [key: string]: FarmIntegrationAPI | FarmIntegrationAPIOperation; }; export type FarmIntegrationRouteOperationCarrier< TPath extends string = string, TOperation extends FarmIntegrationAPIOperation = FarmIntegrationAPIOperation, > = { path: TPath; __operation: TOperation; }; export function defineIntegrationAPIOperation< TBody = never, TQuery = never, TResponse = unknown, TServer extends boolean = false, TMethod extends FarmIntegrationAPIMethod = FarmIntegrationAPIMethod, >( operation: Omit< FarmIntegrationAPIOperation, "kind" | "__types" >, ): FarmIntegrationAPIOperation; export function defineIntegrationAPI(api: TAPI): TAPI; type IntegrationAPIBuilderOptions = Omit< FarmIntegrationAPIOperation, "kind" | "method" | "path" | "__pathless" | "__types" >; type RouteOperationsToAPI< TOperations extends readonly FarmIntegrationAPIOperation[], > = { [TMethod in Lowercase]: Extract< TOperations[number], { method: Uppercase } >; }; type StripRouteClientPrefix = TPath extends `/api/${string}/${infer TRest}` ? TRest : TPath extends `/${string}/${infer TRest}` ? TRest : TPath extends `/${infer TRest}` ? TRest : TPath; type NormalizeRouteSegment = TSegment extends `[...${infer TName}]` ? TName : TSegment extends `[${infer TName}]` ? TName : TSegment extends `${infer TName}(${string}` ? TName : TSegment; type RouteNamespaceFromPath< TPath extends string, TOperation extends FarmIntegrationAPIOperation, > = TPath extends `${infer THead}/${infer TTail}` ? { [TKey in NormalizeRouteSegment]: RouteNamespaceFromPath; } : { [TKey in NormalizeRouteSegment]: { [TMethod in Lowercase]: TOperation; }; }; type UnionToIntersection = ( TUnion extends unknown ? (value: TUnion) => void : never ) extends (value: infer TIntersection) => void ? TIntersection : never; type ExpandRecursively = TValue extends (...args: any[]) => any ? TValue : TValue extends object ? { [TKey in keyof TValue]: ExpandRecursively } : TValue; type RoutesToAPI[]> = ExpandRecursively< UnionToIntersection< TRoutes[number] extends FarmIntegrationRouteOperationCarrier ? RouteNamespaceFromPath, TOperation> : never > >; export const api: { get( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; get( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; get( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; get( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; route(path: string, definition: TAPI): TAPI; route[]>( path: string, ...operations: TOperations ): RouteOperationsToAPI; fromRoutes[]>( routes: TRoutes, ): RoutesToAPI; query( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; query( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; post( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; post( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; put( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; put( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; patch( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; patch( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; delete( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; delete( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; options( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; options( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; head( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; head( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; form: { query( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; query( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; post( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; post( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; put( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; put( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; patch( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; patch( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; delete( path: string, options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; delete( options?: IntegrationAPIBuilderOptions, ): FarmIntegrationAPIOperation; }; }; export const endpoint: typeof api; /** * Small per-call integration metadata. When sent from a browser, values are * client-controlled and should be validated before authorization decisions. */ export type IntegrationClientData = Record; export interface IntegrationClientOptions extends ClientLifecycleHooks { fetch?: typeof globalThis.fetch; timeoutMs?: number; baseURL?: string; headers?: ClientHeaders; credentials?: RequestCredentials; data?: IntegrationClientData; isServer?: false | undefined; } interface IntegrationRequestOptionsBase extends ClientLifecycleHooks { timeoutMs?: number; headers?: Record; signal?: AbortSignal; credentials?: RequestCredentials; data?: IntegrationClientData; } export interface IntegrationClientRequestOptions< TData = unknown, > extends IntegrationRequestOptionsBase {} export type IntegrationServerRequestLike = | Request | { url?: string; headers?: HeadersInit; }; export interface IntegrationServerClientOptions extends Omit< IntegrationClientOptions, "isServer" > { isServer: true; request?: IntegrationServerRequestLike; forwardHeaders?: boolean | readonly string[]; } export interface IntegrationServerClientRequestOptions< TData = unknown, > extends IntegrationRequestOptionsBase { baseURL?: string; request?: IntegrationServerRequestLike; forwardHeaders?: boolean | readonly string[]; } export class IntegrationClientError extends Error { readonly status: number; readonly response: Response; readonly data: TData | undefined; } export type IntegrationOperationResult< TData = unknown, TError = IntegrationClientError | Error, > = { data: TData | null; error: TError | null; }; type ExtractIntegrationOperationBody = T extends { __types?: { body: infer TBody }; } ? TBody : never; type ExtractIntegrationOperationQuery = T extends { __types?: { query: infer TQuery }; } ? TQuery : never; type ExtractIntegrationOperationResponse = T extends { __types?: { response: infer TResponse }; } ? TResponse : unknown; export type InferIntegrationOperationBody = ExtractIntegrationOperationBody; export type InferIntegrationOperationQuery = ExtractIntegrationOperationQuery; export type InferIntegrationOperationResponse = ExtractIntegrationOperationResponse; type IsIntegrationNever = [T] extends [never] ? true : false; type IntegrationOperationInput = IsIntegrationNever> extends true ? IsIntegrationNever> extends true ? {} : { query?: ExtractIntegrationOperationQuery } : IsIntegrationNever> extends true ? { body: ExtractIntegrationOperationBody } : { body: ExtractIntegrationOperationBody; query?: ExtractIntegrationOperationQuery; }; type IntegrationOperationMethod = ( options?: IntegrationOperationInput, requestOptions?: IntegrationClientRequestOptions>, ) => Promise>>; type IsUnion = T extends any ? ([U] extends [T] ? false : true) : never; type SingleKey = [T] extends [never] ? never : IsUnion extends true ? never : T; type ExtractAPIFromSource = TSource extends { api?: infer TAPI } ? NonNullable extends FarmIntegrationAPI ? NonNullable : never : TSource extends FarmIntegrationAPI ? TSource : never; type SourceKeysWithAPI> = { [K in keyof TSources]: [ExtractAPIFromSource] extends [never] ? never : K; }[keyof TSources]; type IsServerRegisteredOperation = T extends { isServer: true } ? true : false; type ClientOperationKeys = { [K in keyof TAPI]: TAPI[K] extends FarmIntegrationAPIOperation ? IsServerRegisteredOperation extends true ? never : K : never; }[keyof TAPI]; type ClientNamespaceShape = { [K in keyof TAPI as TAPI[K] extends FarmIntegrationAPIOperation ? IsServerRegisteredOperation extends true ? never : K : K]: TAPI[K] extends FarmIntegrationAPIOperation ? IntegrationOperationMethod : TAPI[K] extends Record ? IntegrationAPIToClient : never; }; type SingleClientOperationKey = Exclude> extends never ? SingleKey> : never; type IntegrationAPIToClient = TAPI extends FarmIntegrationAPIOperation ? IntegrationOperationMethod : TAPI extends Record ? [SingleClientOperationKey] extends [never] ? ClientNamespaceShape : SingleClientOperationKey extends keyof TAPI ? IntegrationOperationMethod]> & ClientNamespaceShape : ClientNamespaceShape : never; export type IntegrationClient> = { [K in SourceKeysWithAPI]: IntegrationAPIToClient>; }; export type IntegrationClientRoot> = { integrations: IntegrationClient; }; export type IntegrationClientAliases> = IntegrationClient & { integrations: IntegrationClient; }; type IntegrationServerOperationMethod = ( options?: IntegrationOperationInput, requestOptions?: IntegrationServerClientRequestOptions>, ) => Promise>>; type ServerOperationKeys = { [K in keyof TAPI]: TAPI[K] extends FarmIntegrationAPIOperation ? K : never; }[keyof TAPI]; type ServerNamespaceShape = { [K in keyof TAPI]: TAPI[K] extends FarmIntegrationAPIOperation ? IntegrationServerOperationMethod : TAPI[K] extends Record ? IntegrationAPIToServerClient : never; }; type SingleServerOperationKey = Exclude> extends never ? SingleKey> : never; type IntegrationAPIToServerClient = TAPI extends FarmIntegrationAPIOperation ? IntegrationServerOperationMethod : TAPI extends Record ? [SingleServerOperationKey] extends [never] ? ServerNamespaceShape : SingleServerOperationKey extends keyof TAPI ? IntegrationServerOperationMethod]> & ServerNamespaceShape : ServerNamespaceShape : never; export type IntegrationServerClient> = { [K in SourceKeysWithAPI]: IntegrationAPIToServerClient< ExtractAPIFromSource >; }; export type IntegrationServerClientRoot> = { integrations: IntegrationServerClient; }; export type IntegrationServerClientAliases> = IntegrationServerClient & { integrations: IntegrationServerClient; }; export type IntegrationAPI> = IntegrationClientAliases & { server: ( options: Omit, ) => IntegrationServerClientAliases; }; export type IntegrationClients> = { api: IntegrationServerClientAliases; apiClient: IntegrationClientAliases; }; export function createIntegrationClient>( sources: { integrations: TSources }, options: IntegrationServerClientOptions, ): IntegrationServerClientAliases; export function createIntegrationClient>( sources: { integrations: TSources }, options?: IntegrationClientOptions, ): IntegrationClientAliases; export function createIntegrationClient>( sources: TSources, options: IntegrationServerClientOptions, ): IntegrationServerClient; export function createIntegrationClient>( sources: TSources, options?: IntegrationClientOptions, ): IntegrationClient; export function createIntegrationServerClient>(sources: { integrations: TSources; }): IntegrationServerClientAliases; export function createIntegrationServerClient>( sources: TSources, ): IntegrationServerClient; export function createIntegrationServerClient>( sources: { integrations: TSources }, options: Omit, ): IntegrationServerClientAliases; export function createIntegrationServerClient>( sources: TSources, options: Omit, ): IntegrationServerClient; export function integrationsClient< TSources extends Record, >(): IntegrationClientAliases; export function integrationsClient>( options: IntegrationClientOptions, ): IntegrationClientAliases; export function integrationsServer< TSources extends Record, >(): IntegrationServerClientAliases; export function integrationsServer>( options: Omit, ): IntegrationServerClientAliases; export function createIntegrationApi>( sources: { integrations: TSources }, options?: IntegrationClientOptions, ): IntegrationAPI; export function createIntegrationClients>( clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function createIntegrationClients>( sources: TSources, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function createIntegrationClients>( sources: { integrations: TSources }, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function createIntegrations>( clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function createIntegrations>( sources: TSources, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function createIntegrations>( sources: { integrations: TSources }, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function integrationClients>( clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function integrationClients>( sources: TSources, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function integrationClients>( sources: { integrations: TSources }, clientOptions?: IntegrationClientOptions, serverOptions?: Omit, ): IntegrationClients; export function getIntegrationAPIManifest(): Record; }