@tanstack/start-client-core 1.168.2 → 1.169.1

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.
@@ -0,0 +1,46 @@
1
+ import { RequestMiddlewareAfterServer, RequestServerOptions } from './createMiddleware.js';
2
+ import { Register } from '@tanstack/router-core';
3
+ export declare const csrfSymbol: unique symbol;
4
+ export type CsrfSecFetchSite = 'same-origin' | 'same-site' | 'cross-site' | 'none';
5
+ export type CsrfMatcher<TValue, TRegister = Register, TMiddlewares = unknown> = TValue | Array<TValue> | ((value: TValue | (string & {}), ctx: RequestServerOptions<TRegister, TMiddlewares>) => boolean | Promise<boolean>);
6
+ export interface CsrfMiddlewareOptions<TRegister = Register, TMiddlewares = unknown> {
7
+ /**
8
+ * Return `true` to validate this request, or `false` to skip validation.
9
+ *
10
+ * @default undefined, which validates every request handled by this middleware.
11
+ */
12
+ filter?: (ctx: RequestServerOptions<TRegister, TMiddlewares>) => boolean | Promise<boolean>;
13
+ /**
14
+ * Allowed Origin values. Defaults to the trusted request origin.
15
+ */
16
+ origin?: CsrfMatcher<string, TRegister, TMiddlewares>;
17
+ /**
18
+ * Allowed Sec-Fetch-Site values.
19
+ *
20
+ * @default 'same-origin'
21
+ */
22
+ secFetchSite?: CsrfMatcher<CsrfSecFetchSite, TRegister, TMiddlewares>;
23
+ /**
24
+ * Whether to use Referer as a fallback when Sec-Fetch-Site and Origin are absent.
25
+ *
26
+ * @default true
27
+ */
28
+ referer?: boolean | ((referer: string, ctx: RequestServerOptions<TRegister, TMiddlewares>) => boolean | Promise<boolean>);
29
+ /**
30
+ * Allow requests when Sec-Fetch-Site, Origin, and Referer are all missing.
31
+ *
32
+ * @default false
33
+ */
34
+ allowRequestsWithoutOriginCheck?: boolean;
35
+ /**
36
+ * Optional response returned when CSRF validation fails.
37
+ *
38
+ * @default new Response('Forbidden', { status: 403 })
39
+ */
40
+ failureResponse?: Response | ((ctx: RequestServerOptions<TRegister, TMiddlewares>) => Response | Promise<Response>);
41
+ }
42
+ type CreateCsrfMiddleware = <TRegister, TMiddlewares>(opts?: CsrfMiddlewareOptions<TRegister, TMiddlewares>) => RequestMiddlewareAfterServer<{}, undefined, undefined>;
43
+ export declare const createCsrfMiddleware: CreateCsrfMiddleware;
44
+ export declare function isCsrfRequestAllowed<TRegister, TMiddlewares>(opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>, ctx: RequestServerOptions<TRegister, TMiddlewares>): Promise<boolean>;
45
+ export declare function getCsrfRequestValidationResult<TRegister, TMiddlewares>(opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>, ctx: RequestServerOptions<TRegister, TMiddlewares>): Promise<boolean | undefined>;
46
+ export {};
@@ -0,0 +1,63 @@
1
+ import { createMiddleware } from "./createMiddleware.js";
2
+ import { createIsomorphicFn } from "@tanstack/start-fn-stubs";
3
+ //#region src/createCsrfMiddleware.ts
4
+ var csrfSymbol = Symbol.for("tanstack-start:csrf-middleware");
5
+ var innerCreateCsrfMiddleware = (opts = {}) => {
6
+ const middleware = createMiddleware().server(async (ctx) => {
7
+ const csrfCtx = ctx;
8
+ if (opts.filter && !await opts.filter(csrfCtx)) return ctx.next();
9
+ if (await isCsrfRequestAllowed(opts, csrfCtx)) return ctx.next();
10
+ return getFailureResponse(opts, csrfCtx);
11
+ });
12
+ if (process.env.NODE_ENV !== "production") Object.defineProperty(middleware, csrfSymbol, { value: true });
13
+ return middleware;
14
+ };
15
+ var createCsrfMiddleware = createIsomorphicFn().server(innerCreateCsrfMiddleware);
16
+ async function isCsrfRequestAllowed(opts, ctx) {
17
+ const result = await getCsrfRequestValidationResult(opts, ctx);
18
+ return result === true || result === void 0 && opts.allowRequestsWithoutOriginCheck === true;
19
+ }
20
+ async function getCsrfRequestValidationResult(opts, ctx) {
21
+ const fetchSite = ctx.request.headers.get("Sec-Fetch-Site");
22
+ if (fetchSite !== null) return matchValue(opts.secFetchSite ?? "same-origin", fetchSite, ctx);
23
+ const origin = ctx.request.headers.get("Origin");
24
+ if (origin !== null) {
25
+ if (opts.origin) return matchValue(opts.origin, origin, ctx);
26
+ return origin === new URL(ctx.request.url).origin;
27
+ }
28
+ const referer = ctx.request.headers.get("Referer");
29
+ if (referer === null || opts.referer === false) return;
30
+ if (typeof opts.referer === "function") return opts.referer(referer, ctx);
31
+ if (opts.origin) {
32
+ const refererOrigin = getOriginFromUrl(referer);
33
+ return refererOrigin !== void 0 && matchValue(opts.origin, refererOrigin, ctx);
34
+ }
35
+ return isRefererSameOrigin(referer, new URL(ctx.request.url).origin);
36
+ }
37
+ async function matchValue(matcher, value, ctx) {
38
+ if (typeof matcher === "function") return matcher(value, ctx);
39
+ if (Array.isArray(matcher)) return matcher.includes(value);
40
+ return value === matcher;
41
+ }
42
+ function getOriginFromUrl(url) {
43
+ try {
44
+ return new URL(url).origin;
45
+ } catch {
46
+ return;
47
+ }
48
+ }
49
+ function isRefererSameOrigin(referer, requestOrigin) {
50
+ if (referer === requestOrigin) return true;
51
+ if (!referer.startsWith(requestOrigin)) return false;
52
+ if (referer.length === requestOrigin.length) return true;
53
+ const code = referer.charCodeAt(requestOrigin.length);
54
+ return code === 47 || code === 63 || code === 35;
55
+ }
56
+ async function getFailureResponse(opts, ctx) {
57
+ if (typeof opts.failureResponse === "function") return opts.failureResponse(ctx);
58
+ return opts.failureResponse?.clone() ?? new Response("Forbidden", { status: 403 });
59
+ }
60
+ //#endregion
61
+ export { createCsrfMiddleware, csrfSymbol, getCsrfRequestValidationResult, isCsrfRequestAllowed };
62
+
63
+ //# sourceMappingURL=createCsrfMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCsrfMiddleware.js","names":[],"sources":["../../src/createCsrfMiddleware.ts"],"sourcesContent":["import { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport { createMiddleware } from './createMiddleware'\nimport type {\n RequestMiddlewareAfterServer,\n RequestServerOptions,\n} from './createMiddleware'\nimport type { Register } from '@tanstack/router-core'\n\nexport const csrfSymbol = Symbol.for('tanstack-start:csrf-middleware')\n\nexport type CsrfSecFetchSite =\n | 'same-origin'\n | 'same-site'\n | 'cross-site'\n | 'none'\n\nexport type CsrfMatcher<TValue, TRegister = Register, TMiddlewares = unknown> =\n | TValue\n | Array<TValue>\n | ((\n value: TValue | (string & {}),\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n ) => boolean | Promise<boolean>)\n\nexport interface CsrfMiddlewareOptions<\n TRegister = Register,\n TMiddlewares = unknown,\n> {\n /**\n * Return `true` to validate this request, or `false` to skip validation.\n *\n * @default undefined, which validates every request handled by this middleware.\n */\n filter?: (\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n ) => boolean | Promise<boolean>\n /**\n * Allowed Origin values. Defaults to the trusted request origin.\n */\n origin?: CsrfMatcher<string, TRegister, TMiddlewares>\n /**\n * Allowed Sec-Fetch-Site values.\n *\n * @default 'same-origin'\n */\n secFetchSite?: CsrfMatcher<CsrfSecFetchSite, TRegister, TMiddlewares>\n /**\n * Whether to use Referer as a fallback when Sec-Fetch-Site and Origin are absent.\n *\n * @default true\n */\n referer?:\n | boolean\n | ((\n referer: string,\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n ) => boolean | Promise<boolean>)\n /**\n * Allow requests when Sec-Fetch-Site, Origin, and Referer are all missing.\n *\n * @default false\n */\n allowRequestsWithoutOriginCheck?: boolean\n /**\n * Optional response returned when CSRF validation fails.\n *\n * @default new Response('Forbidden', { status: 403 })\n */\n failureResponse?:\n | Response\n | ((\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n ) => Response | Promise<Response>)\n}\n\ntype CreateCsrfMiddleware = <TRegister, TMiddlewares>(\n opts?: CsrfMiddlewareOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareAfterServer<{}, undefined, undefined>\n\nconst innerCreateCsrfMiddleware: CreateCsrfMiddleware = (opts = {}) => {\n const middleware = createMiddleware().server(async (ctx) => {\n const csrfCtx = ctx as RequestServerOptions<any, any>\n\n if (opts.filter && !(await opts.filter(csrfCtx))) {\n return ctx.next()\n }\n\n if (await isCsrfRequestAllowed(opts, csrfCtx)) {\n return ctx.next()\n }\n\n return getFailureResponse(opts, csrfCtx)\n })\n\n if (process.env.NODE_ENV !== 'production') {\n Object.defineProperty(middleware, csrfSymbol, { value: true })\n }\n\n return middleware\n}\n\nexport const createCsrfMiddleware: CreateCsrfMiddleware =\n createIsomorphicFn().server(innerCreateCsrfMiddleware) as CreateCsrfMiddleware\n\nexport async function isCsrfRequestAllowed<TRegister, TMiddlewares>(\n opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n): Promise<boolean> {\n const result = await getCsrfRequestValidationResult(opts, ctx)\n return (\n result === true ||\n (result === undefined && opts.allowRequestsWithoutOriginCheck === true)\n )\n}\n\nexport async function getCsrfRequestValidationResult<TRegister, TMiddlewares>(\n opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n): Promise<boolean | undefined> {\n const fetchSite = ctx.request.headers.get('Sec-Fetch-Site')\n if (fetchSite !== null) {\n return matchValue(opts.secFetchSite ?? 'same-origin', fetchSite, ctx)\n }\n\n const origin = ctx.request.headers.get('Origin')\n if (origin !== null) {\n if (opts.origin) {\n return matchValue(opts.origin, origin, ctx)\n }\n\n return origin === new URL(ctx.request.url).origin\n }\n\n const referer = ctx.request.headers.get('Referer')\n if (referer === null || opts.referer === false) {\n return undefined\n }\n\n if (typeof opts.referer === 'function') {\n return opts.referer(referer, ctx)\n }\n\n if (opts.origin) {\n const refererOrigin = getOriginFromUrl(referer)\n return (\n refererOrigin !== undefined && matchValue(opts.origin, refererOrigin, ctx)\n )\n }\n\n return isRefererSameOrigin(referer, new URL(ctx.request.url).origin)\n}\n\nasync function matchValue<TValue extends string, TRegister, TMiddlewares>(\n matcher: CsrfMatcher<TValue, TRegister, TMiddlewares>,\n value: string,\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n): Promise<boolean> {\n if (typeof matcher === 'function') {\n return matcher(value, ctx)\n }\n\n if (Array.isArray(matcher)) {\n // typescript is dumb for array.includes()\n return matcher.includes(value as TValue)\n }\n\n return value === matcher\n}\n\nfunction getOriginFromUrl(url: string): string | undefined {\n try {\n return new URL(url).origin\n } catch {\n return undefined\n }\n}\n\nfunction isRefererSameOrigin(referer: string, requestOrigin: string): boolean {\n if (referer === requestOrigin) return true\n if (!referer.startsWith(requestOrigin)) return false\n if (referer.length === requestOrigin.length) return true\n const code = referer.charCodeAt(requestOrigin.length)\n return code === 47 /* '/' */ || code === 63 /* '?' */ || code === 35 /* '#' */\n}\n\nasync function getFailureResponse<TRegister, TMiddlewares>(\n opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,\n ctx: RequestServerOptions<TRegister, TMiddlewares>,\n): Promise<Response> {\n if (typeof opts.failureResponse === 'function') {\n return opts.failureResponse(ctx)\n }\n\n return (\n opts.failureResponse?.clone() ?? new Response('Forbidden', { status: 403 })\n )\n}\n"],"mappings":";;;AAQA,IAAa,aAAa,OAAO,IAAI,iCAAiC;AAuEtE,IAAM,6BAAmD,OAAO,EAAE,KAAK;CACrE,MAAM,aAAa,kBAAkB,CAAC,OAAO,OAAO,QAAQ;EAC1D,MAAM,UAAU;AAEhB,MAAI,KAAK,UAAU,CAAE,MAAM,KAAK,OAAO,QAAQ,CAC7C,QAAO,IAAI,MAAM;AAGnB,MAAI,MAAM,qBAAqB,MAAM,QAAQ,CAC3C,QAAO,IAAI,MAAM;AAGnB,SAAO,mBAAmB,MAAM,QAAQ;GACxC;AAEF,KAAA,QAAA,IAAA,aAA6B,aAC3B,QAAO,eAAe,YAAY,YAAY,EAAE,OAAO,MAAM,CAAC;AAGhE,QAAO;;AAGT,IAAa,uBACX,oBAAoB,CAAC,OAAO,0BAA0B;AAExD,eAAsB,qBACpB,MACA,KACkB;CAClB,MAAM,SAAS,MAAM,+BAA+B,MAAM,IAAI;AAC9D,QACE,WAAW,QACV,WAAW,KAAA,KAAa,KAAK,oCAAoC;;AAItE,eAAsB,+BACpB,MACA,KAC8B;CAC9B,MAAM,YAAY,IAAI,QAAQ,QAAQ,IAAI,iBAAiB;AAC3D,KAAI,cAAc,KAChB,QAAO,WAAW,KAAK,gBAAgB,eAAe,WAAW,IAAI;CAGvE,MAAM,SAAS,IAAI,QAAQ,QAAQ,IAAI,SAAS;AAChD,KAAI,WAAW,MAAM;AACnB,MAAI,KAAK,OACP,QAAO,WAAW,KAAK,QAAQ,QAAQ,IAAI;AAG7C,SAAO,WAAW,IAAI,IAAI,IAAI,QAAQ,IAAI,CAAC;;CAG7C,MAAM,UAAU,IAAI,QAAQ,QAAQ,IAAI,UAAU;AAClD,KAAI,YAAY,QAAQ,KAAK,YAAY,MACvC;AAGF,KAAI,OAAO,KAAK,YAAY,WAC1B,QAAO,KAAK,QAAQ,SAAS,IAAI;AAGnC,KAAI,KAAK,QAAQ;EACf,MAAM,gBAAgB,iBAAiB,QAAQ;AAC/C,SACE,kBAAkB,KAAA,KAAa,WAAW,KAAK,QAAQ,eAAe,IAAI;;AAI9E,QAAO,oBAAoB,SAAS,IAAI,IAAI,IAAI,QAAQ,IAAI,CAAC,OAAO;;AAGtE,eAAe,WACb,SACA,OACA,KACkB;AAClB,KAAI,OAAO,YAAY,WACrB,QAAO,QAAQ,OAAO,IAAI;AAG5B,KAAI,MAAM,QAAQ,QAAQ,CAExB,QAAO,QAAQ,SAAS,MAAgB;AAG1C,QAAO,UAAU;;AAGnB,SAAS,iBAAiB,KAAiC;AACzD,KAAI;AACF,SAAO,IAAI,IAAI,IAAI,CAAC;SACd;AACN;;;AAIJ,SAAS,oBAAoB,SAAiB,eAAgC;AAC5E,KAAI,YAAY,cAAe,QAAO;AACtC,KAAI,CAAC,QAAQ,WAAW,cAAc,CAAE,QAAO;AAC/C,KAAI,QAAQ,WAAW,cAAc,OAAQ,QAAO;CACpD,MAAM,OAAO,QAAQ,WAAW,cAAc,OAAO;AACrD,QAAO,SAAS,MAAgB,SAAS,MAAgB,SAAS;;AAGpE,eAAe,mBACb,MACA,KACmB;AACnB,KAAI,OAAO,KAAK,oBAAoB,WAClC,QAAO,KAAK,gBAAgB,IAAI;AAGlC,QACE,KAAK,iBAAiB,OAAO,IAAI,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC"}
@@ -171,6 +171,10 @@ export interface RequestServerOptions<TRegister, TMiddlewares> {
171
171
  pathname: string;
172
172
  context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>;
173
173
  next: RequestServerNextFn<TRegister, TMiddlewares>;
174
+ /**
175
+ * Type of Start handler currently processing this request.
176
+ */
177
+ handlerType: 'serverFn' | 'router';
174
178
  /**
175
179
  * Metadata about the server function being invoked.
176
180
  * This is only present when the request is handling a server function call.
@@ -1 +1 @@
1
- {"version":3,"file":"createMiddleware.js","names":[],"sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { middleware }),\n ) as any\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { inputValidator }),\n ) as any\n },\n client: (client: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { client }),\n ) as any\n },\n server: (server: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { server }),\n ) as any\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n inputValidator: <TNewValidator>(\n inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"mappings":";AAiCA,IAAa,oBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAkB;EACtB,MAAM;EACN,GAAI,UAAU;EACf;AAED,QAAO;EACL,SAAS;EACT,aAAa,eAAoB;AAC/B,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,YAAY,CAAC,CAC/C;;EAEH,iBAAiB,mBAAwB;AACvC,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,gBAAgB,CAAC,CACnD;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEJ"}
1
+ {"version":3,"file":"createMiddleware.js","names":[],"sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { middleware }),\n ) as any\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { inputValidator }),\n ) as any\n },\n client: (client: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { client }),\n ) as any\n },\n server: (server: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { server }),\n ) as any\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n inputValidator: <TNewValidator>(\n inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Type of Start handler currently processing this request.\n */\n handlerType: 'serverFn' | 'router'\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"mappings":";AAiCA,IAAa,oBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAkB;EACtB,MAAM;EACN,GAAI,UAAU;EACf;AAED,QAAO;EACL,SAAS;EACT,aAAa,eAAoB;AAC/B,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,YAAY,CAAC,CAC/C;;EAEH,iBAAiB,mBAAwB;AACvC,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,gBAAgB,CAAC,CACnD;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEJ"}
@@ -7,6 +7,8 @@ export { createServerFn } from './createServerFn.js';
7
7
  export { createMiddleware, type IntersectAllValidatorInputs, type IntersectAllValidatorOutputs, type FunctionMiddlewareServerFn, type AnyFunctionMiddleware, type FunctionMiddlewareOptions, type FunctionMiddlewareWithTypes, type FunctionMiddlewareValidator, type FunctionMiddlewareServer, type FunctionMiddlewareAfterClient, type FunctionMiddlewareAfterServer, type FunctionMiddleware, type FunctionMiddlewareAfterMiddleware, type FunctionMiddlewareClientFnOptions, type FunctionMiddlewareClientFnResult, type FunctionMiddlewareClientNextFn, type FunctionClientResultWithContext, type AssignAllClientContextBeforeNext, type AssignAllMiddleware, type FunctionMiddlewareAfterValidator, type FunctionMiddlewareClientFn, type FunctionMiddlewareServerFnResult, type FunctionMiddlewareClient, type FunctionMiddlewareServerFnOptions, type FunctionMiddlewareServerNextFn, type FunctionServerResultWithContext, type AnyRequestMiddleware, type RequestMiddlewareOptions, type RequestMiddlewareWithTypes, type RequestMiddlewareServer, type RequestMiddlewareAfterServer, type RequestMiddleware, type RequestMiddlewareAfterMiddleware, type RequestServerFn, type RequestMiddlewareServerFnResult, type RequestServerOptions, type RequestServerNextFn, type RequestServerNextFnOptions, type RequestServerResult, } from './createMiddleware.js';
