@tanstack/start-client-core 1.132.0-alpha.8 → 1.132.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -82,23 +82,31 @@ export type ServerFnBaseOptions<TRegister extends Register, TMethod extends Meth
|
|
|
82
82
|
export type ValidateValidatorInput<TRegister extends Register, TValidator> = ValidateSerializable<ResolveValidatorInput<TValidator>, RegisteredSerializableInput<TRegister> | FormData>;
|
|
83
83
|
export type ValidateValidator<TRegister extends Register, TValidator> = ValidateValidatorInput<TRegister, TValidator> extends infer TInput ? Validator<TInput, any> : never;
|
|
84
84
|
export type ConstrainValidator<TRegister extends Register, TValidator> = (unknown extends TValidator ? TValidator : ResolveValidatorInput<TValidator> extends ValidateValidator<TRegister, TValidator> ? TValidator : never) | ValidateValidator<TRegister, TValidator>;
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
type ToTuple<T> = T extends ReadonlyArray<infer U> ? T : T extends undefined ? [] : [T];
|
|
86
|
+
export interface ServerFnMiddleware<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> {
|
|
87
|
+
middleware: <const TNewMiddlewares = undefined>(middlewares: Constrain<TNewMiddlewares, ReadonlyArray<AnyFunctionMiddleware>>) => ServerFnAfterMiddleware<TRegister, TMethod, TServerFnResponseType, [
|
|
88
|
+
...ToTuple<TMiddlewares>,
|
|
89
|
+
...ToTuple<TNewMiddlewares>
|
|
90
|
+
], TValidator>;
|
|
87
91
|
}
|
|
88
|
-
export interface ServerFnAfterMiddleware<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> extends ServerFnValidator<TRegister, TMethod, TServerFnResponseType, TMiddlewares>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator> {
|
|
92
|
+
export interface ServerFnAfterMiddleware<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> extends ServerFnMiddleware<TRegister, TMethod, TServerFnResponseType, TMiddlewares, undefined>, ServerFnValidator<TRegister, TMethod, TServerFnResponseType, TMiddlewares>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator> {
|
|
93
|
+
<TNewMethod extends Method = TMethod, TNewServerFnResponseType extends ServerFnResponseType = TServerFnResponseType>(options?: {
|
|
94
|
+
method?: TNewMethod;
|
|
95
|
+
response?: TNewServerFnResponseType;
|
|
96
|
+
}): ServerFnAfterMiddleware<TRegister, TNewMethod, TNewServerFnResponseType, TMiddlewares, TValidator>;
|
|
89
97
|
}
|
|
90
98
|
export type ValidatorFn<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares> = <TValidator>(validator: ConstrainValidator<TRegister, TValidator>) => ServerFnAfterValidator<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator>;
|
|
91
99
|
export interface ServerFnValidator<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares> {
|
|
92
100
|
validator: ValidatorFn<TRegister, TMethod, TServerFnResponseType, TMiddlewares>;
|
|
93
101
|
}
|
|
94
|
-
export interface ServerFnAfterValidator<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> extends ServerFnMiddleware<TRegister, TMethod, TServerFnResponseType, TValidator>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator> {
|
|
102
|
+
export interface ServerFnAfterValidator<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> extends ServerFnMiddleware<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator> {
|
|
95
103
|
}
|
|
96
104
|
export interface ServerFnAfterTyper<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> extends ServerFnHandler<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator> {
|
|
97
105
|
}
|
|
98
106
|
export interface ServerFnHandler<TRegister extends Register, TMethod extends Method, TServerFnResponseType extends ServerFnResponseType, TMiddlewares, TValidator> {
|
|
99
107
|
handler: <TNewResponse>(fn?: ServerFn<TRegister, TMethod, TServerFnResponseType, TMiddlewares, TValidator, TNewResponse>) => Fetcher<TRegister, TMiddlewares, TValidator, TNewResponse, TServerFnResponseType>;
|
|
100
108
|
}
|
|
101
|
-
export interface ServerFnBuilder<TRegister extends Register, TMethod extends Method = 'GET', TServerFnResponseType extends ServerFnResponseType = 'data'> extends ServerFnMiddleware<TRegister, TMethod, TServerFnResponseType, undefined>, ServerFnValidator<TRegister, TMethod, TServerFnResponseType, undefined>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, undefined, undefined> {
|
|
109
|
+
export interface ServerFnBuilder<TRegister extends Register, TMethod extends Method = 'GET', TServerFnResponseType extends ServerFnResponseType = 'data'> extends ServerFnMiddleware<TRegister, TMethod, TServerFnResponseType, undefined, undefined>, ServerFnValidator<TRegister, TMethod, TServerFnResponseType, undefined>, ServerFnHandler<TRegister, TMethod, TServerFnResponseType, undefined, undefined> {
|
|
102
110
|
options: ServerFnBaseOptions<TRegister, TMethod, TServerFnResponseType, unknown, undefined, undefined>;
|
|
103
111
|
}
|
|
104
112
|
export declare function flattenMiddlewares(middlewares: Array<AnyFunctionMiddleware>): Array<AnyFunctionMiddleware>;
|
|
@@ -124,3 +132,4 @@ export type MiddlewareFn = (ctx: ServerFnMiddlewareOptions & {
|
|
|
124
132
|
export declare const applyMiddleware: (middlewareFn: MiddlewareFn, ctx: ServerFnMiddlewareOptions, nextFn: NextFn) => Promise<ServerFnMiddlewareResult>;
|
|
125
133
|
export declare function execValidator(validator: AnyValidator, input: unknown): unknown;
|
|
126
134
|
export declare function serverFnBaseToMiddleware(options: ServerFnBaseOptions<any, any, any, any, any, any>): AnyFunctionMiddleware;
|
|
135
|
+
export {};
|
|
@@ -7,37 +7,38 @@ function createServerFn(options, __opts) {
|
|
|
7
7
|
if (typeof resolvedOptions.method === "undefined") {
|
|
8
8
|
resolvedOptions.method = "GET";
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
const res = {
|
|
11
11
|
options: resolvedOptions,
|
|
12
12
|
middleware: (middleware) => {
|
|
13
|
-
|
|
13
|
+
const newOptions = {
|
|
14
|
+
...resolvedOptions,
|
|
15
|
+
middleware: [...resolvedOptions.middleware || [], ...middleware]
|
|
16
|
+
};
|
|
17
|
+
return createServerFn(void 0, newOptions);
|
|
14
18
|
},
|
|
15
19
|
validator: (validator) => {
|
|
16
|
-
|
|
20
|
+
const newOptions = { ...resolvedOptions, validator };
|
|
21
|
+
return createServerFn(void 0, newOptions);
|
|
17
22
|
},
|
|
18
23
|
handler: (...args) => {
|
|
19
24
|
const [extractedFn, serverFn] = args;
|
|
20
|
-
|
|
21
|
-
...extractedFn,
|
|
22
|
-
extractedFn,
|
|
23
|
-
serverFn
|
|
24
|
-
});
|
|
25
|
+
const newOptions = { ...resolvedOptions, extractedFn, serverFn };
|
|
25
26
|
const resolvedMiddleware = [
|
|
26
|
-
...
|
|
27
|
-
serverFnBaseToMiddleware(
|
|
27
|
+
...newOptions.middleware || [],
|
|
28
|
+
serverFnBaseToMiddleware(newOptions)
|
|
28
29
|
];
|
|
29
30
|
return Object.assign(
|
|
30
31
|
async (opts) => {
|
|
31
32
|
return executeMiddleware(resolvedMiddleware, "client", {
|
|
32
33
|
...extractedFn,
|
|
33
|
-
...
|
|
34
|
+
...newOptions,
|
|
34
35
|
data: opts?.data,
|
|
35
36
|
headers: opts?.headers,
|
|
36
37
|
signal: opts?.signal,
|
|
37
38
|
context: {},
|
|
38
39
|
router: getRouterInstance()
|
|
39
40
|
}).then((d) => {
|
|
40
|
-
if (
|
|
41
|
+
if (newOptions.response === "full") {
|
|
41
42
|
return d;
|
|
42
43
|
}
|
|
43
44
|
if (d.error) throw d.error;
|
|
@@ -68,6 +69,16 @@ function createServerFn(options, __opts) {
|
|
|
68
69
|
);
|
|
69
70
|
}
|
|
70
71
|
};
|
|
72
|
+
const fun = (options2) => {
|
|
73
|
+
return {
|
|
74
|
+
...res,
|
|
75
|
+
options: {
|
|
76
|
+
...res.options,
|
|
77
|
+
...options2
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
return Object.assign(fun, res);
|
|
71
82
|
}
|
|
72
83
|
async function executeMiddleware(middlewares, env, opts) {
|
|
73
84
|
const flattenedMiddlewares = flattenMiddlewares([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { isNotFound, isRedirect } from '@tanstack/router-core'\nimport { mergeHeaders } from '@tanstack/router-core/ssr/client'\nimport { globalMiddleware } from './registerGlobalMiddleware'\n\nimport { getRouterInstance } from './getRouterInstance'\nimport type {\n AnyRouter,\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n ValidateSerializableInputResult,\n Validator,\n} from '@tanstack/router-core'\nimport type { JsonResponse } from '@tanstack/router-core/ssr/client'\nimport type { Readable } from 'node:stream'\nimport type {\n AnyFunctionMiddleware,\n AssignAllClientSendContext,\n AssignAllServerContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nexport function createServerFn<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = undefined,\n TValidator = undefined,\n>(\n options?: {\n method?: TMethod\n response?: TServerFnResponseType\n },\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >,\n): ServerFnBuilder<TRegister, TMethod, TServerFnResponseType> {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as TMethod\n }\n\n return {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n return createServerFn<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { middleware })) as any\n },\n validator: (validator) => {\n return createServerFn<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { validator })) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<TRegister, TResponse, TServerFnResponseType>,\n ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse\n >,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n Object.assign(resolvedOptions, {\n ...extractedFn,\n extractedFn,\n serverFn,\n })\n\n const resolvedMiddleware = [\n ...(resolvedOptions.middleware || []),\n serverFnBaseToMiddleware(resolvedOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...resolvedOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n router: getRouterInstance(),\n }).then((d) => {\n if (resolvedOptions.response === 'full') {\n return d\n }\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const ctx = {\n ...extractedFn,\n ...opts,\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n }\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddleware,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n nextMiddleware.options.validator &&\n (env === 'client' ? nextMiddleware.options.validateClient : true)\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(nextMiddleware.options.validator, ctx.data)\n }\n\n const middlewareFn = (\n env === 'client'\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n response?: ServerFnResponseType\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n // router?: AnyRouter\n}\n\nexport type Fetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TValidator>\n ? OptionalFetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n : RequiredFetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n\nexport interface FetcherBase {\n url: string\n __executeServer: (opts: {\n method: Method\n response?: ServerFnResponseType\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport type FetchResult<\n TRegister extends Register,\n TMiddlewares,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = TServerFnResponseType extends 'raw'\n ? Promise<Response>\n : TServerFnResponseType extends 'full'\n ? Promise<FullFetcherData<TRegister, TMiddlewares, TResponse>>\n : Promise<FetcherData<TRegister, TResponse>>\n\nexport interface OptionalFetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TRegister, TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport interface RequiredFetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TRegister, TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface FullFetcherData<\n TRegister extends Register,\n TMiddlewares,\n TResponse,\n> {\n error: unknown\n result: FetcherData<TRegister, TResponse>\n context: AssignAllClientSendContext<TMiddlewares>\n}\n\nexport type FetcherData<TRegister extends Register, TResponse> =\n TResponse extends JsonResponse<any>\n ? ValidateSerializableInputResult<TRegister, ReturnType<TResponse['json']>>\n : ValidateSerializableInputResult<TRegister, TResponse>\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\nexport type ServerFnResponseType = 'data' | 'full' | 'raw'\n\n// see https://h3.unjs.io/guide/event-handler#responses-types\nexport type RawResponse = Response | ReadableStream | Readable | null | string\n\nexport type ServerFnReturnType<\n TRegister extends Register,\n TServerFnResponseType extends ServerFnResponseType,\n TResponse,\n> = TServerFnResponseType extends 'raw'\n ? RawResponse | Promise<RawResponse>\n :\n | Promise<ValidateSerializableInput<TRegister, TResponse>>\n | ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister extends Register,\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,\n) => ServerFnReturnType<TRegister, TServerFnResponseType, TResponse>\n\nexport interface ServerFnCtx<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n method: TMethod\n response: TServerFnResponseType\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TValidator>>\n context: Expand<AssignAllServerContext<TMiddlewares>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<\n TRegister extends Register,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = {\n (\n opts: CompiledFetcherFnOptions &\n ServerFnBaseOptions<TRegister, Method, TServerFnResponseType>,\n ): Promise<TResponse>\n url: string\n}\n\nexport type ServerFnBaseOptions<\n TRegister extends Register,\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInput = unknown,\n> = {\n method: TMethod\n response?: TServerFnResponseType\n validateClient?: boolean\n middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware>>\n validator?: ConstrainValidator<TRegister, TInput>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse, TServerFnResponseType>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TInput,\n TResponse\n >\n functionId: string\n}\n\nexport type ValidateValidatorInput<\n TRegister extends Register,\n TValidator,\n> = ValidateSerializable<\n ResolveValidatorInput<TValidator>,\n RegisteredSerializableInput<TRegister> | FormData\n>\n\nexport type ValidateValidator<TRegister extends Register, TValidator> =\n ValidateValidatorInput<TRegister, TValidator> extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<TRegister extends Register, TValidator> =\n | (unknown extends TValidator\n ? TValidator\n : ResolveValidatorInput<TValidator> extends ValidateValidator<\n TRegister,\n TValidator\n >\n ? TValidator\n : never)\n | ValidateValidator<TRegister, TValidator>\n\nexport interface ServerFnMiddleware<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TValidator,\n> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TNewMiddlewares,\n TValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnValidator<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\nexport type ValidatorFn<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> = <TValidator>(\n validator: ConstrainValidator<TRegister, TValidator>,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n>\n\nexport interface ServerFnValidator<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> {\n validator: ValidatorFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares\n >\n}\n\nexport interface ServerFnAfterValidator<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TValidator\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TNewResponse\n >,\n ) => Fetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TNewResponse,\n TServerFnResponseType\n >\n}\n\nexport interface ServerFnBuilder<\n TRegister extends Register,\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n> extends ServerFnMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n undefined\n >,\n ServerFnValidator<TRegister, TMethod, TServerFnResponseType, undefined>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n undefined,\n undefined\n > {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TServerFnResponseType,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport function flattenMiddlewares(\n middlewares: Array<AnyFunctionMiddleware>,\n): Array<AnyFunctionMiddleware> {\n const seen = new Set<AnyFunctionMiddleware>()\n const flattened: Array<AnyFunctionMiddleware> = []\n\n const recurse = (middleware: Array<AnyFunctionMiddleware>) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n response?: ServerFnResponseType\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n router?: AnyRouter\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : ctx.response === 'raw'\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nexport function serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n _types: undefined!,\n options: {\n validator: options.validator,\n validateClient: options.validateClient,\n client: async ({ next, sendContext, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":[],"mappings":";;;;AAgCO,SAAS,eAQd,SAIA,QAQ4D;AAC5D,QAAM,kBAAmB,UAAU,WAAW,CAAA;AAS9C,MAAI,OAAO,gBAAgB,WAAW,aAAa;AACjD,oBAAgB,SAAS;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC,eAAe;AAC1B,aAAO,eAOL,QAAW,OAAO,OAAO,iBAAiB,EAAE,WAAA,CAAY,CAAC;AAAA,IAC7D;AAAA,IACA,WAAW,CAAC,cAAc;AACxB,aAAO,eAOL,QAAW,OAAO,OAAO,iBAAiB,EAAE,UAAA,CAAW,CAAC;AAAA,IAC5D;AAAA,IACA,SAAS,IAAI,SAAS;AAIpB,YAAM,CAAC,aAAa,QAAQ,IAAI;AAchC,aAAO,OAAO,iBAAiB;AAAA,QAC7B,GAAG;AAAA,QACH;AAAA,QACA;AAAA,MAAA,CACD;AAED,YAAM,qBAAqB;AAAA,QACzB,GAAI,gBAAgB,cAAc,CAAA;AAAA,QAClC,yBAAyB,eAAe;AAAA,MAAA;AAM1C,aAAO,OAAO;AAAA,QACZ,OAAO,SAAoC;AAEzC,iBAAO,kBAAkB,oBAAoB,UAAU;AAAA,YACrD,GAAG;AAAA,YACH,GAAG;AAAA,YACH,MAAM,MAAM;AAAA,YACZ,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,SAAS,CAAA;AAAA,YACT,QAAQ,kBAAA;AAAA,UAAkB,CAC3B,EAAE,KAAK,CAAC,MAAM;AACb,gBAAI,gBAAgB,aAAa,QAAQ;AACvC,qBAAO;AAAA,YACT;AACA,gBAAI,EAAE,MAAO,OAAM,EAAE;AACrB,mBAAO,EAAE;AAAA,UACX,CAAC;AAAA,QACH;AAAA,QACA;AAAA;AAAA,UAEE,GAAG;AAAA;AAAA;AAAA,UAGH,iBAAiB,OAAO,MAAW,WAAwB;AACzD,kBAAM,MAAM;AAAA,cACV,GAAG;AAAA,cACH,GAAG;AAAA,cACH;AAAA,YAAA;AAGF,mBAAO,kBAAkB,oBAAoB,UAAU,GAAG,EAAE;AAAA,cAC1D,CAAC,OAAO;AAAA;AAAA,gBAEN,QAAQ,EAAE;AAAA,gBACV,OAAO,EAAE;AAAA,gBACT,SAAS,EAAE;AAAA,cAAA;AAAA,YACb;AAAA,UAEJ;AAAA,QAAA;AAAA,MACF;AAAA,IAEJ;AAAA,EAAA;AAEJ;AAEA,eAAsB,kBACpB,aACA,KACA,MACmC;AACnC,QAAM,uBAAuB,mBAAmB;AAAA,IAC9C,GAAG;AAAA,IACH,GAAG;AAAA,EAAA,CACJ;AAED,QAAM,OAAe,OAAO,QAAQ;AAElC,UAAM,iBAAiB,qBAAqB,MAAA;AAG5C,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,IACT;AAEA,QACE,eAAe,QAAQ,cACtB,QAAQ,WAAW,eAAe,QAAQ,iBAAiB,OAC5D;AAEA,UAAI,OAAO,MAAM,cAAc,eAAe,QAAQ,WAAW,IAAI,IAAI;AAAA,IAC3E;AAEA,UAAM,eACJ,QAAQ,WACJ,eAAe,QAAQ,SACvB,eAAe,QAAQ;AAG7B,QAAI,cAAc;AAEhB,aAAO,gBAAgB,cAAc,KAAK,OAAO,WAAW;AAC1D,eAAO,KAAK,MAAM,EAAE,MAAM,CAAC,UAAe;AACxC,cAAI,WAAW,KAAK,KAAK,WAAW,KAAK,GAAG;AAC1C,mBAAO;AAAA,cACL,GAAG;AAAA,cACH;AAAA,YAAA;AAAA,UAEJ;AAEA,gBAAM;AAAA,QACR,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,WAAO,KAAK,GAAG;AAAA,EACjB;AAGA,SAAO,KAAK;AAAA,IACV,GAAG;AAAA,IACH,SAAS,KAAK,WAAW,CAAA;AAAA,IACzB,aAAa,KAAK,eAAe,CAAA;AAAA,IACjC,SAAS,KAAK,WAAW,CAAA;AAAA,EAAC,CAC3B;AACH;AAsXO,SAAS,mBACd,aAC8B;AAC9B,QAAM,2BAAW,IAAA;AACjB,QAAM,YAA0C,CAAA;AAEhD,QAAM,UAAU,CAAC,eAA6C;AAC5D,eAAW,QAAQ,CAAC,MAAM;AACxB,UAAI,EAAE,QAAQ,YAAY;AACxB,gBAAQ,EAAE,QAAQ,UAAU;AAAA,MAC9B;AAEA,UAAI,CAAC,KAAK,IAAI,CAAC,GAAG;AAChB,aAAK,IAAI,CAAC;AACV,kBAAU,KAAK,CAAC;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,UAAQ,WAAW;AAEnB,SAAO;AACT;AA6BO,MAAM,kBAAkB,OAC7B,cACA,KACA,WACG;AACH,SAAO,aAAa;AAAA,IAClB,GAAG;AAAA,IACH,MAAO,OACL,UAAgD,OAC7C;AAEH,aAAO,OAAO;AAAA,QACZ,GAAG;AAAA,QACH,GAAG;AAAA,QACH,SAAS;AAAA,UACP,GAAG,IAAI;AAAA,UACP,GAAG,QAAQ;AAAA,QAAA;AAAA,QAEb,aAAa;AAAA,UACX,GAAG,IAAI;AAAA,UACP,GAAI,QAAQ,eAAe,CAAA;AAAA,QAAC;AAAA,QAE9B,SAAS,aAAa,IAAI,SAAS,QAAQ,OAAO;AAAA,QAClD,QACE,QAAQ,WAAW,SACf,QAAQ,SACR,IAAI,aAAa,QACf,UACC,IAAY;AAAA,QACrB,OAAO,QAAQ,SAAU,IAAY;AAAA,MAAA,CACtC;AAAA,IACH;AAAA,EAAA,CACM;AACV;AAEO,SAAS,cACd,WACA,OACS;AACT,MAAI,aAAa,KAAM,QAAO,CAAA;AAE9B,MAAI,eAAe,WAAW;AAC5B,UAAM,SAAS,UAAU,WAAW,EAAE,SAAS,KAAK;AAEpD,QAAI,kBAAkB;AACpB,YAAM,IAAI,MAAM,gCAAgC;AAElD,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,KAAK,UAAU,OAAO,QAAQ,QAAW,CAAC,CAAC;AAE7D,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,WAAW,WAAW;AACxB,WAAO,UAAU,MAAM,KAAK;AAAA,EAC9B;AAEA,MAAI,OAAO,cAAc,YAAY;AACnC,WAAO,UAAU,KAAK;AAAA,EACxB;AAEA,QAAM,IAAI,MAAM,yBAAyB;AAC3C;AAEO,SAAS,yBACd,SACuB;AACvB,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,WAAW,QAAQ;AAAA,MACnB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ,OAAO,EAAE,MAAM,aAAa,GAAG,UAAU;AAC/C,cAAM,UAAU;AAAA,UACd,GAAG;AAAA;AAAA,UAEH,SAAS;AAAA,QAAA;AAKX,cAAM,MAAM,MAAM,QAAQ,cAAc,OAAO;AAE/C,eAAO,KAAK,GAAG;AAAA,MAKjB;AAAA,MACA,QAAQ,OAAO,EAAE,MAAM,GAAG,UAAU;AAElC,cAAM,SAAS,MAAM,QAAQ,WAAW,GAAW;AAEnD,eAAO,KAAK;AAAA,UACV,GAAG;AAAA,UACH;AAAA,QAAA,CACM;AAAA,MAMV;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { isNotFound, isRedirect } from '@tanstack/router-core'\nimport { mergeHeaders } from '@tanstack/router-core/ssr/client'\nimport { globalMiddleware } from './registerGlobalMiddleware'\n\nimport { getRouterInstance } from './getRouterInstance'\nimport type {\n AnyRouter,\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n ValidateSerializableInputResult,\n Validator,\n} from '@tanstack/router-core'\nimport type { JsonResponse } from '@tanstack/router-core/ssr/client'\nimport type { Readable } from 'node:stream'\nimport type {\n AnyFunctionMiddleware,\n AssignAllClientSendContext,\n AssignAllServerContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nexport function createServerFn<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = undefined,\n TValidator = undefined,\n>(\n options?: {\n method?: TMethod\n response?: TServerFnResponseType\n },\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >,\n): ServerFnBuilder<TRegister, TMethod, TServerFnResponseType> {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as TMethod\n }\n\n const res: ServerFnBuilder<TRegister, TMethod, TServerFnResponseType> = {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n // multiple calls to `middleware()` merge the middlewares with the previously supplied ones\n // this is primarily useful for letting users create their own abstractions on top of `createServerFn`\n const newOptions = {\n ...resolvedOptions,\n middleware: [...(resolvedOptions.middleware || []), ...middleware],\n }\n return createServerFn<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, newOptions) as any\n },\n validator: (validator) => {\n const newOptions = { ...resolvedOptions, validator: validator as any }\n return createServerFn<\n TRegister,\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, newOptions) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<TRegister, TResponse, TServerFnResponseType>,\n ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse\n >,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n const newOptions = { ...resolvedOptions, extractedFn, serverFn }\n\n const resolvedMiddleware = [\n ...(newOptions.middleware || []),\n serverFnBaseToMiddleware(newOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n router: getRouterInstance(),\n }).then((d) => {\n if (newOptions.response === 'full') {\n return d\n }\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const ctx = {\n ...extractedFn,\n ...opts,\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n }\n const fun = (options?: {\n method?: TMethod\n response?: TServerFnResponseType\n }) => {\n return {\n ...res,\n options: {\n ...res.options,\n ...options,\n },\n }\n }\n return Object.assign(fun, res)\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddleware,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n nextMiddleware.options.validator &&\n (env === 'client' ? nextMiddleware.options.validateClient : true)\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(nextMiddleware.options.validator, ctx.data)\n }\n\n const middlewareFn = (\n env === 'client'\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n response?: ServerFnResponseType\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n // router?: AnyRouter\n}\n\nexport type Fetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TValidator>\n ? OptionalFetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n : RequiredFetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n\nexport interface FetcherBase {\n url: string\n __executeServer: (opts: {\n method: Method\n response?: ServerFnResponseType\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport type FetchResult<\n TRegister extends Register,\n TMiddlewares,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = TServerFnResponseType extends 'raw'\n ? Promise<Response>\n : TServerFnResponseType extends 'full'\n ? Promise<FullFetcherData<TRegister, TMiddlewares, TResponse>>\n : Promise<FetcherData<TRegister, TResponse>>\n\nexport interface OptionalFetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TRegister, TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport interface RequiredFetcher<\n TRegister extends Register,\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TRegister, TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface FullFetcherData<\n TRegister extends Register,\n TMiddlewares,\n TResponse,\n> {\n error: unknown\n result: FetcherData<TRegister, TResponse>\n context: AssignAllClientSendContext<TMiddlewares>\n}\n\nexport type FetcherData<TRegister extends Register, TResponse> =\n TResponse extends JsonResponse<any>\n ? ValidateSerializableInputResult<TRegister, ReturnType<TResponse['json']>>\n : ValidateSerializableInputResult<TRegister, TResponse>\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\nexport type ServerFnResponseType = 'data' | 'full' | 'raw'\n\n// see https://h3.unjs.io/guide/event-handler#responses-types\nexport type RawResponse = Response | ReadableStream | Readable | null | string\n\nexport type ServerFnReturnType<\n TRegister extends Register,\n TServerFnResponseType extends ServerFnResponseType,\n TResponse,\n> = TServerFnResponseType extends 'raw'\n ? RawResponse | Promise<RawResponse>\n :\n | Promise<ValidateSerializableInput<TRegister, TResponse>>\n | ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister extends Register,\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,\n) => ServerFnReturnType<TRegister, TServerFnResponseType, TResponse>\n\nexport interface ServerFnCtx<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n method: TMethod\n response: TServerFnResponseType\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TValidator>>\n context: Expand<AssignAllServerContext<TMiddlewares>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<\n TRegister extends Register,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = {\n (\n opts: CompiledFetcherFnOptions &\n ServerFnBaseOptions<TRegister, Method, TServerFnResponseType>,\n ): Promise<TResponse>\n url: string\n}\n\nexport type ServerFnBaseOptions<\n TRegister extends Register,\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInput = unknown,\n> = {\n method: TMethod\n response?: TServerFnResponseType\n validateClient?: boolean\n middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware>>\n validator?: ConstrainValidator<TRegister, TInput>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse, TServerFnResponseType>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TInput,\n TResponse\n >\n functionId: string\n}\n\nexport type ValidateValidatorInput<\n TRegister extends Register,\n TValidator,\n> = ValidateSerializable<\n ResolveValidatorInput<TValidator>,\n RegisteredSerializableInput<TRegister> | FormData\n>\n\nexport type ValidateValidator<TRegister extends Register, TValidator> =\n ValidateValidatorInput<TRegister, TValidator> extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<TRegister extends Register, TValidator> =\n | (unknown extends TValidator\n ? TValidator\n : ResolveValidatorInput<TValidator> extends ValidateValidator<\n TRegister,\n TValidator\n >\n ? TValidator\n : never)\n | ValidateValidator<TRegister, TValidator>\n\ntype ToTuple<T> =\n T extends ReadonlyArray<infer U> ? T : T extends undefined ? [] : [T]\n\nexport interface ServerFnMiddleware<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n [...ToTuple<TMiddlewares>, ...ToTuple<TNewMiddlewares>],\n TValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n undefined\n >,\n ServerFnValidator<TRegister, TMethod, TServerFnResponseType, TMiddlewares>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {\n <\n TNewMethod extends Method = TMethod,\n TNewServerFnResponseType extends\n ServerFnResponseType = TServerFnResponseType,\n >(options?: {\n method?: TNewMethod\n response?: TNewServerFnResponseType\n }): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TNewServerFnResponseType,\n TMiddlewares,\n TValidator\n >\n}\n\nexport type ValidatorFn<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> = <TValidator>(\n validator: ConstrainValidator<TRegister, TValidator>,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n>\n\nexport interface ServerFnValidator<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> {\n validator: ValidatorFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares\n >\n}\n\nexport interface ServerFnAfterValidator<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister extends Register,\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TNewResponse\n >,\n ) => Fetcher<\n TRegister,\n TMiddlewares,\n TValidator,\n TNewResponse,\n TServerFnResponseType\n >\n}\n\nexport interface ServerFnBuilder<\n TRegister extends Register,\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n> extends ServerFnMiddleware<\n TRegister,\n TMethod,\n TServerFnResponseType,\n undefined,\n undefined\n >,\n ServerFnValidator<TRegister, TMethod, TServerFnResponseType, undefined>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TServerFnResponseType,\n undefined,\n undefined\n > {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TServerFnResponseType,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport function flattenMiddlewares(\n middlewares: Array<AnyFunctionMiddleware>,\n): Array<AnyFunctionMiddleware> {\n const seen = new Set<AnyFunctionMiddleware>()\n const flattened: Array<AnyFunctionMiddleware> = []\n\n const recurse = (middleware: Array<AnyFunctionMiddleware>) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n response?: ServerFnResponseType\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n router?: AnyRouter\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : ctx.response === 'raw'\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nexport function serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n _types: undefined!,\n options: {\n validator: options.validator,\n validateClient: options.validateClient,\n client: async ({ next, sendContext, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":["options"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/createServerFn.ts
CHANGED
|
@@ -64,9 +64,15 @@ export function createServerFn<
|
|
|
64
64
|
resolvedOptions.method = 'GET' as TMethod
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
const res: ServerFnBuilder<TRegister, TMethod, TServerFnResponseType> = {
|
|
68
68
|
options: resolvedOptions as any,
|
|
69
69
|
middleware: (middleware) => {
|
|
70
|
+
// multiple calls to `middleware()` merge the middlewares with the previously supplied ones
|
|
71
|
+
// this is primarily useful for letting users create their own abstractions on top of `createServerFn`
|
|
72
|
+
const newOptions = {
|
|
73
|
+
...resolvedOptions,
|
|
74
|
+
middleware: [...(resolvedOptions.middleware || []), ...middleware],
|
|
75
|
+
}
|
|
70
76
|
return createServerFn<
|
|
71
77
|
TRegister,
|
|
72
78
|
TMethod,
|
|
@@ -74,9 +80,10 @@ export function createServerFn<
|
|
|
74
80
|
TResponse,
|
|
75
81
|
TMiddlewares,
|
|
76
82
|
TValidator
|
|
77
|
-
>(undefined,
|
|
83
|
+
>(undefined, newOptions) as any
|
|
78
84
|
},
|
|
79
85
|
validator: (validator) => {
|
|
86
|
+
const newOptions = { ...resolvedOptions, validator: validator as any }
|
|
80
87
|
return createServerFn<
|
|
81
88
|
TRegister,
|
|
82
89
|
TMethod,
|
|
@@ -84,7 +91,7 @@ export function createServerFn<
|
|
|
84
91
|
TResponse,
|
|
85
92
|
TMiddlewares,
|
|
86
93
|
TValidator
|
|
87
|
-
>(undefined,
|
|
94
|
+
>(undefined, newOptions) as any
|
|
88
95
|
},
|
|
89
96
|
handler: (...args) => {
|
|
90
97
|
// This function signature changes due to AST transformations
|
|
@@ -104,15 +111,11 @@ export function createServerFn<
|
|
|
104
111
|
|
|
105
112
|
// Keep the original function around so we can use it
|
|
106
113
|
// in the server environment
|
|
107
|
-
|
|
108
|
-
...extractedFn,
|
|
109
|
-
extractedFn,
|
|
110
|
-
serverFn,
|
|
111
|
-
})
|
|
114
|
+
const newOptions = { ...resolvedOptions, extractedFn, serverFn }
|
|
112
115
|
|
|
113
116
|
const resolvedMiddleware = [
|
|
114
|
-
...(
|
|
115
|
-
serverFnBaseToMiddleware(
|
|
117
|
+
...(newOptions.middleware || []),
|
|
118
|
+
serverFnBaseToMiddleware(newOptions),
|
|
116
119
|
]
|
|
117
120
|
|
|
118
121
|
// We want to make sure the new function has the same
|
|
@@ -123,14 +126,14 @@ export function createServerFn<
|
|
|
123
126
|
// Start by executing the client-side middleware chain
|
|
124
127
|
return executeMiddleware(resolvedMiddleware, 'client', {
|
|
125
128
|
...extractedFn,
|
|
126
|
-
...
|
|
129
|
+
...newOptions,
|
|
127
130
|
data: opts?.data as any,
|
|
128
131
|
headers: opts?.headers,
|
|
129
132
|
signal: opts?.signal,
|
|
130
133
|
context: {},
|
|
131
134
|
router: getRouterInstance(),
|
|
132
135
|
}).then((d) => {
|
|
133
|
-
if (
|
|
136
|
+
if (newOptions.response === 'full') {
|
|
134
137
|
return d
|
|
135
138
|
}
|
|
136
139
|
if (d.error) throw d.error
|
|
@@ -162,6 +165,19 @@ export function createServerFn<
|
|
|
162
165
|
) as any
|
|
163
166
|
},
|
|
164
167
|
}
|
|
168
|
+
const fun = (options?: {
|
|
169
|
+
method?: TMethod
|
|
170
|
+
response?: TServerFnResponseType
|
|
171
|
+
}) => {
|
|
172
|
+
return {
|
|
173
|
+
...res,
|
|
174
|
+
options: {
|
|
175
|
+
...res.options,
|
|
176
|
+
...options,
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return Object.assign(fun, res)
|
|
165
181
|
}
|
|
166
182
|
|
|
167
183
|
export async function executeMiddleware(
|
|
@@ -440,10 +456,14 @@ export type ConstrainValidator<TRegister extends Register, TValidator> =
|
|
|
440
456
|
: never)
|
|
441
457
|
| ValidateValidator<TRegister, TValidator>
|
|
442
458
|
|
|
459
|
+
type ToTuple<T> =
|
|
460
|
+
T extends ReadonlyArray<infer U> ? T : T extends undefined ? [] : [T]
|
|
461
|
+
|
|
443
462
|
export interface ServerFnMiddleware<
|
|
444
463
|
TRegister extends Register,
|
|
445
464
|
TMethod extends Method,
|
|
446
465
|
TServerFnResponseType extends ServerFnResponseType,
|
|
466
|
+
TMiddlewares,
|
|
447
467
|
TValidator,
|
|
448
468
|
> {
|
|
449
469
|
middleware: <const TNewMiddlewares = undefined>(
|
|
@@ -455,7 +475,7 @@ export interface ServerFnMiddleware<
|
|
|
455
475
|
TRegister,
|
|
456
476
|
TMethod,
|
|
457
477
|
TServerFnResponseType,
|
|
458
|
-
TNewMiddlewares,
|
|
478
|
+
[...ToTuple<TMiddlewares>, ...ToTuple<TNewMiddlewares>],
|
|
459
479
|
TValidator
|
|
460
480
|
>
|
|
461
481
|
}
|
|
@@ -466,19 +486,36 @@ export interface ServerFnAfterMiddleware<
|
|
|
466
486
|
TServerFnResponseType extends ServerFnResponseType,
|
|
467
487
|
TMiddlewares,
|
|
468
488
|
TValidator,
|
|
469
|
-
> extends
|
|
489
|
+
> extends ServerFnMiddleware<
|
|
470
490
|
TRegister,
|
|
471
491
|
TMethod,
|
|
472
492
|
TServerFnResponseType,
|
|
473
|
-
TMiddlewares
|
|
493
|
+
TMiddlewares,
|
|
494
|
+
undefined
|
|
474
495
|
>,
|
|
496
|
+
ServerFnValidator<TRegister, TMethod, TServerFnResponseType, TMiddlewares>,
|
|
475
497
|
ServerFnHandler<
|
|
476
498
|
TRegister,
|
|
477
499
|
TMethod,
|
|
478
500
|
TServerFnResponseType,
|
|
479
501
|
TMiddlewares,
|
|
480
502
|
TValidator
|
|
481
|
-
> {
|
|
503
|
+
> {
|
|
504
|
+
<
|
|
505
|
+
TNewMethod extends Method = TMethod,
|
|
506
|
+
TNewServerFnResponseType extends
|
|
507
|
+
ServerFnResponseType = TServerFnResponseType,
|
|
508
|
+
>(options?: {
|
|
509
|
+
method?: TNewMethod
|
|
510
|
+
response?: TNewServerFnResponseType
|
|
511
|
+
}): ServerFnAfterMiddleware<
|
|
512
|
+
TRegister,
|
|
513
|
+
TNewMethod,
|
|
514
|
+
TNewServerFnResponseType,
|
|
515
|
+
TMiddlewares,
|
|
516
|
+
TValidator
|
|
517
|
+
>
|
|
518
|
+
}
|
|
482
519
|
|
|
483
520
|
export type ValidatorFn<
|
|
484
521
|
TRegister extends Register,
|
|
@@ -519,6 +556,7 @@ export interface ServerFnAfterValidator<
|
|
|
519
556
|
TRegister,
|
|
520
557
|
TMethod,
|
|
521
558
|
TServerFnResponseType,
|
|
559
|
+
TMiddlewares,
|
|
522
560
|
TValidator
|
|
523
561
|
>,
|
|
524
562
|
ServerFnHandler<
|
|
@@ -577,6 +615,7 @@ export interface ServerFnBuilder<
|
|
|
577
615
|
TRegister,
|
|
578
616
|
TMethod,
|
|
579
617
|
TServerFnResponseType,
|
|
618
|
+
undefined,
|
|
580
619
|
undefined
|
|
581
620
|
>,
|
|
582
621
|
ServerFnValidator<TRegister, TMethod, TServerFnResponseType, undefined>,
|
|
@@ -97,7 +97,6 @@ test('createServerFn with middleware and context', () => {
|
|
|
97
97
|
|
|
98
98
|
expectTypeOf(fnWithMiddleware).toHaveProperty('handler')
|
|
99
99
|
expectTypeOf(fnWithMiddleware).toHaveProperty('validator')
|
|
100
|
-
expectTypeOf(fnWithMiddleware).not.toHaveProperty('middleware')
|
|
101
100
|
|
|
102
101
|
fnWithMiddleware.handler((options) => {
|
|
103
102
|
expectTypeOf(options).toEqualTypeOf<{
|
|
@@ -513,3 +512,88 @@ test('createServerFn validator infers unknown for default input type', () => {
|
|
|
513
512
|
|
|
514
513
|
expectTypeOf(fn()).toEqualTypeOf<Promise<'failed' | 'success'>>()
|
|
515
514
|
})
|
|
515
|
+
|
|
516
|
+
test('incrementally building createServerFn with multiple middleware calls', () => {
|
|
517
|
+
const middleware1 = createMiddleware({ type: 'function' }).server(
|
|
518
|
+
({ next }) => {
|
|
519
|
+
return next({ context: { a: 'a' } as const })
|
|
520
|
+
},
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
const middleware2 = createMiddleware({ type: 'function' }).server(
|
|
524
|
+
({ next }) => {
|
|
525
|
+
return next({ context: { b: 'b' } as const })
|
|
526
|
+
},
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
const middleware3 = createMiddleware({ type: 'function' }).server(
|
|
530
|
+
({ next }) => {
|
|
531
|
+
return next({ context: { c: 'c' } as const })
|
|
532
|
+
},
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
const builderWithMw1 = createServerFn({ method: 'GET' }).middleware([
|
|
536
|
+
middleware1,
|
|
537
|
+
])
|
|
538
|
+
|
|
539
|
+
expectTypeOf(builderWithMw1).toHaveProperty('handler')
|
|
540
|
+
expectTypeOf(builderWithMw1).toHaveProperty('validator')
|
|
541
|
+
expectTypeOf(builderWithMw1).toHaveProperty('middleware')
|
|
542
|
+
|
|
543
|
+
builderWithMw1.handler((options) => {
|
|
544
|
+
expectTypeOf(options).toEqualTypeOf<{
|
|
545
|
+
method: 'GET'
|
|
546
|
+
context: {
|
|
547
|
+
readonly a: 'a'
|
|
548
|
+
}
|
|
549
|
+
data: undefined
|
|
550
|
+
signal: AbortSignal
|
|
551
|
+
response: 'data'
|
|
552
|
+
}>()
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
// overrides method
|
|
556
|
+
const builderWithMw2 = builderWithMw1({ method: 'POST' }).middleware([
|
|
557
|
+
middleware2,
|
|
558
|
+
])
|
|
559
|
+
|
|
560
|
+
expectTypeOf(builderWithMw2).toHaveProperty('handler')
|
|
561
|
+
expectTypeOf(builderWithMw2).toHaveProperty('validator')
|
|
562
|
+
expectTypeOf(builderWithMw2).toHaveProperty('middleware')
|
|
563
|
+
|
|
564
|
+
builderWithMw2.handler((options) => {
|
|
565
|
+
expectTypeOf(options).toEqualTypeOf<{
|
|
566
|
+
method: 'POST'
|
|
567
|
+
context: {
|
|
568
|
+
readonly a: 'a'
|
|
569
|
+
readonly b: 'b'
|
|
570
|
+
}
|
|
571
|
+
data: undefined
|
|
572
|
+
signal: AbortSignal
|
|
573
|
+
response: 'data'
|
|
574
|
+
}>()
|
|
575
|
+
})
|
|
576
|
+
|
|
577
|
+
// overrides method again
|
|
578
|
+
const builderWithMw3 = builderWithMw2({ method: 'GET' }).middleware([
|
|
579
|
+
middleware3,
|
|
580
|
+
])
|
|
581
|
+
|
|
582
|
+
expectTypeOf(builderWithMw3).toHaveProperty('handler')
|
|
583
|
+
expectTypeOf(builderWithMw3).toHaveProperty('validator')
|
|
584
|
+
expectTypeOf(builderWithMw3).toHaveProperty('middleware')
|
|
585
|
+
|
|
586
|
+
builderWithMw3.handler((options) => {
|
|
587
|
+
expectTypeOf(options).toEqualTypeOf<{
|
|
588
|
+
method: 'GET'
|
|
589
|
+
context: {
|
|
590
|
+
readonly a: 'a'
|
|
591
|
+
readonly b: 'b'
|
|
592
|
+
readonly c: 'c'
|
|
593
|
+
}
|
|
594
|
+
data: undefined
|
|
595
|
+
signal: AbortSignal
|
|
596
|
+
response: 'data'
|
|
597
|
+
}>()
|
|
598
|
+
})
|
|
599
|
+
})
|