@tanstack/start-client-core 1.151.6 → 1.152.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/client-rpc/serverFnFetcher.js +2 -1
- package/dist/esm/client-rpc/serverFnFetcher.js.map +1 -1
- package/dist/esm/createMiddleware.d.ts +5 -1
- package/dist/esm/createMiddleware.js.map +1 -1
- package/dist/esm/createServerFn.d.ts +4 -0
- package/dist/esm/createServerFn.js +8 -3
- package/dist/esm/createServerFn.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/client-rpc/serverFnFetcher.ts +5 -1
- package/src/createMiddleware.ts +10 -1
- package/src/createServerFn.ts +13 -1
- package/src/index.tsx +1 -0
- package/src/tests/createServerFn.test-d.ts +15 -1
- package/src/tests/createServerMiddleware.test-d.ts +10 -1
|
@@ -20,6 +20,7 @@ async function serverFnFetcher(url, args, handler) {
|
|
|
20
20
|
}
|
|
21
21
|
const _first = args[0];
|
|
22
22
|
const first = _first;
|
|
23
|
+
const fetchImpl = first.fetch ?? handler;
|
|
23
24
|
const type = first.data instanceof FormData ? "formData" : "payload";
|
|
24
25
|
const headers = first.headers ? new Headers(first.headers) : new Headers();
|
|
25
26
|
headers.set("x-tsr-serverFn", "true");
|
|
@@ -54,7 +55,7 @@ async function serverFnFetcher(url, args, handler) {
|
|
|
54
55
|
body = fetchBody?.body;
|
|
55
56
|
}
|
|
56
57
|
return await getResponse(
|
|
57
|
-
async () =>
|
|
58
|
+
async () => fetchImpl(url, {
|
|
58
59
|
method: first.method,
|
|
59
60
|
headers,
|
|
60
61
|
signal: first.signal,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverFnFetcher.js","sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n createRawStreamDeserializePlugin,\n encode,\n isNotFound,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport {\n TSS_CONTENT_TYPE_FRAMED,\n TSS_FORMDATA_CONTEXT,\n X_TSS_RAW_RESPONSE,\n X_TSS_SERIALIZED,\n validateFramedProtocolVersion,\n} from '../constants'\nimport { createFrameDecoder } from './frame-decoder'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\n\n/**\n * Checks if an object has at least one own enumerable property.\n * More efficient than Object.keys(obj).length > 0 as it short-circuits on first property.\n */\nconst hop = Object.prototype.hasOwnProperty\nfunction hasOwnProperties(obj: object): boolean {\n for (const _ in obj) {\n if (hop.call(obj, _)) {\n return true\n }\n }\n return false\n}\n// caller =>\n// serverFnFetcher =>\n// client =>\n// server =>\n// fn =>\n// seroval =>\n// client middleware =>\n// serverFnFetcher =>\n// caller\n\nexport async function serverFnFetcher(\n url: string,\n args: Array<any>,\n handler: (url: string, requestInit: RequestInit) => Promise<Response>,\n) {\n if (!serovalPlugins) {\n serovalPlugins = getDefaultSerovalPlugins()\n }\n const _first = args[0]\n\n const first = _first as FunctionMiddlewareClientFnOptions<any, any, any> & {\n headers?: HeadersInit\n }\n const type = first.data instanceof FormData ? 'formData' : 'payload'\n\n // Arrange the headers\n const headers = first.headers ? new Headers(first.headers) : new Headers()\n headers.set('x-tsr-serverFn', 'true')\n\n if (type === 'payload') {\n headers.set(\n 'accept',\n `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json`,\n )\n }\n\n // If the method is GET, we need to move the payload to the query string\n if (first.method === 'GET') {\n if (type === 'formData') {\n throw new Error('FormData is not supported with GET requests')\n }\n const serializedPayload = await serializePayload(first)\n if (serializedPayload !== undefined) {\n const encodedPayload = encode({\n payload: serializedPayload,\n })\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n let body = undefined\n if (first.method === 'POST') {\n const fetchBody = await getFetchBody(first)\n if (fetchBody?.contentType) {\n headers.set('content-type', fetchBody.contentType)\n }\n body = fetchBody?.body\n }\n\n return await getResponse(async () =>\n handler(url, {\n method: first.method,\n headers,\n signal: first.signal,\n body,\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<string | undefined> {\n let payloadAvailable = false\n const payloadToSerialize: any = {}\n if (opts.data !== undefined) {\n payloadAvailable = true\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n payloadAvailable = true\n payloadToSerialize['context'] = opts.context\n }\n\n if (payloadAvailable) {\n return serialize(payloadToSerialize)\n }\n return undefined\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetchBody(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<{ body: FormData | string; contentType?: string } | undefined> {\n if (opts.data instanceof FormData) {\n let serializedContext = undefined\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n serializedContext = await serialize(opts.context)\n }\n if (serializedContext !== undefined) {\n opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext)\n }\n return { body: opts.data }\n }\n const serializedBody = await serializePayload(opts)\n if (serializedBody) {\n return { body: serializedBody, contentType: 'application/json' }\n }\n return undefined\n}\n\n/**\n * Retrieves a response from a given function and manages potential errors\n * and special response types including redirects and not found errors.\n *\n * @param fn - The function to execute for obtaining the response.\n * @returns The processed response from the function.\n * @throws If the response is invalid or an error occurs during processing.\n */\nasync function getResponse(fn: () => Promise<Response>) {\n let response: Response\n try {\n response = await fn() // client => server => fn => server => client\n } catch (error) {\n if (error instanceof Response) {\n response = error\n } else {\n console.log(error)\n throw error\n }\n }\n\n if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {\n return response\n }\n\n const contentType = response.headers.get('content-type')\n invariant(contentType, 'expected content-type header to be set')\n const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED)\n\n // If the response is serialized by the start server, we need to process it\n // differently than a normal response.\n if (serializedByStart) {\n let result\n\n // If it's a framed response (contains RawStream), use frame decoder\n if (contentType.includes(TSS_CONTENT_TYPE_FRAMED)) {\n // Validate protocol version compatibility\n validateFramedProtocolVersion(contentType)\n\n if (!response.body) {\n throw new Error('No response body for framed response')\n }\n\n const { getOrCreateStream, jsonChunks } = createFrameDecoder(\n response.body,\n )\n\n // Create deserialize plugin that wires up the raw streams\n const rawStreamPlugin =\n createRawStreamDeserializePlugin(getOrCreateStream)\n const plugins = [rawStreamPlugin, ...(serovalPlugins || [])]\n\n const refs = new Map()\n result = await processFramedResponse({\n jsonStream: jsonChunks,\n onMessage: (msg: any) => fromCrossJSON(msg, { refs, plugins }),\n onError(msg, error) {\n console.error(msg, error)\n },\n })\n }\n // If it's a stream from the start serializer, process it as such\n else if (contentType.includes('application/x-ndjson')) {\n const refs = new Map()\n result = await processServerFnResponse({\n response,\n onMessage: (msg) =>\n fromCrossJSON(msg, { refs, plugins: serovalPlugins! }),\n onError(msg, error) {\n // TODO how could we notify consumer that an error occurred?\n console.error(msg, error)\n },\n })\n }\n // If it's a JSON response, it can be simpler\n else if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n\n return result\n }\n\n // If it wasn't processed by the start serializer, check\n // if it's JSON\n if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const redirect = parseRedirect(jsonPayload)\n if (redirect) {\n throw redirect\n }\n if (isNotFound(jsonPayload)) {\n throw jsonPayload\n }\n return jsonPayload\n }\n\n // Otherwise, if it's not OK, throw the content\n if (!response.ok) {\n throw new Error(await response.text())\n }\n\n // Or return the response itself\n return response\n}\n\nasync function processServerFnResponse({\n response,\n onMessage,\n onError,\n}: {\n response: Response\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n if (!response.body) {\n throw new Error('No response body')\n }\n\n const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()\n\n let buffer = ''\n let firstRead = false\n let firstObject\n\n while (!firstRead) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n if (buffer.length === 0 && done) {\n throw new Error('Stream ended before first object')\n }\n\n // common case: buffer ends with newline\n if (buffer.endsWith('\\n')) {\n const lines = buffer.split('\\n').filter(Boolean)\n const firstLine = lines[0]\n if (!firstLine) throw new Error('No JSON line in the first chunk')\n firstObject = JSON.parse(firstLine)\n firstRead = true\n buffer = lines.slice(1).join('\\n')\n } else {\n // fallback: wait for a newline to parse first object safely\n const newlineIndex = buffer.indexOf('\\n')\n if (newlineIndex >= 0) {\n const line = buffer.slice(0, newlineIndex).trim()\n buffer = buffer.slice(newlineIndex + 1)\n if (line.length > 0) {\n firstObject = JSON.parse(line)\n firstRead = true\n }\n }\n }\n }\n\n // process rest of the stream asynchronously\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n const lastNewline = buffer.lastIndexOf('\\n')\n if (lastNewline >= 0) {\n const chunk = buffer.slice(0, lastNewline)\n buffer = buffer.slice(lastNewline + 1)\n const lines = chunk.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n try {\n onMessage(JSON.parse(line))\n } catch (e) {\n onError?.(`Invalid JSON line: ${line}`, e)\n }\n }\n }\n\n if (done) {\n break\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n\n/**\n * Processes a framed response where each JSON chunk is a complete JSON string\n * (already decoded by frame decoder).\n */\nasync function processFramedResponse({\n jsonStream,\n onMessage,\n onError,\n}: {\n jsonStream: ReadableStream<string>\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n const reader = jsonStream.getReader()\n\n // Read first JSON frame - this is the main result\n const { value: firstValue, done: firstDone } = await reader.read()\n if (firstDone || !firstValue) {\n throw new Error('Stream ended before first object')\n }\n\n // Each frame is a complete JSON string\n const firstObject = JSON.parse(firstValue)\n\n // Process remaining frames asynchronously (for streaming refs like RawStream)\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n try {\n onMessage(JSON.parse(value))\n } catch (e) {\n onError?.(`Invalid JSON: ${value}`, e)\n }\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"serverFnFetcher.js","sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n createRawStreamDeserializePlugin,\n encode,\n isNotFound,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport {\n TSS_CONTENT_TYPE_FRAMED,\n TSS_FORMDATA_CONTEXT,\n X_TSS_RAW_RESPONSE,\n X_TSS_SERIALIZED,\n validateFramedProtocolVersion,\n} from '../constants'\nimport { createFrameDecoder } from './frame-decoder'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\n\n/**\n * Checks if an object has at least one own enumerable property.\n * More efficient than Object.keys(obj).length > 0 as it short-circuits on first property.\n */\nconst hop = Object.prototype.hasOwnProperty\nfunction hasOwnProperties(obj: object): boolean {\n for (const _ in obj) {\n if (hop.call(obj, _)) {\n return true\n }\n }\n return false\n}\n// caller =>\n// serverFnFetcher =>\n// client =>\n// server =>\n// fn =>\n// seroval =>\n// client middleware =>\n// serverFnFetcher =>\n// caller\n\nexport async function serverFnFetcher(\n url: string,\n args: Array<any>,\n handler: (url: string, requestInit: RequestInit) => Promise<Response>,\n) {\n if (!serovalPlugins) {\n serovalPlugins = getDefaultSerovalPlugins()\n }\n const _first = args[0]\n\n const first = _first as FunctionMiddlewareClientFnOptions<any, any, any> & {\n headers?: HeadersInit\n }\n\n // Use custom fetch if provided, otherwise fall back to the passed handler (global fetch)\n const fetchImpl = first.fetch ?? handler\n\n const type = first.data instanceof FormData ? 'formData' : 'payload'\n\n // Arrange the headers\n const headers = first.headers ? new Headers(first.headers) : new Headers()\n headers.set('x-tsr-serverFn', 'true')\n\n if (type === 'payload') {\n headers.set(\n 'accept',\n `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json`,\n )\n }\n\n // If the method is GET, we need to move the payload to the query string\n if (first.method === 'GET') {\n if (type === 'formData') {\n throw new Error('FormData is not supported with GET requests')\n }\n const serializedPayload = await serializePayload(first)\n if (serializedPayload !== undefined) {\n const encodedPayload = encode({\n payload: serializedPayload,\n })\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n let body = undefined\n if (first.method === 'POST') {\n const fetchBody = await getFetchBody(first)\n if (fetchBody?.contentType) {\n headers.set('content-type', fetchBody.contentType)\n }\n body = fetchBody?.body\n }\n\n return await getResponse(async () =>\n fetchImpl(url, {\n method: first.method,\n headers,\n signal: first.signal,\n body,\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<string | undefined> {\n let payloadAvailable = false\n const payloadToSerialize: any = {}\n if (opts.data !== undefined) {\n payloadAvailable = true\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n payloadAvailable = true\n payloadToSerialize['context'] = opts.context\n }\n\n if (payloadAvailable) {\n return serialize(payloadToSerialize)\n }\n return undefined\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetchBody(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<{ body: FormData | string; contentType?: string } | undefined> {\n if (opts.data instanceof FormData) {\n let serializedContext = undefined\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n serializedContext = await serialize(opts.context)\n }\n if (serializedContext !== undefined) {\n opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext)\n }\n return { body: opts.data }\n }\n const serializedBody = await serializePayload(opts)\n if (serializedBody) {\n return { body: serializedBody, contentType: 'application/json' }\n }\n return undefined\n}\n\n/**\n * Retrieves a response from a given function and manages potential errors\n * and special response types including redirects and not found errors.\n *\n * @param fn - The function to execute for obtaining the response.\n * @returns The processed response from the function.\n * @throws If the response is invalid or an error occurs during processing.\n */\nasync function getResponse(fn: () => Promise<Response>) {\n let response: Response\n try {\n response = await fn() // client => server => fn => server => client\n } catch (error) {\n if (error instanceof Response) {\n response = error\n } else {\n console.log(error)\n throw error\n }\n }\n\n if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {\n return response\n }\n\n const contentType = response.headers.get('content-type')\n invariant(contentType, 'expected content-type header to be set')\n const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED)\n\n // If the response is serialized by the start server, we need to process it\n // differently than a normal response.\n if (serializedByStart) {\n let result\n\n // If it's a framed response (contains RawStream), use frame decoder\n if (contentType.includes(TSS_CONTENT_TYPE_FRAMED)) {\n // Validate protocol version compatibility\n validateFramedProtocolVersion(contentType)\n\n if (!response.body) {\n throw new Error('No response body for framed response')\n }\n\n const { getOrCreateStream, jsonChunks } = createFrameDecoder(\n response.body,\n )\n\n // Create deserialize plugin that wires up the raw streams\n const rawStreamPlugin =\n createRawStreamDeserializePlugin(getOrCreateStream)\n const plugins = [rawStreamPlugin, ...(serovalPlugins || [])]\n\n const refs = new Map()\n result = await processFramedResponse({\n jsonStream: jsonChunks,\n onMessage: (msg: any) => fromCrossJSON(msg, { refs, plugins }),\n onError(msg, error) {\n console.error(msg, error)\n },\n })\n }\n // If it's a stream from the start serializer, process it as such\n else if (contentType.includes('application/x-ndjson')) {\n const refs = new Map()\n result = await processServerFnResponse({\n response,\n onMessage: (msg) =>\n fromCrossJSON(msg, { refs, plugins: serovalPlugins! }),\n onError(msg, error) {\n // TODO how could we notify consumer that an error occurred?\n console.error(msg, error)\n },\n })\n }\n // If it's a JSON response, it can be simpler\n else if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n\n return result\n }\n\n // If it wasn't processed by the start serializer, check\n // if it's JSON\n if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const redirect = parseRedirect(jsonPayload)\n if (redirect) {\n throw redirect\n }\n if (isNotFound(jsonPayload)) {\n throw jsonPayload\n }\n return jsonPayload\n }\n\n // Otherwise, if it's not OK, throw the content\n if (!response.ok) {\n throw new Error(await response.text())\n }\n\n // Or return the response itself\n return response\n}\n\nasync function processServerFnResponse({\n response,\n onMessage,\n onError,\n}: {\n response: Response\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n if (!response.body) {\n throw new Error('No response body')\n }\n\n const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()\n\n let buffer = ''\n let firstRead = false\n let firstObject\n\n while (!firstRead) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n if (buffer.length === 0 && done) {\n throw new Error('Stream ended before first object')\n }\n\n // common case: buffer ends with newline\n if (buffer.endsWith('\\n')) {\n const lines = buffer.split('\\n').filter(Boolean)\n const firstLine = lines[0]\n if (!firstLine) throw new Error('No JSON line in the first chunk')\n firstObject = JSON.parse(firstLine)\n firstRead = true\n buffer = lines.slice(1).join('\\n')\n } else {\n // fallback: wait for a newline to parse first object safely\n const newlineIndex = buffer.indexOf('\\n')\n if (newlineIndex >= 0) {\n const line = buffer.slice(0, newlineIndex).trim()\n buffer = buffer.slice(newlineIndex + 1)\n if (line.length > 0) {\n firstObject = JSON.parse(line)\n firstRead = true\n }\n }\n }\n }\n\n // process rest of the stream asynchronously\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n const lastNewline = buffer.lastIndexOf('\\n')\n if (lastNewline >= 0) {\n const chunk = buffer.slice(0, lastNewline)\n buffer = buffer.slice(lastNewline + 1)\n const lines = chunk.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n try {\n onMessage(JSON.parse(line))\n } catch (e) {\n onError?.(`Invalid JSON line: ${line}`, e)\n }\n }\n }\n\n if (done) {\n break\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n\n/**\n * Processes a framed response where each JSON chunk is a complete JSON string\n * (already decoded by frame decoder).\n */\nasync function processFramedResponse({\n jsonStream,\n onMessage,\n onError,\n}: {\n jsonStream: ReadableStream<string>\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n const reader = jsonStream.getReader()\n\n // Read first JSON frame - this is the main result\n const { value: firstValue, done: firstDone } = await reader.read()\n if (firstDone || !firstValue) {\n throw new Error('Stream ended before first object')\n }\n\n // Each frame is a complete JSON string\n const firstObject = JSON.parse(firstValue)\n\n // Process remaining frames asynchronously (for streaming refs like RawStream)\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n try {\n onMessage(JSON.parse(value))\n } catch (e) {\n onError?.(`Invalid JSON: ${value}`, e)\n }\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StartInstanceOptions } from './createStart.js';
|
|
2
|
-
import { AnyServerFn, ConstrainValidator, Method } from './createServerFn.js';
|
|
2
|
+
import { AnyServerFn, ConstrainValidator, CustomFetch, Method } from './createServerFn.js';
|
|
3
3
|
import { ClientFnMeta, ServerFnMeta } from './constants.js';
|
|
4
4
|
import { AnyContext, Assign, Constrain, Expand, IntersectAssign, Register, ResolveValidatorInput, ResolveValidatorOutput, ValidateSerializableInput } from '@tanstack/router-core';
|
|
5
5
|
export type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(options?: {
|
|
@@ -80,6 +80,7 @@ export type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <TSendCont
|
|
|
80
80
|
context?: TNewClientContext;
|
|
81
81
|
sendContext?: ValidateSerializableInput<TRegister, TSendContext>;
|
|
82
82
|
headers?: HeadersInit;
|
|
83
|
+
fetch?: CustomFetch;
|
|
83
84
|
}) => Promise<FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>>;
|
|
84
85
|
export interface FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> {
|
|
85
86
|
server: <TNewServerContext = undefined, TSendContext = undefined>(server: FunctionMiddlewareServerFn<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TNewServerContext, TSendContext>) => FunctionMiddlewareAfterServer<TRegister, TMiddlewares, TInputValidator, TNewServerContext, TServerSendContext, TClientContext, TSendContext>;
|
|
@@ -121,6 +122,8 @@ export interface FunctionMiddlewareClientFnOptions<in out TRegister, in out TMid
|
|
|
121
122
|
signal: AbortSignal;
|
|
122
123
|
serverFnMeta: ClientFnMeta;
|
|
123
124
|
next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>;
|
|
125
|
+
filename: string;
|
|
126
|
+
fetch?: CustomFetch;
|
|
124
127
|
}
|
|
125
128
|
export type FunctionMiddlewareClientFnResult<TMiddlewares, TSendContext, TClientContext> = Promise<FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>> | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>;
|
|
126
129
|
export type FunctionClientResultWithContext<in out TMiddlewares, in out TSendContext, in out TClientContext> = {
|
|
@@ -128,6 +131,7 @@ export type FunctionClientResultWithContext<in out TMiddlewares, in out TSendCon
|
|
|
128
131
|
context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>;
|
|
129
132
|
sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>;
|
|
130
133
|
headers: HeadersInit;
|
|
134
|
+
fetch?: CustomFetch;
|
|
131
135
|
};
|
|
132
136
|
export interface FunctionMiddlewareAfterClient<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> extends FunctionMiddlewareWithTypes<TRegister, TMiddlewares, TInputValidator, undefined, TServerSendContext, TClientContext, undefined>, FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> {
|
|
133
137
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMiddleware.js","sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type { AnyServerFn, ConstrainValidator, Method } 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}) => 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}\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}\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"],"names":[],"mappings":"AA4BO,MAAM,mBAA2C,CAAC,SAAS,WAAW;AAC3E,QAAM,kBAAkB;AAAA,IACtB,MAAM;AAAA,IACN,GAAI,UAAU;AAAA,EAAA;AAGhB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC,eAAoB;AAC/B,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,YAAY;AAAA,MAAA;AAAA,IAEjD;AAAA,IACA,gBAAgB,CAAC,mBAAwB;AACvC,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,gBAAgB;AAAA,MAAA;AAAA,IAErD;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,EAAA;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"createMiddleware.js","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"],"names":[],"mappings":"AAiCO,MAAM,mBAA2C,CAAC,SAAS,WAAW;AAC3E,QAAM,kBAAkB;AAAA,IACtB,MAAM;AAAA,IACN,GAAI,UAAU;AAAA,EAAA;AAGhB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC,eAAoB;AAC/B,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,YAAY;AAAA,MAAA;AAAA,IAEjD;AAAA,IACA,gBAAgB,CAAC,mBAAwB;AACvC,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,gBAAgB;AAAA,MAAA;AAAA,IAErD;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,EAAA;AAEJ;"}
|
|
@@ -11,6 +11,7 @@ export type CompiledFetcherFnOptions = {
|
|
|
11
11
|
data: unknown;
|
|
12
12
|
headers?: HeadersInit;
|
|
13
13
|
signal?: AbortSignal;
|
|
14
|
+
fetch?: CustomFetch;
|
|
14
15
|
context?: any;
|
|
15
16
|
};
|
|
16
17
|
export type Fetcher<TMiddlewares, TInputValidator, TResponse> = undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator> ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse> : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>;
|
|
@@ -31,9 +32,11 @@ export interface OptionalFetcher<TMiddlewares, TInputValidator, TResponse> exten
|
|
|
31
32
|
export interface RequiredFetcher<TMiddlewares, TInputValidator, TResponse> extends FetcherBase {
|
|
32
33
|
(opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>): Promise<Awaited<TResponse>>;
|
|
33
34
|
}
|
|
35
|
+
export type CustomFetch = typeof globalThis.fetch;
|
|
34
36
|
export type FetcherBaseOptions = {
|
|
35
37
|
headers?: HeadersInit;
|
|
36
38
|
signal?: AbortSignal;
|
|
39
|
+
fetch?: CustomFetch;
|
|
37
40
|
};
|
|
38
41
|
export interface OptionalFetcherDataOptions<TMiddlewares, TInputValidator> extends FetcherBaseOptions {
|
|
39
42
|
data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>;
|
|
@@ -116,6 +119,7 @@ export type ServerFnMiddlewareOptions = {
|
|
|
116
119
|
sendContext?: any;
|
|
117
120
|
context?: any;
|
|
118
121
|
serverFnMeta: ClientFnMeta;
|
|
122
|
+
fetch?: CustomFetch;
|
|
119
123
|
};
|
|
120
124
|
export type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {
|
|
121
125
|
result?: unknown;
|
|
@@ -49,6 +49,7 @@ const createServerFn = (options, __opts) => {
|
|
|
49
49
|
data: opts?.data,
|
|
50
50
|
headers: opts?.headers,
|
|
51
51
|
signal: opts?.signal,
|
|
52
|
+
fetch: opts?.fetch,
|
|
52
53
|
context: createNullProtoObject()
|
|
53
54
|
});
|
|
54
55
|
const redirect = parseRedirect(result.error);
|
|
@@ -148,6 +149,8 @@ async function executeMiddleware(middlewares, env, opts) {
|
|
|
148
149
|
context: safeObjectMerge(ctx.context, userCtx.context),
|
|
149
150
|
sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),
|
|
150
151
|
headers: mergeHeaders(ctx.headers, userCtx.headers),
|
|
152
|
+
_callSiteFetch: ctx._callSiteFetch,
|
|
153
|
+
fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,
|
|
151
154
|
result: userCtx.result !== void 0 ? userCtx.result : userCtx instanceof Response ? userCtx : ctx.result,
|
|
152
155
|
error: userCtx.error ?? ctx.error
|
|
153
156
|
};
|
|
@@ -192,7 +195,8 @@ async function executeMiddleware(middlewares, env, opts) {
|
|
|
192
195
|
...opts,
|
|
193
196
|
headers: opts.headers || {},
|
|
194
197
|
sendContext: opts.sendContext || {},
|
|
195
|
-
context: opts.context || createNullProtoObject()
|
|
198
|
+
context: opts.context || createNullProtoObject(),
|
|
199
|
+
_callSiteFetch: opts.fetch
|
|
196
200
|
});
|
|
197
201
|
}
|
|
198
202
|
function flattenMiddlewares(middlewares, maxDepth = 100) {
|
|
@@ -238,11 +242,12 @@ function serverFnBaseToMiddleware(options) {
|
|
|
238
242
|
"~types": void 0,
|
|
239
243
|
options: {
|
|
240
244
|
inputValidator: options.inputValidator,
|
|
241
|
-
client: async ({ next, sendContext, ...ctx }) => {
|
|
245
|
+
client: async ({ next, sendContext, fetch, ...ctx }) => {
|
|
242
246
|
const payload = {
|
|
243
247
|
...ctx,
|
|
244
248
|
// switch the sendContext over to context
|
|
245
|
-
context: sendContext
|
|
249
|
+
context: sendContext,
|
|
250
|
+
fetch
|
|
246
251
|
};
|
|
247
252
|
const res = await options.extractedFn?.(payload);
|
|
248
253
|
return next(res);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: {\n method?: TMethod\n },\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator\n >,\n) => ServerFnBuilder<TRegister, TMethod>\n\nexport const createServerFn: CreateServerFn<Register> = (options, __opts) => {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n any,\n any,\n any,\n any,\n any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const res: ServerFnBuilder<Register, Method> = {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n // multiple calls to `middleware()` merge the middlewares with the previously supplied ones\n // this is primarily useful for letting users create their own abstractions on top of `createServerFn`\n\n const newMiddleware = [...(resolvedOptions.middleware || [])]\n middleware.map((m) => {\n if (TSS_SERVER_FUNCTION_FACTORY in m) {\n if (m.options.middleware) {\n newMiddleware.push(...m.options.middleware)\n }\n } else {\n newMiddleware.push(m)\n }\n })\n\n const newOptions = {\n ...resolvedOptions,\n middleware: newMiddleware,\n }\n const res = createServerFn(undefined, newOptions) as any\n res[TSS_SERVER_FUNCTION_FACTORY] = true\n return res\n },\n inputValidator: (inputValidator) => {\n const newOptions = { ...resolvedOptions, inputValidator }\n return createServerFn(undefined, newOptions) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<Register, any>,\n ServerFn<Register, Method, any, any, any>,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n const newOptions = { ...resolvedOptions, extractedFn, serverFn }\n\n const resolvedMiddleware = [\n ...(newOptions.middleware || []),\n serverFnBaseToMiddleware(newOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n // Use safeObjectMerge for opts.context which comes from client\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Use safeObjectMerge for opts.context which comes from client\n context: safeObjectMerge(\n serverContextAfterGlobalMiddlewares,\n opts.context,\n ),\n signal,\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions) as any\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n if (\n 'inputValidator' in nextMiddleware.options &&\n nextMiddleware.options.inputValidator &&\n env === 'server'\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(\n nextMiddleware.options.inputValidator,\n ctx.data,\n )\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext as any,\n } as any)\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n> = {\n method: TMethod\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> = TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {\n <TNewMethod extends Method = TMethod>(options?: {\n method?: TNewMethod\n }): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator\n >\n}\n\nexport type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares> = <\n TInputValidator,\n>(\n inputValidator: ConstrainValidator<TRegister, TMethod, TInputValidator>,\n) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>\n extends\n ServerFnWithTypes<TRegister, TMethod, undefined, undefined, undefined>,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined>,\n ServerFnValidator<TRegister, TMethod, undefined>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined> {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n method: TMethod\n middlewares: TMiddlewares\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n '~types': undefined!,\n options: {\n inputValidator: options.inputValidator,\n client: async ({ next, sendContext, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":["res","options","result"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: {\n method?: TMethod\n },\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator\n >,\n) => ServerFnBuilder<TRegister, TMethod>\n\nexport const createServerFn: CreateServerFn<Register> = (options, __opts) => {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n any,\n any,\n any,\n any,\n any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const res: ServerFnBuilder<Register, Method> = {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n // multiple calls to `middleware()` merge the middlewares with the previously supplied ones\n // this is primarily useful for letting users create their own abstractions on top of `createServerFn`\n\n const newMiddleware = [...(resolvedOptions.middleware || [])]\n middleware.map((m) => {\n if (TSS_SERVER_FUNCTION_FACTORY in m) {\n if (m.options.middleware) {\n newMiddleware.push(...m.options.middleware)\n }\n } else {\n newMiddleware.push(m)\n }\n })\n\n const newOptions = {\n ...resolvedOptions,\n middleware: newMiddleware,\n }\n const res = createServerFn(undefined, newOptions) as any\n res[TSS_SERVER_FUNCTION_FACTORY] = true\n return res\n },\n inputValidator: (inputValidator) => {\n const newOptions = { ...resolvedOptions, inputValidator }\n return createServerFn(undefined, newOptions) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<Register, any>,\n ServerFn<Register, Method, any, any, any>,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n const newOptions = { ...resolvedOptions, extractedFn, serverFn }\n\n const resolvedMiddleware = [\n ...(newOptions.middleware || []),\n serverFnBaseToMiddleware(newOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n fetch: opts?.fetch,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n // Use safeObjectMerge for opts.context which comes from client\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Use safeObjectMerge for opts.context which comes from client\n context: safeObjectMerge(\n serverContextAfterGlobalMiddlewares,\n opts.context,\n ),\n signal,\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions) as any\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n if (\n 'inputValidator' in nextMiddleware.options &&\n nextMiddleware.options.inputValidator &&\n env === 'server'\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(\n nextMiddleware.options.inputValidator,\n ctx.data,\n )\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n _callSiteFetch: ctx._callSiteFetch,\n fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext as any,\n } as any)\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n _callSiteFetch: opts.fetch,\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport type CustomFetch = typeof globalThis.fetch\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n> = {\n method: TMethod\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> = TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {\n <TNewMethod extends Method = TMethod>(options?: {\n method?: TNewMethod\n }): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator\n >\n}\n\nexport type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares> = <\n TInputValidator,\n>(\n inputValidator: ConstrainValidator<TRegister, TMethod, TInputValidator>,\n) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>\n extends\n ServerFnWithTypes<TRegister, TMethod, undefined, undefined, undefined>,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined>,\n ServerFnValidator<TRegister, TMethod, undefined>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined> {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n method: TMethod\n middlewares: TMiddlewares\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n fetch?: CustomFetch\n /** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */\n _callSiteFetch?: CustomFetch\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n '~types': undefined!,\n options: {\n inputValidator: options.inputValidator,\n client: async ({ next, sendContext, fetch, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n fetch,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":["res","options","result"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { OnRawStreamCallback } from '@tanstack/router-core';
|
|
|
5
5
|
export { createIsomorphicFn, createServerOnlyFn, createClientOnlyFn, type IsomorphicFn, type ServerOnlyFn, type ClientOnlyFn, type IsomorphicFnBase, } from '@tanstack/start-fn-stubs';
|
|
6
6
|
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
|
-
export type { CompiledFetcherFnOptions, CompiledFetcherFn, Fetcher, RscStream, FetcherBaseOptions, ServerFn, ServerFnCtx, MiddlewareFn, ServerFnMiddlewareOptions, ServerFnMiddlewareResult, ServerFnBuilder, ServerFnBaseOptions, NextFn, Method, OptionalFetcher, RequiredFetcher, } from './createServerFn.js';
|
|
8
|
+
export type { CompiledFetcherFnOptions, CompiledFetcherFn, CustomFetch, Fetcher, RscStream, FetcherBaseOptions, ServerFn, ServerFnCtx, MiddlewareFn, ServerFnMiddlewareOptions, ServerFnMiddlewareResult, ServerFnBuilder, ServerFnBaseOptions, NextFn, Method, OptionalFetcher, RequiredFetcher, } from './createServerFn.js';
|
|
9
9
|
export { execValidator, flattenMiddlewares, executeMiddleware, } from './createServerFn.js';
|
|
10
10
|
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
11
|
export type { FrameType as FrameTypeValue, ClientFnMeta, ServerFnMeta, } from './constants.js';
|
package/package.json
CHANGED
|
@@ -56,6 +56,10 @@ export async function serverFnFetcher(
|
|
|
56
56
|
const first = _first as FunctionMiddlewareClientFnOptions<any, any, any> & {
|
|
57
57
|
headers?: HeadersInit
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
// Use custom fetch if provided, otherwise fall back to the passed handler (global fetch)
|
|
61
|
+
const fetchImpl = first.fetch ?? handler
|
|
62
|
+
|
|
59
63
|
const type = first.data instanceof FormData ? 'formData' : 'payload'
|
|
60
64
|
|
|
61
65
|
// Arrange the headers
|
|
@@ -97,7 +101,7 @@ export async function serverFnFetcher(
|
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
return await getResponse(async () =>
|
|
100
|
-
|
|
104
|
+
fetchImpl(url, {
|
|
101
105
|
method: first.method,
|
|
102
106
|
headers,
|
|
103
107
|
signal: first.signal,
|
package/src/createMiddleware.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { StartInstanceOptions } from './createStart'
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AnyServerFn,
|
|
4
|
+
ConstrainValidator,
|
|
5
|
+
CustomFetch,
|
|
6
|
+
Method,
|
|
7
|
+
} from './createServerFn'
|
|
3
8
|
import type { ClientFnMeta, ServerFnMeta } from './constants'
|
|
4
9
|
import type {
|
|
5
10
|
AnyContext,
|
|
@@ -405,6 +410,7 @@ export type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <
|
|
|
405
410
|
context?: TNewClientContext
|
|
406
411
|
sendContext?: ValidateSerializableInput<TRegister, TSendContext>
|
|
407
412
|
headers?: HeadersInit
|
|
413
|
+
fetch?: CustomFetch
|
|
408
414
|
}) => Promise<
|
|
409
415
|
FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>
|
|
410
416
|
>
|
|
@@ -612,6 +618,8 @@ export interface FunctionMiddlewareClientFnOptions<
|
|
|
612
618
|
signal: AbortSignal
|
|
613
619
|
serverFnMeta: ClientFnMeta
|
|
614
620
|
next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>
|
|
621
|
+
filename: string
|
|
622
|
+
fetch?: CustomFetch
|
|
615
623
|
}
|
|
616
624
|
|
|
617
625
|
export type FunctionMiddlewareClientFnResult<
|
|
@@ -637,6 +645,7 @@ export type FunctionClientResultWithContext<
|
|
|
637
645
|
context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>
|
|
638
646
|
sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>
|
|
639
647
|
headers: HeadersInit
|
|
648
|
+
fetch?: CustomFetch
|
|
640
649
|
}
|
|
641
650
|
|
|
642
651
|
export interface FunctionMiddlewareAfterClient<
|
package/src/createServerFn.ts
CHANGED
|
@@ -123,6 +123,7 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
|
|
|
123
123
|
data: opts?.data as any,
|
|
124
124
|
headers: opts?.headers,
|
|
125
125
|
signal: opts?.signal,
|
|
126
|
+
fetch: opts?.fetch,
|
|
126
127
|
context: createNullProtoObject(),
|
|
127
128
|
})
|
|
128
129
|
|
|
@@ -257,6 +258,8 @@ export async function executeMiddleware(
|
|
|
257
258
|
context: safeObjectMerge(ctx.context, userCtx.context),
|
|
258
259
|
sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),
|
|
259
260
|
headers: mergeHeaders(ctx.headers, userCtx.headers),
|
|
261
|
+
_callSiteFetch: ctx._callSiteFetch,
|
|
262
|
+
fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,
|
|
260
263
|
result:
|
|
261
264
|
userCtx.result !== undefined
|
|
262
265
|
? userCtx.result
|
|
@@ -321,6 +324,7 @@ export async function executeMiddleware(
|
|
|
321
324
|
headers: opts.headers || {},
|
|
322
325
|
sendContext: opts.sendContext || {},
|
|
323
326
|
context: opts.context || createNullProtoObject(),
|
|
327
|
+
_callSiteFetch: opts.fetch,
|
|
324
328
|
})
|
|
325
329
|
}
|
|
326
330
|
|
|
@@ -329,6 +333,7 @@ export type CompiledFetcherFnOptions = {
|
|
|
329
333
|
data: unknown
|
|
330
334
|
headers?: HeadersInit
|
|
331
335
|
signal?: AbortSignal
|
|
336
|
+
fetch?: CustomFetch
|
|
332
337
|
context?: any
|
|
333
338
|
}
|
|
334
339
|
|
|
@@ -369,9 +374,12 @@ export interface RequiredFetcher<
|
|
|
369
374
|
): Promise<Awaited<TResponse>>
|
|
370
375
|
}
|
|
371
376
|
|
|
377
|
+
export type CustomFetch = typeof globalThis.fetch
|
|
378
|
+
|
|
372
379
|
export type FetcherBaseOptions = {
|
|
373
380
|
headers?: HeadersInit
|
|
374
381
|
signal?: AbortSignal
|
|
382
|
+
fetch?: CustomFetch
|
|
375
383
|
}
|
|
376
384
|
|
|
377
385
|
export interface OptionalFetcherDataOptions<
|
|
@@ -712,6 +720,9 @@ export type ServerFnMiddlewareOptions = {
|
|
|
712
720
|
sendContext?: any
|
|
713
721
|
context?: any
|
|
714
722
|
serverFnMeta: ClientFnMeta
|
|
723
|
+
fetch?: CustomFetch
|
|
724
|
+
/** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */
|
|
725
|
+
_callSiteFetch?: CustomFetch
|
|
715
726
|
}
|
|
716
727
|
|
|
717
728
|
export type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {
|
|
@@ -762,11 +773,12 @@ function serverFnBaseToMiddleware(
|
|
|
762
773
|
'~types': undefined!,
|
|
763
774
|
options: {
|
|
764
775
|
inputValidator: options.inputValidator,
|
|
765
|
-
client: async ({ next, sendContext, ...ctx }) => {
|
|
776
|
+
client: async ({ next, sendContext, fetch, ...ctx }) => {
|
|
766
777
|
const payload = {
|
|
767
778
|
...ctx,
|
|
768
779
|
// switch the sendContext over to context
|
|
769
780
|
context: sendContext,
|
|
781
|
+
fetch,
|
|
770
782
|
} as any
|
|
771
783
|
|
|
772
784
|
// Execute the extracted function
|
package/src/index.tsx
CHANGED
|
@@ -10,7 +10,11 @@ import type {
|
|
|
10
10
|
ValidateSerializableInput,
|
|
11
11
|
Validator,
|
|
12
12
|
} from '@tanstack/router-core'
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
ConstrainValidator,
|
|
15
|
+
CustomFetch,
|
|
16
|
+
ServerFnReturnType,
|
|
17
|
+
} from '../createServerFn'
|
|
14
18
|
|
|
15
19
|
test('createServerFn without middleware', () => {
|
|
16
20
|
expectTypeOf(createServerFn()).toHaveProperty('handler')
|
|
@@ -55,6 +59,7 @@ test('createServerFn with validator function', () => {
|
|
|
55
59
|
data: { input: string }
|
|
56
60
|
headers?: HeadersInit
|
|
57
61
|
signal?: AbortSignal
|
|
62
|
+
fetch?: CustomFetch
|
|
58
63
|
}>()
|
|
59
64
|
|
|
60
65
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -83,6 +88,7 @@ test('createServerFn with async validator function', () => {
|
|
|
83
88
|
data: string
|
|
84
89
|
headers?: HeadersInit
|
|
85
90
|
signal?: AbortSignal
|
|
91
|
+
fetch?: CustomFetch
|
|
86
92
|
}>()
|
|
87
93
|
|
|
88
94
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -113,6 +119,7 @@ test('createServerFn with validator with parse method', () => {
|
|
|
113
119
|
data: string
|
|
114
120
|
headers?: HeadersInit
|
|
115
121
|
signal?: AbortSignal
|
|
122
|
+
fetch?: CustomFetch
|
|
116
123
|
}>()
|
|
117
124
|
|
|
118
125
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -143,6 +150,7 @@ test('createServerFn with async validator with parse method', () => {
|
|
|
143
150
|
data: string
|
|
144
151
|
headers?: HeadersInit
|
|
145
152
|
signal?: AbortSignal
|
|
153
|
+
fetch?: CustomFetch
|
|
146
154
|
}>()
|
|
147
155
|
|
|
148
156
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -190,6 +198,7 @@ test('createServerFn with standard validator', () => {
|
|
|
190
198
|
data: string
|
|
191
199
|
headers?: HeadersInit
|
|
192
200
|
signal?: AbortSignal
|
|
201
|
+
fetch?: CustomFetch
|
|
193
202
|
}>()
|
|
194
203
|
|
|
195
204
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -238,6 +247,7 @@ test('createServerFn with async standard validator', () => {
|
|
|
238
247
|
data: string
|
|
239
248
|
headers?: HeadersInit
|
|
240
249
|
signal?: AbortSignal
|
|
250
|
+
fetch?: CustomFetch
|
|
241
251
|
}>()
|
|
242
252
|
|
|
243
253
|
expectTypeOf<ReturnType<typeof fn>>().resolves.toEqualTypeOf<void>()
|
|
@@ -352,6 +362,7 @@ describe('createServerFn with middleware and validator', () => {
|
|
|
352
362
|
}
|
|
353
363
|
headers?: HeadersInit
|
|
354
364
|
signal?: AbortSignal
|
|
365
|
+
fetch?: CustomFetch
|
|
355
366
|
}>()
|
|
356
367
|
|
|
357
368
|
expectTypeOf(fn).returns.resolves.toEqualTypeOf<'some-data'>()
|
|
@@ -459,6 +470,7 @@ test('createServerFn where validator is optional if object is optional', () => {
|
|
|
459
470
|
data?: 'c' | undefined
|
|
460
471
|
headers?: HeadersInit
|
|
461
472
|
signal?: AbortSignal
|
|
473
|
+
fetch?: CustomFetch
|
|
462
474
|
}
|
|
463
475
|
| undefined
|
|
464
476
|
>()
|
|
@@ -482,6 +494,7 @@ test('createServerFn where data is optional if there is no validator', () => {
|
|
|
482
494
|
data?: undefined
|
|
483
495
|
headers?: HeadersInit
|
|
484
496
|
signal?: AbortSignal
|
|
497
|
+
fetch?: CustomFetch
|
|
485
498
|
}
|
|
486
499
|
| undefined
|
|
487
500
|
>()
|
|
@@ -624,6 +637,7 @@ test('createServerFn validator infers unknown for default input type', () => {
|
|
|
624
637
|
data?: unknown | undefined
|
|
625
638
|
headers?: HeadersInit
|
|
626
639
|
signal?: AbortSignal
|
|
640
|
+
fetch?: CustomFetch
|
|
627
641
|
}
|
|
628
642
|
| undefined
|
|
629
643
|
>()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectTypeOf, test } from 'vitest'
|
|
2
2
|
import { createMiddleware } from '../createMiddleware'
|
|
3
3
|
import type { RequestServerNextFn } from '../createMiddleware'
|
|
4
|
-
import type { ConstrainValidator } from '../createServerFn'
|
|
4
|
+
import type { ConstrainValidator, CustomFetch } from '../createServerFn'
|
|
5
5
|
import type { Register } from '@tanstack/router-core'
|
|
6
6
|
import type { ServerFnMeta } from '../constants'
|
|
7
7
|
|
|
@@ -156,6 +156,7 @@ test('createMiddleware merges client context and sends to the server', () => {
|
|
|
156
156
|
context: { a: boolean }
|
|
157
157
|
sendContext: undefined
|
|
158
158
|
headers: HeadersInit
|
|
159
|
+
fetch?: CustomFetch
|
|
159
160
|
}>()
|
|
160
161
|
|
|
161
162
|
return result
|
|
@@ -173,6 +174,7 @@ test('createMiddleware merges client context and sends to the server', () => {
|
|
|
173
174
|
context: { b: string }
|
|
174
175
|
sendContext: undefined
|
|
175
176
|
headers: HeadersInit
|
|
177
|
+
fetch?: CustomFetch
|
|
176
178
|
}>()
|
|
177
179
|
|
|
178
180
|
return result
|
|
@@ -191,6 +193,7 @@ test('createMiddleware merges client context and sends to the server', () => {
|
|
|
191
193
|
context: { a: boolean; b: string; c: number }
|
|
192
194
|
sendContext: undefined
|
|
193
195
|
headers: HeadersInit
|
|
196
|
+
fetch?: CustomFetch
|
|
194
197
|
}>()
|
|
195
198
|
|
|
196
199
|
return result
|
|
@@ -214,6 +217,7 @@ test('createMiddleware merges client context and sends to the server', () => {
|
|
|
214
217
|
context: { a: boolean; b: string; c: number }
|
|
215
218
|
sendContext: { a: boolean; b: string; c: number; d: 5 }
|
|
216
219
|
headers: HeadersInit
|
|
220
|
+
fetch?: CustomFetch
|
|
217
221
|
}>()
|
|
218
222
|
|
|
219
223
|
return result
|
|
@@ -302,6 +306,7 @@ test('createMiddleware merges server context and client context, sends server co
|
|
|
302
306
|
context: { fromClient1: string }
|
|
303
307
|
sendContext: undefined
|
|
304
308
|
headers: HeadersInit
|
|
309
|
+
fetch?: CustomFetch
|
|
305
310
|
}>()
|
|
306
311
|
|
|
307
312
|
return result
|
|
@@ -341,6 +346,7 @@ test('createMiddleware merges server context and client context, sends server co
|
|
|
341
346
|
context: { fromClient2: string }
|
|
342
347
|
sendContext: undefined
|
|
343
348
|
headers: HeadersInit
|
|
349
|
+
fetch?: CustomFetch
|
|
344
350
|
}>()
|
|
345
351
|
|
|
346
352
|
return result
|
|
@@ -388,6 +394,7 @@ test('createMiddleware merges server context and client context, sends server co
|
|
|
388
394
|
}
|
|
389
395
|
sendContext: undefined
|
|
390
396
|
headers: HeadersInit
|
|
397
|
+
fetch?: CustomFetch
|
|
391
398
|
}>()
|
|
392
399
|
|
|
393
400
|
return result
|
|
@@ -445,6 +452,7 @@ test('createMiddleware merges server context and client context, sends server co
|
|
|
445
452
|
}
|
|
446
453
|
sendContext: { toServer1: 'toServer1' }
|
|
447
454
|
headers: HeadersInit
|
|
455
|
+
fetch?: CustomFetch
|
|
448
456
|
}>()
|
|
449
457
|
|
|
450
458
|
return result
|
|
@@ -512,6 +520,7 @@ test('createMiddleware merges server context and client context, sends server co
|
|
|
512
520
|
}
|
|
513
521
|
sendContext: { toServer1: 'toServer1'; toServer2: 'toServer2' }
|
|
514
522
|
headers: HeadersInit
|
|
523
|
+
fetch?: CustomFetch
|
|
515
524
|
}>()
|
|
516
525
|
|
|
517
526
|
return result
|