@tanstack/start-client-core 1.168.2 → 1.169.0
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.
- package/dist/esm/createCsrfMiddleware.d.ts +46 -0
- package/dist/esm/createCsrfMiddleware.js +63 -0
- package/dist/esm/createCsrfMiddleware.js.map +1 -0
- package/dist/esm/createMiddleware.d.ts +4 -0
- package/dist/esm/createMiddleware.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -1
- package/package.json +4 -4
- package/src/createCsrfMiddleware.ts +197 -0
- package/src/createMiddleware.ts +4 -0
- package/src/index.tsx +11 -0
- package/src/tests/createServerMiddleware.test-d.ts +7 -0
|
@@ -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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "1.169.0",
|
|
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.
|
|
74
|
-
"@tanstack/start-fn-stubs": "1.
|
|
75
|
-
"@tanstack/start-storage-context": "1.
|
|
73
|
+
"@tanstack/router-core": "1.170.0",
|
|
74
|
+
"@tanstack/start-fn-stubs": "1.162.0",
|
|
75
|
+
"@tanstack/start-storage-context": "1.167.0"
|
|
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
|
+
}
|
package/src/createMiddleware.ts
CHANGED
|
@@ -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
|
|