@tanstack/start-client-core 1.132.26 → 1.132.29

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.
@@ -2,7 +2,7 @@ import { isPlainObject, encode, parseRedirect, isNotFound } from "@tanstack/rout
2
2
  import { fromCrossJSON, toJSONAsync } from "seroval";
3
3
  import invariant from "tiny-invariant";
4
4
  import { getDefaultSerovalPlugins } from "../getDefaultSerovalPlugins.js";
5
- import { X_TSS_SERIALIZED, TSS_FORMDATA_CONTEXT } from "../constants.js";
5
+ import { X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, TSS_FORMDATA_CONTEXT } from "../constants.js";
6
6
  let serovalPlugins = null;
7
7
  async function serverFnFetcher(url, args, handler) {
8
8
  if (!serovalPlugins) {
@@ -100,6 +100,9 @@ async function getResponse(fn) {
100
100
  throw error;
101
101
  }
102
102
  })();
103
+ if (response.headers.get(X_TSS_RAW_RESPONSE) === "true") {
104
+ return response;
105
+ }
103
106
  const contentType = response.headers.get("content-type");
104
107
  invariant(contentType, "expected content-type header to be set");
105
108
  const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED);
@@ -1 +1 @@
1
- {"version":3,"file":"serverFnFetcher.js","sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n encode,\n isNotFound,\n isPlainObject,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport { TSS_FORMDATA_CONTEXT, X_TSS_SERIALIZED } from '../constants'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\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 // If createServerFn was used to wrap the fetcher,\n // We need to handle the arguments differently\n if (isPlainObject(_first) && _first.method) {\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 = new Headers({\n 'x-tsr-redirect': 'manual',\n ...(type === 'payload'\n ? {\n 'content-type': 'application/json',\n accept: 'application/x-ndjson, application/json',\n }\n : {}),\n ...(first.headers instanceof Headers\n ? Object.fromEntries(first.headers.entries())\n : first.headers),\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 encodedPayload = encode({\n payload: await serializePayload(first),\n })\n\n if (encodedPayload) {\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n if (url.includes('?')) {\n url += `&createServerFn`\n } else {\n url += `?createServerFn`\n }\n\n return await getResponse(async () =>\n handler(url, {\n method: first.method,\n headers,\n signal: first.signal,\n ...(await getFetcherRequestOptions(first)),\n }),\n )\n }\n\n // If not a custom fetcher, it was probably\n // a `use server` function, so just proxy the arguments\n // through as a POST request\n return await getResponse(() =>\n handler(url, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(args),\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n) {\n const payloadToSerialize: any = {}\n if (opts.data) {\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && Object.keys(opts.context).length > 0) {\n payloadToSerialize['context'] = opts.context\n }\n\n return serialize(payloadToSerialize)\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetcherRequestOptions(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n) {\n if (opts.method === 'POST') {\n if (opts.data instanceof FormData) {\n opts.data.set(TSS_FORMDATA_CONTEXT, await serialize(opts.context))\n return {\n body: opts.data,\n }\n }\n\n return {\n body: await serializePayload(opts),\n }\n }\n\n return {}\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 const response = await (async () => {\n try {\n return await fn()\n } catch (error) {\n if (error instanceof Response) {\n return error\n }\n\n throw error\n }\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 // If the response is not ok, throw an error\n if (!response.ok) {\n if (serializedByStart && contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n throw result\n }\n\n throw new Error(await response.text())\n }\n\n if (serializedByStart) {\n let result\n 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 (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n return result\n }\n\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 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"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serverFnFetcher.js","sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n encode,\n isNotFound,\n isPlainObject,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport {\n TSS_FORMDATA_CONTEXT,\n X_TSS_RAW_RESPONSE,\n X_TSS_SERIALIZED,\n} from '../constants'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\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 // If createServerFn was used to wrap the fetcher,\n // We need to handle the arguments differently\n if (isPlainObject(_first) && _first.method) {\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 = new Headers({\n 'x-tsr-redirect': 'manual',\n ...(type === 'payload'\n ? {\n 'content-type': 'application/json',\n accept: 'application/x-ndjson, application/json',\n }\n : {}),\n ...(first.headers instanceof Headers\n ? Object.fromEntries(first.headers.entries())\n : first.headers),\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 encodedPayload = encode({\n payload: await serializePayload(first),\n })\n\n if (encodedPayload) {\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n if (url.includes('?')) {\n url += `&createServerFn`\n } else {\n url += `?createServerFn`\n }\n\n return await getResponse(async () =>\n handler(url, {\n method: first.method,\n headers,\n signal: first.signal,\n ...(await getFetcherRequestOptions(first)),\n }),\n )\n }\n\n // If not a custom fetcher, it was probably\n // a `use server` function, so just proxy the arguments\n // through as a POST request\n return await getResponse(() =>\n handler(url, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(args),\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n) {\n const payloadToSerialize: any = {}\n if (opts.data) {\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && Object.keys(opts.context).length > 0) {\n payloadToSerialize['context'] = opts.context\n }\n\n return serialize(payloadToSerialize)\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetcherRequestOptions(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n) {\n if (opts.method === 'POST') {\n if (opts.data instanceof FormData) {\n opts.data.set(TSS_FORMDATA_CONTEXT, await serialize(opts.context))\n return {\n body: opts.data,\n }\n }\n\n return {\n body: await serializePayload(opts),\n }\n }\n\n return {}\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 const response = await (async () => {\n try {\n return await fn()\n } catch (error) {\n if (error instanceof Response) {\n return error\n }\n\n throw error\n }\n })()\n\n if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {\n return response\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 // If the response is not ok, throw an error\n if (!response.ok) {\n if (serializedByStart && contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n throw result\n }\n\n throw new Error(await response.text())\n }\n\n if (serializedByStart) {\n let result\n 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 (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n return result\n }\n\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 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"],"names":[],"mappings":"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"}
@@ -2,4 +2,5 @@ export declare const TSS_FORMDATA_CONTEXT = "__TSS_CONTEXT";
2
2
  export declare const TSS_SERVER_FUNCTION: unique symbol;
3
3
  export declare const TSS_SERVER_FUNCTION_FACTORY: unique symbol;
4
4
  export declare const X_TSS_SERIALIZED = "x-tss-serialized";
5
+ export declare const X_TSS_RAW_RESPONSE = "x-tss-raw";
5
6
  export {};
@@ -4,10 +4,12 @@ const TSS_SERVER_FUNCTION_FACTORY = Symbol.for(
4
4
  "TSS_SERVER_FUNCTION_FACTORY"
5
5
  );
6
6
  const X_TSS_SERIALIZED = "x-tss-serialized";
7
+ const X_TSS_RAW_RESPONSE = "x-tss-raw";
7
8
  export {
8
9
  TSS_FORMDATA_CONTEXT,
9
10
  TSS_SERVER_FUNCTION,
10
11
  TSS_SERVER_FUNCTION_FACTORY,
12
+ X_TSS_RAW_RESPONSE,
11
13
  X_TSS_SERIALIZED
12
14
  };
13
15
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../../src/constants.ts"],"sourcesContent":["export const TSS_FORMDATA_CONTEXT = '__TSS_CONTEXT'\nexport const TSS_SERVER_FUNCTION = Symbol.for('TSS_SERVER_FUNCTION')\nexport const TSS_SERVER_FUNCTION_FACTORY = Symbol.for(\n 'TSS_SERVER_FUNCTION_FACTORY',\n)\n\nexport const X_TSS_SERIALIZED = 'x-tss-serialized'\nexport {}\n"],"names":[],"mappings":"AAAO,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB,OAAO,IAAI,qBAAqB;AAC5D,MAAM,8BAA8B,OAAO;AAAA,EAChD;AACF;AAEO,MAAM,mBAAmB;"}
1
+ {"version":3,"file":"constants.js","sources":["../../src/constants.ts"],"sourcesContent":["export const TSS_FORMDATA_CONTEXT = '__TSS_CONTEXT'\nexport const TSS_SERVER_FUNCTION = Symbol.for('TSS_SERVER_FUNCTION')\nexport const TSS_SERVER_FUNCTION_FACTORY = Symbol.for(\n 'TSS_SERVER_FUNCTION_FACTORY',\n)\n\nexport const X_TSS_SERIALIZED = 'x-tss-serialized'\nexport const X_TSS_RAW_RESPONSE = 'x-tss-raw'\nexport {}\n"],"names":[],"mappings":"AAAO,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB,OAAO,IAAI,qBAAqB;AAC5D,MAAM,8BAA8B,OAAO;AAAA,EAChD;AACF;AAEO,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;"}
@@ -1,5 +1,5 @@
1
1
  import { TSS_SERVER_FUNCTION_FACTORY, TSS_SERVER_FUNCTION } from './constants.js';
2
- import { AnyValidator, Constrain, Expand, Register, RegisteredSerializableInput, ResolveValidatorInput, ValidateSerializable, ValidateSerializableInput, ValidateSerializableInputResult, Validator } from '@tanstack/router-core';
2
+ import { AnyValidator, Constrain, Expand, Register, RegisteredSerializableInput, ResolveValidatorInput, ValidateSerializable, ValidateSerializableInput, Validator } from '@tanstack/router-core';
3
3
  import { JsonResponse } from '@tanstack/router-core/ssr/client';
4
4
  import { AnyFunctionMiddleware, AnyRequestMiddleware, AssignAllServerFnContext, IntersectAllValidatorInputs, IntersectAllValidatorOutputs } from './createMiddleware.js';
5
5
  export type CreateServerFn<TRegister> = <TMethod extends Method, TResponse = unknown, TMiddlewares = undefined, TInputValidator = undefined>(options?: {
@@ -14,7 +14,7 @@ export type CompiledFetcherFnOptions = {
14
14
  signal?: AbortSignal;
15
15
  context?: any;
16
16
  };
17
- export type Fetcher<TRegister, TMiddlewares, TInputValidator, TResponse> = undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator> ? OptionalFetcher<TRegister, TMiddlewares, TInputValidator, TResponse> : RequiredFetcher<TRegister, TMiddlewares, TInputValidator, TResponse>;
17
+ export type Fetcher<TMiddlewares, TInputValidator, TResponse> = undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator> ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse> : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>;
18
18
  export interface FetcherBase {
19
19
  [TSS_SERVER_FUNCTION]: true;
20
20
  url: string;
@@ -26,11 +26,11 @@ export interface FetcherBase {
26
26
  signal: AbortSignal;
27
27
  }) => Promise<unknown>;
28
28
  }
29
- export interface OptionalFetcher<TRegister, TMiddlewares, TInputValidator, TResponse> extends FetcherBase {
30
- (options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>): Promise<FetcherData<TRegister, TResponse>>;
29
+ export interface OptionalFetcher<TMiddlewares, TInputValidator, TResponse> extends FetcherBase {
30
+ (options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>): Promise<FetcherData<TResponse>>;
31
31
  }
32
- export interface RequiredFetcher<TRegister, TMiddlewares, TInputValidator, TResponse> extends FetcherBase {
33
- (opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>): Promise<FetcherData<TRegister, TResponse>>;
32
+ export interface RequiredFetcher<TMiddlewares, TInputValidator, TResponse> extends FetcherBase {
33
+ (opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>): Promise<FetcherData<TResponse>>;
34
34
  }
35
35
  export type FetcherBaseOptions = {
36
36
  headers?: HeadersInit;
@@ -42,12 +42,12 @@ export interface OptionalFetcherDataOptions<TMiddlewares, TInputValidator> exten
42
42
  export interface RequiredFetcherDataOptions<TMiddlewares, TInputValidator> extends FetcherBaseOptions {
43
43
  data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>;
44
44
  }
45
- export type FetcherData<TRegister, TResponse> = TResponse extends Response ? Response : TResponse extends JsonResponse<any> ? ValidateSerializableInputResult<TRegister, ReturnType<TResponse['json']>> : ValidateSerializableInputResult<TRegister, TResponse>;
46
45
  export type RscStream<T> = {
47
46
  __cacheState: T;
48
47
  };
49
48
  export type Method = 'GET' | 'POST';
50
- export type ServerFnReturnType<TRegister, TResponse> = Response | Promise<ValidateSerializableInput<TRegister, TResponse>> | ValidateSerializableInput<TRegister, TResponse>;
49
+ export type FetcherData<TResponse> = Awaited<TResponse> extends Response ? Awaited<TResponse> : Awaited<TResponse> extends JsonResponse<any> ? ReturnType<Awaited<TResponse>['json']> : Awaited<TResponse>;
50
+ export type ServerFnReturnType<TRegister, TResponse> = Awaited<TResponse> extends Response ? TResponse : ValidateSerializableInput<TRegister, TResponse>;
51
51
  export type ServerFn<TRegister, TMethod, TMiddlewares, TInputValidator, TResponse> = (ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>) => ServerFnReturnType<TRegister, TResponse>;
52
52
  export interface ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator> {
53
53
  method: TMethod;
@@ -88,7 +88,7 @@ export interface ServerFnAfterValidator<TRegister, TMethod extends Method, TMidd
88
88
  export interface ServerFnAfterTyper<TRegister, TMethod extends Method, TMiddlewares, TInputValidator> extends ServerFnWithTypes<TRegister, TMethod, TMiddlewares, TInputValidator, undefined>, ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {
89
89
  }
90
90
  export interface ServerFnHandler<TRegister, TMethod extends Method, TMiddlewares, TInputValidator> {
91
- handler: <TNewResponse>(fn?: ServerFn<TRegister, TMethod, TMiddlewares, TInputValidator, TNewResponse>) => Fetcher<TRegister, TMiddlewares, TInputValidator, TNewResponse>;
91
+ handler: <TNewResponse>(fn?: ServerFn<TRegister, TMethod, TMiddlewares, TInputValidator, TNewResponse>) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>;
92
92
  }
93
93
  export interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'> extends ServerFnWithTypes<TRegister, TMethod, undefined, undefined, undefined>, ServerFnMiddleware<TRegister, TMethod, undefined, undefined>, ServerFnValidator<TRegister, TMethod, undefined>, ServerFnHandler<TRegister, TMethod, undefined, undefined> {
94
94
  options: ServerFnBaseOptions<TRegister, TMethod, unknown, undefined, undefined>;
@@ -95,7 +95,7 @@ const createServerFn = (options, __opts) => {
95
95
  return Object.assign(fun, res);
96
96
  };
97
97
  async function executeMiddleware(middlewares, env, opts) {
98
- const globalMiddlewares = getStartOptions().functionMiddleware || [];
98
+ const globalMiddlewares = getStartOptions()?.functionMiddleware || [];
99
99
  const flattenedMiddlewares = flattenMiddlewares([
100
100
  ...globalMiddlewares,
101
101
  ...middlewares
@@ -1 +1 @@
1
- {"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { isNotFound, isRedirect } from '@tanstack/router-core'\nimport { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getServerContextAfterGlobalMiddlewares } from './getServerContextAfterGlobalMiddlewares'\nimport { getStartOptions } from './getStartOptions'\nimport type { TSS_SERVER_FUNCTION } from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n ValidateSerializableInputResult,\n Validator,\n} from '@tanstack/router-core'\nimport type { JsonResponse } from '@tanstack/router-core/ssr/client'\nimport type {\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 return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n }).then((d) => {\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const serverContextAfterGlobalMiddlewares =\n getServerContextAfterGlobalMiddlewares()\n const ctx = {\n ...extractedFn,\n ...opts,\n context: {\n ...serverContextAfterGlobalMiddlewares,\n ...opts.context,\n },\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n return {\n ...res,\n options: {\n ...res.options,\n ...options,\n },\n }\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 const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n '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 const middlewareFn = (\n env === 'client' && 'client' in nextMiddleware.options\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n}\n\nexport type Fetcher<TRegister, TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TRegister, TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TRegister, 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 TRegister,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<FetcherData<TRegister, TResponse>>\n}\n\nexport interface RequiredFetcher<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<FetcherData<TRegister, TResponse>>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TInputValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, TInputValidator>\n extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type FetcherData<TRegister, TResponse> = TResponse extends Response\n ? Response\n : TResponse extends JsonResponse<any>\n ? ValidateSerializableInputResult<TRegister, ReturnType<TResponse['json']>>\n : ValidateSerializableInputResult<TRegister, TResponse>\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n | Response\n | Promise<ValidateSerializableInput<TRegister, 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 method: TMethod\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\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 functionId: string\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> extends 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> extends 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> extends 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<TRegister, TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>\n extends ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined\n >,\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 middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n): Array<AnyFunctionMiddleware | AnyRequestMiddleware> {\n const seen = new Set<AnyFunctionMiddleware | AnyRequestMiddleware>()\n const flattened: Array<AnyFunctionMiddleware | AnyRequestMiddleware> = []\n\n const recurse = (\n middleware: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n ) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\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"],"mappings":"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"}
1
+ {"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { isNotFound, isRedirect } from '@tanstack/router-core'\nimport { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getServerContextAfterGlobalMiddlewares } from './getServerContextAfterGlobalMiddlewares'\nimport { getStartOptions } from './getStartOptions'\nimport type { TSS_SERVER_FUNCTION } 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 { JsonResponse } from '@tanstack/router-core/ssr/client'\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 return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n }).then((d) => {\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const serverContextAfterGlobalMiddlewares =\n getServerContextAfterGlobalMiddlewares()\n const ctx = {\n ...extractedFn,\n ...opts,\n context: {\n ...serverContextAfterGlobalMiddlewares,\n ...opts.context,\n },\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n return {\n ...res,\n options: {\n ...res.options,\n ...options,\n },\n }\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 const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n '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 const middlewareFn = (\n env === 'client' && 'client' in nextMiddleware.options\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n 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<TMiddlewares, TInputValidator, TResponse>\n extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<FetcherData<TResponse>>\n}\n\nexport interface RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<FetcherData<TResponse>>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TInputValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, 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 FetcherData<TResponse> =\n Awaited<TResponse> extends Response\n ? Awaited<TResponse>\n : Awaited<TResponse> extends JsonResponse<any>\n ? ReturnType<Awaited<TResponse>['json']>\n : Awaited<TResponse>\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n Awaited<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 method: TMethod\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\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 functionId: string\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> extends 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> extends 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> extends 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 ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined\n >,\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 middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n): Array<AnyFunctionMiddleware | AnyRequestMiddleware> {\n const seen = new Set<AnyFunctionMiddleware | AnyRequestMiddleware>()\n const flattened: Array<AnyFunctionMiddleware | AnyRequestMiddleware> = []\n\n const recurse = (\n middleware: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n ) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\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"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { defaultSerovalPlugins, makeSerovalPlugin } from "@tanstack/router-core"
2
2
  import { getStartOptions } from "./getStartOptions.js";
3
3
  function getDefaultSerovalPlugins() {
4
4
  const start = getStartOptions();
5
- const adapters = start.serializationAdapters;
5
+ const adapters = start?.serializationAdapters;
6
6
  return [
7
7
  ...adapters?.map(makeSerovalPlugin) ?? [],
8
8
  ...defaultSerovalPlugins
@@ -1 +1 @@
1
- {"version":3,"file":"getDefaultSerovalPlugins.js","sources":["../../src/getDefaultSerovalPlugins.ts"],"sourcesContent":["import {\n makeSerovalPlugin,\n defaultSerovalPlugins as routerDefaultSerovalPlugins,\n} from '@tanstack/router-core'\nimport { getStartOptions } from './getStartOptions'\nimport type { AnySerializationAdapter } from '@tanstack/router-core'\n\nexport function getDefaultSerovalPlugins() {\n const start = getStartOptions()\n const adapters = start.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n return [\n ...(adapters?.map(makeSerovalPlugin) ?? []),\n ...routerDefaultSerovalPlugins,\n ]\n}\n"],"names":["routerDefaultSerovalPlugins"],"mappings":";;AAOO,SAAS,2BAA2B;AACzC,QAAM,QAAQ,gBAAA;AACd,QAAM,WAAW,MAAM;AAGvB,SAAO;AAAA,IACL,GAAI,UAAU,IAAI,iBAAiB,KAAK,CAAA;AAAA,IACxC,GAAGA;AAAAA,EAAA;AAEP;"}
1
+ {"version":3,"file":"getDefaultSerovalPlugins.js","sources":["../../src/getDefaultSerovalPlugins.ts"],"sourcesContent":["import {\n makeSerovalPlugin,\n defaultSerovalPlugins as routerDefaultSerovalPlugins,\n} from '@tanstack/router-core'\nimport { getStartOptions } from './getStartOptions'\nimport type { AnySerializationAdapter } from '@tanstack/router-core'\n\nexport function getDefaultSerovalPlugins() {\n const start = getStartOptions()\n const adapters = start?.serializationAdapters as\n | Array<AnySerializationAdapter>\n | undefined\n return [\n ...(adapters?.map(makeSerovalPlugin) ?? []),\n ...routerDefaultSerovalPlugins,\n ]\n}\n"],"names":["routerDefaultSerovalPlugins"],"mappings":";;AAOO,SAAS,2BAA2B;AACzC,QAAM,QAAQ,gBAAA;AACd,QAAM,WAAW,OAAO;AAGxB,SAAO;AAAA,IACL,GAAI,UAAU,IAAI,iBAAiB,KAAK,CAAA;AAAA,IACxC,GAAGA;AAAAA,EAAA;AAEP;"}
@@ -1 +1,2 @@
1
- export declare const getStartOptions: import('./createIsomorphicFn.js').IsomorphicFn<[], any, import('./createStart.js').AnyStartInstanceOptions>;
1
+ import { AnyStartInstanceOptions } from './createStart.js';
2
+ export declare const getStartOptions: () => AnyStartInstanceOptions | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"getStartOptions.js","sources":["../../src/getStartOptions.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from './createIsomorphicFn'\n\nexport const getStartOptions = createIsomorphicFn()\n .client(() => window.__TSS_START_OPTIONS__!)\n .server(() => getStartContext().startOptions)\n"],"names":[],"mappings":";;AAGO,MAAM,kBAAkB,qBAC5B,OAAO,MAAM,OAAO,qBAAsB,EAC1C,OAAO,MAAM,gBAAA,EAAkB,YAAY;"}
1
+ {"version":3,"file":"getStartOptions.js","sources":["../../src/getStartOptions.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from './createIsomorphicFn'\nimport type { AnyStartInstanceOptions } from './createStart'\n\nexport const getStartOptions: () => AnyStartInstanceOptions | undefined =\n createIsomorphicFn()\n .client(() => window.__TSS_START_OPTIONS__)\n .server(() => getStartContext().startOptions)\n"],"names":[],"mappings":";;AAIO,MAAM,kBACX,qBACG,OAAO,MAAM,OAAO,qBAAqB,EACzC,OAAO,MAAM,gBAAA,EAAkB,YAAY;"}
@@ -6,7 +6,7 @@ export { createServerFn } from './createServerFn.js';
6
6
  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';
7
7
  export type { CompiledFetcherFnOptions, CompiledFetcherFn, Fetcher, RscStream, FetcherData, FetcherBaseOptions, ServerFn, ServerFnCtx, MiddlewareFn, ServerFnMiddlewareOptions, ServerFnMiddlewareResult, ServerFnBuilder, ServerFnBaseOptions, NextFn, Method, OptionalFetcher, RequiredFetcher, } from './createServerFn.js';
8
8
  export { applyMiddleware, execValidator, flattenMiddlewares, executeMiddleware, } from './createServerFn.js';
9
- export { TSS_FORMDATA_CONTEXT, TSS_SERVER_FUNCTION, X_TSS_SERIALIZED, } from './constants.js';
9
+ export { TSS_FORMDATA_CONTEXT, TSS_SERVER_FUNCTION, X_TSS_SERIALIZED, X_TSS_RAW_RESPONSE, } from './constants.js';
10
10
  export type * from './serverRoute.js';
11
11
  export type * from './startEntry.js';
12
12
  export { createStart } from './createStart.js';
package/dist/esm/index.js CHANGED
@@ -3,7 +3,7 @@ import { createIsomorphicFn } from "./createIsomorphicFn.js";
3
3
  import { createClientOnlyFn, createServerOnlyFn } from "./envOnly.js";
4
4
  import { applyMiddleware, createServerFn, execValidator, executeMiddleware, flattenMiddlewares } from "./createServerFn.js";
5
5
  import { createMiddleware } from "./createMiddleware.js";
6
- import { TSS_FORMDATA_CONTEXT, TSS_SERVER_FUNCTION, X_TSS_SERIALIZED } from "./constants.js";
6
+ import { TSS_FORMDATA_CONTEXT, TSS_SERVER_FUNCTION, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED } from "./constants.js";
7
7
  import { createStart } from "./createStart.js";
8
8
  import { getRouterInstance } from "./getRouterInstance.js";
9
9
  import { getDefaultSerovalPlugins } from "./getDefaultSerovalPlugins.js";
@@ -11,6 +11,7 @@ import { getGlobalStartContext } from "./getGlobalStartContext.js";
11
11
  export {
12
12
  TSS_FORMDATA_CONTEXT,
13
13
  TSS_SERVER_FUNCTION,
14
+ X_TSS_RAW_RESPONSE,
14
15
  X_TSS_SERIALIZED,
15
16
  applyMiddleware,
16
17
  createClientOnlyFn,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/start-client-core",
3
- "version": "1.132.26",
3
+ "version": "1.132.29",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -66,8 +66,8 @@
66
66
  "seroval": "^1.3.2",
67
67
  "tiny-invariant": "^1.3.3",
68
68
  "tiny-warning": "^1.0.3",
69
- "@tanstack/router-core": "1.132.26",
70
- "@tanstack/start-storage-context": "1.132.26"
69
+ "@tanstack/router-core": "1.132.29",
70
+ "@tanstack/start-storage-context": "1.132.29"
71
71
  },
72
72
  "scripts": {}
73
73
  }
@@ -7,7 +7,11 @@ import {
7
7
  import { fromCrossJSON, toJSONAsync } from 'seroval'
8
8
  import invariant from 'tiny-invariant'
9
9
  import { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'
10
- import { TSS_FORMDATA_CONTEXT, X_TSS_SERIALIZED } from '../constants'
10
+ import {
11
+ TSS_FORMDATA_CONTEXT,
12
+ X_TSS_RAW_RESPONSE,
13
+ X_TSS_SERIALIZED,
14
+ } from '../constants'
11
15
  import type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'
12
16
  import type { Plugin as SerovalPlugin } from 'seroval'
13
17
 
@@ -156,6 +160,9 @@ async function getResponse(fn: () => Promise<Response>) {
156
160
  }
157
161
  })()
158
162
 
163
+ if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {
164
+ return response
165
+ }
159
166
  const contentType = response.headers.get('content-type')
160
167
  invariant(contentType, 'expected content-type header to be set')
161
168
  const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED)
package/src/constants.ts CHANGED
@@ -5,4 +5,5 @@ export const TSS_SERVER_FUNCTION_FACTORY = Symbol.for(
5
5
  )
6
6
 
7
7
  export const X_TSS_SERIALIZED = 'x-tss-serialized'
8
+ export const X_TSS_RAW_RESPONSE = 'x-tss-raw'
8
9
  export {}
@@ -14,7 +14,6 @@ import type {
14
14
  ResolveValidatorInput,
15
15
  ValidateSerializable,
16
16
  ValidateSerializableInput,
17
- ValidateSerializableInputResult,
18
17
  Validator,
19
18
  } from '@tanstack/router-core'
20
19
  import type { JsonResponse } from '@tanstack/router-core/ssr/client'
@@ -174,7 +173,7 @@ export async function executeMiddleware(
174
173
  env: 'client' | 'server',
175
174
  opts: ServerFnMiddlewareOptions,
176
175
  ): Promise<ServerFnMiddlewareResult> {
177
- const globalMiddlewares = getStartOptions().functionMiddleware || []
176
+ const globalMiddlewares = getStartOptions()?.functionMiddleware || []
178
177
  const flattenedMiddlewares = flattenMiddlewares([
179
178
  ...globalMiddlewares,
180
179
  ...middlewares,
@@ -243,10 +242,10 @@ export type CompiledFetcherFnOptions = {
243
242
  context?: any
244
243
  }
245
244
 
246
- export type Fetcher<TRegister, TMiddlewares, TInputValidator, TResponse> =
245
+ export type Fetcher<TMiddlewares, TInputValidator, TResponse> =
247
246
  undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>
248
- ? OptionalFetcher<TRegister, TMiddlewares, TInputValidator, TResponse>
249
- : RequiredFetcher<TRegister, TMiddlewares, TInputValidator, TResponse>
247
+ ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>
248
+ : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>
250
249
 
251
250
  export interface FetcherBase {
252
251
  [TSS_SERVER_FUNCTION]: true
@@ -260,26 +259,18 @@ export interface FetcherBase {
260
259
  }) => Promise<unknown>
261
260
  }
262
261
 
263
- export interface OptionalFetcher<
264
- TRegister,
265
- TMiddlewares,
266
- TInputValidator,
267
- TResponse,
268
- > extends FetcherBase {
262
+ export interface OptionalFetcher<TMiddlewares, TInputValidator, TResponse>
263
+ extends FetcherBase {
269
264
  (
270
265
  options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,
271
- ): Promise<FetcherData<TRegister, TResponse>>
266
+ ): Promise<FetcherData<TResponse>>
272
267
  }
273
268
 
274
- export interface RequiredFetcher<
275
- TRegister,
276
- TMiddlewares,
277
- TInputValidator,
278
- TResponse,
279
- > extends FetcherBase {
269
+ export interface RequiredFetcher<TMiddlewares, TInputValidator, TResponse>
270
+ extends FetcherBase {
280
271
  (
281
272
  opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,
282
- ): Promise<FetcherData<TRegister, TResponse>>
273
+ ): Promise<FetcherData<TResponse>>
283
274
  }
284
275
 
285
276
  export type FetcherBaseOptions = {
@@ -297,22 +288,23 @@ export interface RequiredFetcherDataOptions<TMiddlewares, TInputValidator>
297
288
  data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>
298
289
  }
299
290
 
300
- export type FetcherData<TRegister, TResponse> = TResponse extends Response
301
- ? Response
302
- : TResponse extends JsonResponse<any>
303
- ? ValidateSerializableInputResult<TRegister, ReturnType<TResponse['json']>>
304
- : ValidateSerializableInputResult<TRegister, TResponse>
305
-
306
291
  export type RscStream<T> = {
307
292
  __cacheState: T
308
293
  }
309
294
 
310
295
  export type Method = 'GET' | 'POST'
311
296
 
297
+ export type FetcherData<TResponse> =
298
+ Awaited<TResponse> extends Response
299
+ ? Awaited<TResponse>
300
+ : Awaited<TResponse> extends JsonResponse<any>
301
+ ? ReturnType<Awaited<TResponse>['json']>
302
+ : Awaited<TResponse>
303
+
312
304
  export type ServerFnReturnType<TRegister, TResponse> =
313
- | Response
314
- | Promise<ValidateSerializableInput<TRegister, TResponse>>
315
- | ValidateSerializableInput<TRegister, TResponse>
305
+ Awaited<TResponse> extends Response
306
+ ? TResponse
307
+ : ValidateSerializableInput<TRegister, TResponse>
316
308
 
317
309
  export type ServerFn<
318
310
  TRegister,
@@ -521,7 +513,7 @@ export interface ServerFnHandler<
521
513
  TInputValidator,
522
514
  TNewResponse
523
515
  >,
524
- ) => Fetcher<TRegister, TMiddlewares, TInputValidator, TNewResponse>
516
+ ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>
525
517
  }
526
518
 
527
519
  export interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>
@@ -7,7 +7,7 @@ import type { AnySerializationAdapter } from '@tanstack/router-core'
7
7
 
8
8
  export function getDefaultSerovalPlugins() {
9
9
  const start = getStartOptions()
10
- const adapters = start.serializationAdapters as
10
+ const adapters = start?.serializationAdapters as
11
11
  | Array<AnySerializationAdapter>
12
12
  | undefined
13
13
  return [
@@ -1,6 +1,8 @@
1
1
  import { getStartContext } from '@tanstack/start-storage-context'
2
2
  import { createIsomorphicFn } from './createIsomorphicFn'
3
+ import type { AnyStartInstanceOptions } from './createStart'
3
4
 
4
- export const getStartOptions = createIsomorphicFn()
5
- .client(() => window.__TSS_START_OPTIONS__!)
6
- .server(() => getStartContext().startOptions)
5
+ export const getStartOptions: () => AnyStartInstanceOptions | undefined =
6
+ createIsomorphicFn()
7
+ .client(() => window.__TSS_START_OPTIONS__)
8
+ .server(() => getStartContext().startOptions)
package/src/index.tsx CHANGED
@@ -85,6 +85,7 @@ export {
85
85
  TSS_FORMDATA_CONTEXT,
86
86
  TSS_SERVER_FUNCTION,
87
87
  X_TSS_SERIALIZED,
88
+ X_TSS_RAW_RESPONSE,
88
89
  } from './constants'
89
90
 
90
91
  export type * from './serverRoute'
@@ -317,11 +317,7 @@ test('createServerFn returns undefined', () => {
317
317
  test('createServerFn cannot return function', () => {
318
318
  expectTypeOf(createServerFn().handler<{ func: () => 'func' }>)
319
319
  .parameter(0)
320
- .returns.toEqualTypeOf<
321
- | Response
322
- | { func: 'Function is not serializable' }
323
- | Promise<{ func: 'Function is not serializable' }>
324
- >()
320
+ .returns.toEqualTypeOf<{ func: 'Function is not serializable' }>()
325
321
  })
326
322
 
327
323
  test('createServerFn cannot validate function', () => {
@@ -598,3 +594,47 @@ test('createServerFn fetcher itself is serializable', () => {
598
594
  const fn1 = createServerFn().handler(() => ({}))
599
595
  const fn2 = createServerFn().handler(() => fn1)
600
596
  })
597
+
598
+ test('createServerFn returns async Response', () => {
599
+ const serverFn = createServerFn().handler(async () => {
600
+ return new Response(new Blob([JSON.stringify({ a: 1 })]), {
601
+ status: 200,
602
+ headers: {
603
+ 'Content-Type': 'application/json',
604
+ },
605
+ })
606
+ })
607
+
608
+ expectTypeOf(serverFn()).toEqualTypeOf<Promise<Response>>()
609
+ })
610
+
611
+ test('createServerFn returns sync Response', () => {
612
+ const serverFn = createServerFn().handler(() => {
613
+ return new Response(new Blob([JSON.stringify({ a: 1 })]), {
614
+ status: 200,
615
+ headers: {
616
+ 'Content-Type': 'application/json',
617
+ },
618
+ })
619
+ })
620
+
621
+ expectTypeOf(serverFn()).toEqualTypeOf<Promise<Response>>()
622
+ })
623
+
624
+ test('createServerFn returns async array', () => {
625
+ const result: Array<{ a: number }> = [{ a: 1 }]
626
+ const serverFn = createServerFn({ method: 'GET' }).handler(async () => {
627
+ return result
628
+ })
629
+
630
+ expectTypeOf(serverFn()).toEqualTypeOf<Promise<Array<{ a: number }>>>()
631
+ })
632
+
633
+ test('createServerFn returns sync array', () => {
634
+ const result: Array<{ a: number }> = [{ a: 1 }]
635
+ const serverFn = createServerFn({ method: 'GET' }).handler(() => {
636
+ return result
637
+ })
638
+
639
+ expectTypeOf(serverFn()).toEqualTypeOf<Promise<Array<{ a: number }>>>()
640
+ })