@tanstack/start-client-core
Version:
Modern and scalable routing for React applications
167 lines (159 loc) • 4.64 kB
text/typescript
import { createMiddleware } from './createMiddleware'
import type { TSS_SERVER_FUNCTION } from './constants'
import type {
AnyFunctionMiddleware,
AnyRequestMiddleware,
CreateMiddlewareFn,
} from './createMiddleware'
import type { CustomFetch } from './createServerFn'
import type {
AnySerializationAdapter,
Register,
SSROption,
} from '@tanstack/router-core'
export interface StartInstanceOptions<
in out TSerializationAdapters,
in out TDefaultSsr,
in out TRequestMiddlewares,
in out TFunctionMiddlewares,
> {
'~types': StartInstanceTypes<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>
serializationAdapters?: TSerializationAdapters
defaultSsr?: TDefaultSsr
requestMiddleware?: TRequestMiddlewares
functionMiddleware?: TFunctionMiddlewares
/**
* Configuration options for server functions.
*/
serverFns?: {
/**
* A custom fetch implementation to use for all server function calls.
* This can be overridden by middleware or at the call site.
*
* Precedence (highest to lowest):
* 1. Call site: `serverFn({ fetch: customFetch })`
* 2. Later middleware: Last middleware in chain that provides `fetch`
* 3. Earlier middleware: First middleware in chain that provides `fetch`
* 4. createStart: `createStart({ serverFns: { fetch: customFetch } })`
* 5. Default: Global `fetch` function
*
* @note Only applies on the client side. During SSR, server functions are called directly.
*/
fetch?: CustomFetch
}
}
export interface StartInstance<
in out TSerializationAdapters,
in out TDefaultSsr,
in out TRequestMiddlewares,
in out TFunctionMiddlewares,
> {
getOptions: () =>
| Promise<
StartInstanceOptions<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>
>
| StartInstanceOptions<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>
createMiddleware: CreateMiddlewareFn<Register>
}
export interface StartInstanceTypes<
in out TSerializationAdapters,
in out TDefaultSsr,
in out TRequestMiddlewares,
in out TFunctionMiddlewares,
> {
serializationAdapters: TSerializationAdapters
defaultSsr: TDefaultSsr
requestMiddleware: TRequestMiddlewares
functionMiddleware: TFunctionMiddlewares
}
function dedupeSerializationAdapters(
deduped: Set<AnySerializationAdapter>,
serializationAdapters: Array<AnySerializationAdapter>,
): void {
for (let i = 0, len = serializationAdapters.length; i < len; i++) {
const current = serializationAdapters[i]!
if (!deduped.has(current)) {
deduped.add(current)
if (current.extends) {
dedupeSerializationAdapters(deduped, current.extends)
}
}
}
}
export const createStart = <
const TSerializationAdapters extends ReadonlyArray<AnySerializationAdapter> =
[],
TDefaultSsr extends SSROption = SSROption,
const TRequestMiddlewares extends ReadonlyArray<AnyRequestMiddleware> = [],
const TFunctionMiddlewares extends ReadonlyArray<AnyFunctionMiddleware> = [],
>(
getOptions: () =>
| Promise<
Omit<
StartInstanceOptions<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>,
'~types'
>
>
| Omit<
StartInstanceOptions<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>,
'~types'
>,
): StartInstance<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
> => {
return {
getOptions: async () => {
const options = await getOptions()
if (options.serializationAdapters) {
const deduped = new Set<AnySerializationAdapter>()
dedupeSerializationAdapters(
deduped,
options.serializationAdapters as unknown as Array<AnySerializationAdapter>,
)
options.serializationAdapters = Array.from(deduped) as any
}
return options
},
createMiddleware: createMiddleware,
} as StartInstance<
TSerializationAdapters,
TDefaultSsr,
TRequestMiddlewares,
TFunctionMiddlewares
>
}
export type AnyStartInstance = StartInstance<any, any, any, any>
export type AnyStartInstanceOptions = StartInstanceOptions<any, any, any, any>
declare module '@tanstack/router-core' {
interface SerializableExtensions {
serverFn: { [TSS_SERVER_FUNCTION]: true }
}
}