8
8
  export type { CompiledFetcherFnOptions, CompiledFetcherFn, CustomFetch, Fetcher, RscStream, FetcherBaseOptions, ServerFn, ServerFnCtx, ServerFnOptions, ServerFnStrict, ServerFnStrictInput, ServerFnStrictOutput, MiddlewareFn, ServerFnMiddlewareOptions, ServerFnMiddlewareResult, ServerFnBuilder, ServerFnBaseOptions, NextFn, Method, OptionalFetcher, RequiredFetcher, } from './createServerFn.js';
9
9
  export { execValidator, flattenMiddlewares, executeMiddleware, } from './createServerFn.js';
10
+ export { createCsrfMiddleware, csrfSymbol, getCsrfRequestValidationResult, isCsrfRequestAllowed, } from './createCsrfMiddleware.js';
11
+ export type { CsrfMatcher, CsrfMiddlewareOptions, CsrfSecFetchSite, } from './createCsrfMiddleware.js';
10
12
  export { TSS_FORMDATA_CONTEXT, TSS_SERVER_FUNCTION, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FRAMED_PROTOCOL_VERSION, FrameType, FRAME_HEADER_SIZE, X_TSS_SERIALIZED, X_TSS_RAW_RESPONSE, X_TSS_CONTEXT, validateFramedProtocolVersion, } from './constants.js';
11
13
  export type { FrameType as FrameTypeValue, ClientFnMeta, ServerFnMeta, } from './constants.js';
12
14
  export type * from './serverRoute.js';
package/dist/esm/index.js CHANGED
@@ -2,6 +2,7 @@ import { FRAME_HEADER_SIZE, FrameType, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE
2
2
  import { createNullProtoObject, safeObjectMerge } from "./safeObjectMerge.js";
3
3
  import { createServerFn, execValidator, executeMiddleware, flattenMiddlewares } from "./createServerFn.js";
4
4
  import { createMiddleware } from "./createMiddleware.js";
5
+ import { createCsrfMiddleware, csrfSymbol, getCsrfRequestValidationResult, isCsrfRequestAllowed } from "./createCsrfMiddleware.js";
5
6
  import { createStart } from "./createStart.js";
6
7
  import { getRouterInstance } from "./getRouterInstance.js";
7
8
  import { getDefaultSerovalPlugins } from "./getDefaultSerovalPlugins.js";
@@ -10,4 +11,4 @@ import { trackPostProcessPromise } from "./client-rpc/serverFnFetcher.js";
10
11
  import { hydrate, json, mergeHeaders } from "@tanstack/router-core/ssr/client";
11
12
  import { RawStream } from "@tanstack/router-core";
12
13
  import { createClientOnlyFn, createIsomorphicFn, createServerOnlyFn } from "@tanstack/start-fn-stubs";
13
- export { FRAME_HEADER_SIZE, FrameType, RawStream, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, createClientOnlyFn, createIsomorphicFn, createMiddleware, createNullProtoObject, createServerFn, createServerOnlyFn, createStart, execValidator, executeMiddleware, flattenMiddlewares, getDefaultSerovalPlugins, getGlobalStartContext, getRouterInstance, hydrate, json, mergeHeaders, safeObjectMerge, trackPostProcessPromise, validateFramedProtocolVersion };
14
+ export { FRAME_HEADER_SIZE, FrameType, RawStream, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, createClientOnlyFn, createCsrfMiddleware, createIsomorphicFn, createMiddleware, createNullProtoObject, createServerFn, createServerOnlyFn, createStart, csrfSymbol, execValidator, executeMiddleware, flattenMiddlewares, getCsrfRequestValidationResult, getDefaultSerovalPlugins, getGlobalStartContext, getRouterInstance, hydrate, isCsrfRequestAllowed, json, mergeHeaders, safeObjectMerge, trackPostProcessPromise, validateFramedProtocolVersion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/start-client-core",
3
- "version": "1.168.2",
3
+ "version": "1.169.1",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -70,9 +70,9 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "seroval": "^1.5.4",
73
- "@tanstack/router-core": "1.169.2",
74
- "@tanstack/start-fn-stubs": "1.161.6",
75
- "@tanstack/start-storage-context": "1.166.35"
73
+ "@tanstack/router-core": "1.170.1",
74
+ "@tanstack/start-fn-stubs": "1.162.0",
75
+ "@tanstack/start-storage-context": "1.167.1"
76
76
  },
77
77
  "devDependencies": {
78
78
  "vite": "*",
@@ -0,0 +1,197 @@
1
+ import { createIsomorphicFn } from '@tanstack/start-fn-stubs'
2
+ import { createMiddleware } from './createMiddleware'
3
+ import type {
4
+ RequestMiddlewareAfterServer,
5
+ RequestServerOptions,
6
+ } from './createMiddleware'
7
+ import type { Register } from '@tanstack/router-core'
8
+
9
+ export const csrfSymbol = Symbol.for('tanstack-start:csrf-middleware')
10
+
11
+ export type CsrfSecFetchSite =
12
+ | 'same-origin'
13
+ | 'same-site'
14
+ | 'cross-site'
15
+ | 'none'
16
+
17
+ export type CsrfMatcher<TValue, TRegister = Register, TMiddlewares = unknown> =
18
+ | TValue
19
+ | Array<TValue>
20
+ | ((
21
+ value: TValue | (string & {}),
22
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
23
+ ) => boolean | Promise<boolean>)
24
+
25
+ export interface CsrfMiddlewareOptions<
26
+ TRegister = Register,
27
+ TMiddlewares = unknown,
28
+ > {
29
+ /**
30
+ * Return `true` to validate this request, or `false` to skip validation.
31
+ *
32
+ * @default undefined, which validates every request handled by this middleware.
33
+ */
34
+ filter?: (
35
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
36
+ ) => boolean | Promise<boolean>
37
+ /**
38
+ * Allowed Origin values. Defaults to the trusted request origin.
39
+ */
40
+ origin?: CsrfMatcher<string, TRegister, TMiddlewares>
41
+ /**
42
+ * Allowed Sec-Fetch-Site values.
43
+ *
44
+ * @default 'same-origin'
45
+ */
46
+ secFetchSite?: CsrfMatcher<CsrfSecFetchSite, TRegister, TMiddlewares>
47
+ /**
48
+ * Whether to use Referer as a fallback when Sec-Fetch-Site and Origin are absent.
49
+ *
50
+ * @default true
51
+ */
52
+ referer?:
53
+ | boolean
54
+ | ((
55
+ referer: string,
56
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
57
+ ) => boolean | Promise<boolean>)
58
+ /**
59
+ * Allow requests when Sec-Fetch-Site, Origin, and Referer are all missing.
60
+ *
61
+ * @default false
62
+ */
63
+ allowRequestsWithoutOriginCheck?: boolean
64
+ /**
65
+ * Optional response returned when CSRF validation fails.
66
+ *
67
+ * @default new Response('Forbidden', { status: 403 })
68
+ */
69
+ failureResponse?:
70
+ | Response
71
+ | ((
72
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
73
+ ) => Response | Promise<Response>)
74
+ }
75
+
76
+ type CreateCsrfMiddleware = <TRegister, TMiddlewares>(
77
+ opts?: CsrfMiddlewareOptions<TRegister, TMiddlewares>,
78
+ ) => RequestMiddlewareAfterServer<{}, undefined, undefined>
79
+
80
+ const innerCreateCsrfMiddleware: CreateCsrfMiddleware = (opts = {}) => {
81
+ const middleware = createMiddleware().server(async (ctx) => {
82
+ const csrfCtx = ctx as RequestServerOptions<any, any>
83
+
84
+ if (opts.filter && !(await opts.filter(csrfCtx))) {
85
+ return ctx.next()
86
+ }
87
+
88
+ if (await isCsrfRequestAllowed(opts, csrfCtx)) {
89
+ return ctx.next()
90
+ }
91
+
92
+ return getFailureResponse(opts, csrfCtx)
93
+ })
94
+
95
+ if (process.env.NODE_ENV !== 'production') {
96
+ Object.defineProperty(middleware, csrfSymbol, { value: true })
97
+ }
98
+
99
+ return middleware
100
+ }
101
+
102
+ export const createCsrfMiddleware: CreateCsrfMiddleware =
103
+ createIsomorphicFn().server(innerCreateCsrfMiddleware) as CreateCsrfMiddleware
104
+
105
+ export async function isCsrfRequestAllowed<TRegister, TMiddlewares>(
106
+ opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,
107
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
108
+ ): Promise<boolean> {
109
+ const result = await getCsrfRequestValidationResult(opts, ctx)
110
+ return (
111
+ result === true ||
112
+ (result === undefined && opts.allowRequestsWithoutOriginCheck === true)
113
+ )
114
+ }
115
+
116
+ export async function getCsrfRequestValidationResult<TRegister, TMiddlewares>(
117
+ opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,
118
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
119
+ ): Promise<boolean | undefined> {
120
+ const fetchSite = ctx.request.headers.get('Sec-Fetch-Site')
121
+ if (fetchSite !== null) {
122
+ return matchValue(opts.secFetchSite ?? 'same-origin', fetchSite, ctx)
123
+ }
124
+
125
+ const origin = ctx.request.headers.get('Origin')
126
+ if (origin !== null) {
127
+ if (opts.origin) {
128
+ return matchValue(opts.origin, origin, ctx)
129
+ }
130
+
131
+ return origin === new URL(ctx.request.url).origin
132
+ }
133
+
134
+ const referer = ctx.request.headers.get('Referer')
135
+ if (referer === null || opts.referer === false) {
136
+ return undefined
137
+ }
138
+
139
+ if (typeof opts.referer === 'function') {
140
+ return opts.referer(referer, ctx)
141
+ }
142
+
143
+ if (opts.origin) {
144
+ const refererOrigin = getOriginFromUrl(referer)
145
+ return (
146
+ refererOrigin !== undefined && matchValue(opts.origin, refererOrigin, ctx)
147
+ )
148
+ }
149
+
150
+ return isRefererSameOrigin(referer, new URL(ctx.request.url).origin)
151
+ }
152
+
153
+ async function matchValue<TValue extends string, TRegister, TMiddlewares>(
154
+ matcher: CsrfMatcher<TValue, TRegister, TMiddlewares>,
155
+ value: string,
156
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
157
+ ): Promise<boolean> {
158
+ if (typeof matcher === 'function') {
159
+ return matcher(value, ctx)
160
+ }
161
+
162
+ if (Array.isArray(matcher)) {
163
+ // typescript is dumb for array.includes()
164
+ return matcher.includes(value as TValue)
165
+ }
166
+
167
+ return value === matcher
168
+ }
169
+
170
+ function getOriginFromUrl(url: string): string | undefined {
171
+ try {
172
+ return new URL(url).origin
173
+ } catch {
174
+ return undefined
175
+ }
176
+ }
177
+
178
+ function isRefererSameOrigin(referer: string, requestOrigin: string): boolean {
179
+ if (referer === requestOrigin) return true
180
+ if (!referer.startsWith(requestOrigin)) return false
181
+ if (referer.length === requestOrigin.length) return true
182
+ const code = referer.charCodeAt(requestOrigin.length)
183
+ return code === 47 /* '/' */ || code === 63 /* '?' */ || code === 35 /* '#' */
184
+ }
185
+
186
+ async function getFailureResponse<TRegister, TMiddlewares>(
187
+ opts: CsrfMiddlewareOptions<TRegister, TMiddlewares>,
188
+ ctx: RequestServerOptions<TRegister, TMiddlewares>,
189
+ ): Promise<Response> {
190
+ if (typeof opts.failureResponse === 'function') {
191
+ return opts.failureResponse(ctx)
192
+ }
193
+
194
+ return (
195
+ opts.failureResponse?.clone() ?? new Response('Forbidden', { status: 403 })
196
+ )
197
+ }
@@ -770,6 +770,10 @@ export interface RequestServerOptions<TRegister, TMiddlewares> {
770
770
  pathname: string
771
771
  context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>
772
772
  next: RequestServerNextFn<TRegister, TMiddlewares>
773
+ /**
774
+ * Type of Start handler currently processing this request.
775
+ */
776
+ handlerType: 'serverFn' | 'router'
773
777
  /**
774
778
  * Metadata about the server function being invoked.
775
779
  * This is only present when the request is handling a server function call.
package/src/index.tsx CHANGED
@@ -84,6 +84,17 @@ export {
84
84
  flattenMiddlewares,
85
85
  executeMiddleware,
86
86
  } from './createServerFn'
87
+ export {
88
+ createCsrfMiddleware,
89
+ csrfSymbol,
90
+ getCsrfRequestValidationResult,
91
+ isCsrfRequestAllowed,
92
+ } from './createCsrfMiddleware'
93
+ export type {
94
+ CsrfMatcher,
95
+ CsrfMiddlewareOptions,
96
+ CsrfSecFetchSite,
97
+ } from './createCsrfMiddleware'
87
98
 
88
99
  export {
89
100
  TSS_FORMDATA_CONTEXT,
@@ -675,6 +675,7 @@ test('createMiddleware with type request, no middleware or context', () => {
675
675
  next: RequestServerNextFn<{}, undefined>
676
676
  pathname: string
677
677
  context: undefined
678
+ handlerType: 'serverFn' | 'router'
678
679
  serverFnMeta?: ServerFnMeta
679
680
  }>()
680
681
 
@@ -698,6 +699,7 @@ test('createMiddleware with type request, no middleware with context', () => {
698
699
  next: RequestServerNextFn<{}, undefined>
699
700
  pathname: string
700
701
  context: undefined
702
+ handlerType: 'serverFn' | 'router'
701
703
  serverFnMeta?: ServerFnMeta
702
704
  }>()
703
705
 
@@ -722,6 +724,7 @@ test('createMiddleware with type request, middleware and context', () => {
722
724
  next: RequestServerNextFn<{}, undefined>
723
725
  pathname: string
724
726
  context: undefined
727
+ handlerType: 'serverFn' | 'router'
725
728
  serverFnMeta?: ServerFnMeta
726
729
  }>()
727
730
 
@@ -746,6 +749,7 @@ test('createMiddleware with type request, middleware and context', () => {
746
749
  next: RequestServerNextFn<{}, undefined>
747
750
  pathname: string
748
751
  context: { a: string }
752
+ handlerType: 'serverFn' | 'router'
749
753
  serverFnMeta?: ServerFnMeta
750
754
  }>()
751
755
 
@@ -769,6 +773,7 @@ test('createMiddleware with type request can return Response directly', () => {
769
773
  next: RequestServerNextFn<{}, undefined>
770
774
  pathname: string
771
775
  context: undefined
776
+ handlerType: 'serverFn' | 'router'
772
777
  serverFnMeta?: ServerFnMeta
773
778
  }>()
774
779
 
@@ -789,6 +794,7 @@ test('createMiddleware with type request can return Promise<Response>', () => {
789
794
  next: RequestServerNextFn<{}, undefined>
790
795
  pathname: string
791
796
  context: undefined
797
+ handlerType: 'serverFn' | 'router'
792
798
  serverFnMeta?: ServerFnMeta
793
799
  }>()
794
800
 
@@ -804,6 +810,7 @@ test('createMiddleware with type request can return sync Response', () => {
804
810
  next: RequestServerNextFn<{}, undefined>
805
811
  pathname: string
806
812
  context: undefined
813
+ handlerType: 'serverFn' | 'router'
807
814
  serverFnMeta?: ServerFnMeta
808
815
  }>()
809
816