@tanstack/start-client-core 1.132.0-alpha.2 → 1.132.0-alpha.3

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.
Files changed (43) hide show
  1. package/dist/esm/constants.d.ts +2 -0
  2. package/dist/esm/constants.js +5 -0
  3. package/dist/esm/constants.js.map +1 -0
  4. package/dist/esm/createClientRpc.d.ts +4 -0
  5. package/dist/esm/createClientRpc.js +24 -0
  6. package/dist/esm/createClientRpc.js.map +1 -0
  7. package/dist/esm/createServerFn.d.ts +0 -7
  8. package/dist/esm/createServerFn.js +2 -28
  9. package/dist/esm/createServerFn.js.map +1 -1
  10. package/dist/esm/getRouterInstance.d.ts +1 -0
  11. package/dist/esm/getRouterInstance.js +7 -0
  12. package/dist/esm/getRouterInstance.js.map +1 -0
  13. package/dist/esm/index.d.ts +5 -3
  14. package/dist/esm/index.js +8 -5
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/serializer/ServerFunctionSerializationAdapter.d.ts +5 -0
  17. package/dist/esm/serializer/ServerFunctionSerializationAdapter.js +12 -0
  18. package/dist/esm/serializer/ServerFunctionSerializationAdapter.js.map +1 -0
  19. package/dist/esm/serializer/getClientSerovalPlugins.d.ts +3 -0
  20. package/dist/esm/serializer/getClientSerovalPlugins.js +13 -0
  21. package/dist/esm/serializer/getClientSerovalPlugins.js.map +1 -0
  22. package/dist/esm/serializer/getDefaultSerovalPlugins.d.ts +3 -0
  23. package/dist/esm/serializer/getDefaultSerovalPlugins.js +19 -0
  24. package/dist/esm/serializer/getDefaultSerovalPlugins.js.map +1 -0
  25. package/dist/esm/serializer.d.ts +0 -7
  26. package/dist/esm/serverFnFetcher.d.ts +1 -0
  27. package/dist/esm/serverFnFetcher.js +217 -0
  28. package/dist/esm/serverFnFetcher.js.map +1 -0
  29. package/package.json +5 -3
  30. package/src/constants.ts +2 -0
  31. package/src/createClientRpc.ts +24 -0
  32. package/src/createServerFn.ts +2 -36
  33. package/src/getRouterInstance.ts +7 -0
  34. package/src/index.tsx +6 -4
  35. package/src/serializer/ServerFunctionSerializationAdapter.ts +10 -0
  36. package/src/serializer/getClientSerovalPlugins.ts +10 -0
  37. package/src/serializer/getDefaultSerovalPlugins.ts +24 -0
  38. package/src/serializer.ts +0 -194
  39. package/src/serverFnFetcher.ts +299 -0
  40. package/dist/esm/serializer.js +0 -162
  41. package/dist/esm/serializer.js.map +0 -1
  42. package/dist/esm/tests/serializer.test.d.ts +0 -1
  43. package/src/tests/serializer.test.tsx +0 -151
@@ -0,0 +1,2 @@
1
+ export declare const TSR_FORMDATA_CONTEXT = "__TSR_CONTEXT";
2
+ export {};
@@ -0,0 +1,5 @@
1
+ const TSR_FORMDATA_CONTEXT = "__TSR_CONTEXT";
2
+ export {
3
+ TSR_FORMDATA_CONTEXT
4
+ };
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sources":["../../src/constants.ts"],"sourcesContent":["export const TSR_FORMDATA_CONTEXT = '__TSR_CONTEXT'\nexport {}\n"],"names":[],"mappings":"AAAO,MAAM,uBAAuB;"}
@@ -0,0 +1,4 @@
1
+ export declare const createClientRpc: (functionId: string) => ((...args: Array<any>) => Promise<any>) & {
2
+ url: string;
3
+ functionId: string;
4
+ };
@@ -0,0 +1,24 @@
1
+ import { serverFnFetcher } from "./serverFnFetcher.js";
2
+ let baseUrl;
3
+ function sanitizeBase(base) {
4
+ return base.replace(/^\/|\/$/g, "");
5
+ }
6
+ const createClientRpc = (functionId) => {
7
+ if (!baseUrl) {
8
+ const sanitizedAppBase = sanitizeBase(process.env.TSS_APP_BASE || "/");
9
+ const sanitizedServerBase = sanitizeBase(process.env.TSS_SERVER_FN_BASE);
10
+ baseUrl = `${sanitizedAppBase ? `/${sanitizedAppBase}` : ""}/${sanitizedServerBase}/`;
11
+ }
12
+ const url = baseUrl + functionId;
13
+ const clientFn = (...args) => {
14
+ return serverFnFetcher(url, args, fetch);
15
+ };
16
+ return Object.assign(clientFn, {
17
+ url,
18
+ functionId
19
+ });
20
+ };
21
+ export {
22
+ createClientRpc
23
+ };
24
+ //# sourceMappingURL=createClientRpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createClientRpc.js","sources":["../../src/createClientRpc.ts"],"sourcesContent":["import { serverFnFetcher } from './serverFnFetcher'\n\nlet baseUrl: string\nfunction sanitizeBase(base: string) {\n return base.replace(/^\\/|\\/$/g, '')\n}\n\nexport const createClientRpc = (functionId: string) => {\n if (!baseUrl) {\n const sanitizedAppBase = sanitizeBase(process.env.TSS_APP_BASE || '/')\n const sanitizedServerBase = sanitizeBase(process.env.TSS_SERVER_FN_BASE!)\n baseUrl = `${sanitizedAppBase ? `/${sanitizedAppBase}` : ''}/${sanitizedServerBase}/`\n }\n const url = baseUrl + functionId\n\n const clientFn = (...args: Array<any>) => {\n return serverFnFetcher(url, args, fetch)\n }\n\n return Object.assign(clientFn, {\n url,\n functionId,\n })\n}\n"],"names":[],"mappings":";AAEA,IAAI;AACJ,SAAS,aAAa,MAAc;AAClC,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AAEO,MAAM,kBAAkB,CAAC,eAAuB;AACrD,MAAI,CAAC,SAAS;AACZ,UAAM,mBAAmB,aAAa,QAAQ,IAAI,gBAAgB,GAAG;AACrE,UAAM,sBAAsB,aAAa,QAAQ,IAAI,kBAAmB;AACxE,cAAU,GAAG,mBAAmB,IAAI,gBAAgB,KAAK,EAAE,IAAI,mBAAmB;AAAA,EACpF;AACA,QAAM,MAAM,UAAU;AAEtB,QAAM,WAAW,IAAI,SAAqB;AACxC,WAAO,gBAAgB,KAAK,MAAM,KAAK;AAAA,EACzC;AAEA,SAAO,OAAO,OAAO,UAAU;AAAA,IAC7B;AAAA,IACA;AAAA,EAAA,CACD;AACH;"}
@@ -102,13 +102,6 @@ export interface ServerFnHandler<TMethod extends Method, TServerFnResponseType e
102
102
  export interface ServerFnBuilder<TMethod extends Method = 'GET', TServerFnResponseType extends ServerFnResponseType = 'data'> extends ServerFnMiddleware<TMethod, TServerFnResponseType, undefined>, ServerFnValidator<TMethod, TServerFnResponseType, undefined>, ServerFnHandler<TMethod, TServerFnResponseType, undefined, undefined> {
103
103
  options: ServerFnBaseOptions<TMethod, TServerFnResponseType, unknown, undefined, undefined>;
104
104
  }
105
- export declare function extractFormDataContext(formData: FormData): {
106
- context: unknown;
107
- data: FormData;
108
- } | {
109
- data: FormData;
110
- context?: undefined;
111
- };
112
105
  export declare function flattenMiddlewares(middlewares: Array<AnyFunctionMiddleware>): Array<AnyFunctionMiddleware>;
113
106
  export type ServerFnMiddlewareOptions = {
114
107
  method: Method;
@@ -1,10 +1,7 @@
1
1
  import { isRedirect, isNotFound } from "@tanstack/router-core";
2
2
  import { mergeHeaders } from "@tanstack/router-core/ssr/client";
3
- import { getStartContext } from "@tanstack/start-storage-context";
4
3
  import { globalMiddleware } from "./registerGlobalMiddleware.js";
5
- import { startSerializer } from "./serializer.js";
6
- import { createIsomorphicFn } from "./createIsomorphicFn.js";
7
- const getRouterInstance = createIsomorphicFn().client(() => window.__TSR_ROUTER__).server(() => getStartContext({ throwIfNotFound: false })?.router);
4
+ import { getRouterInstance } from "./getRouterInstance.js";
8
5
  function createServerFn(options, __opts) {
9
6
  const resolvedOptions = __opts || options || {};
10
7
  if (typeof resolvedOptions.method === "undefined") {
@@ -52,8 +49,7 @@ function createServerFn(options, __opts) {
52
49
  ...extractedFn,
53
50
  // The extracted function on the server-side calls
54
51
  // this function
55
- __executeServer: async (opts_, signal) => {
56
- const opts = opts_ instanceof FormData ? extractFormDataContext(opts_) : opts_;
52
+ __executeServer: async (opts, signal) => {
57
53
  const ctx = {
58
54
  ...extractedFn,
59
55
  ...opts,
@@ -109,27 +105,6 @@ async function executeMiddleware(middlewares, env, opts) {
109
105
  context: opts.context || {}
110
106
  });
111
107
  }
112
- function extractFormDataContext(formData) {
113
- const serializedContext = formData.get("__TSR_CONTEXT");
114
- formData.delete("__TSR_CONTEXT");
115
- if (typeof serializedContext !== "string") {
116
- return {
117
- context: {},
118
- data: formData
119
- };
120
- }
121
- try {
122
- const context = startSerializer.parse(serializedContext);
123
- return {
124
- context,
125
- data: formData
126
- };
127
- } catch {
128
- return {
129
- data: formData
130
- };
131
- }
132
- }
133
108
  function flattenMiddlewares(middlewares) {
134
109
  const seen = /* @__PURE__ */ new Set();
135
110
  const flattened = [];
@@ -217,7 +192,6 @@ export {
217
192
  createServerFn,
218
193
  execValidator,
219
194
  executeMiddleware,
220
- extractFormDataContext,
221
195
  flattenMiddlewares,
222
196
  serverFnBaseToMiddleware
223
197
  };
@@ -1 +1 @@
1
- {"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { isNotFound, isRedirect } from '@tanstack/router-core'\nimport { mergeHeaders } from '@tanstack/router-core/ssr/client'\nimport { getStartContext } from '@tanstack/start-storage-context'\nimport { globalMiddleware } from './registerGlobalMiddleware'\n\nimport { startSerializer } from './serializer'\n\nimport { createIsomorphicFn } from './createIsomorphicFn'\nimport type {\n SerializerParse,\n SerializerStringify,\n SerializerStringifyBy,\n} from './serializer'\nimport type {\n AnyRouter,\n AnyValidator,\n Constrain,\n Expand,\n ResolveValidatorInput,\n Validator,\n} from '@tanstack/router-core'\nimport type { JsonResponse } from '@tanstack/router-core/ssr/client'\nimport type { Readable } from 'node:stream'\nimport type {\n AnyFunctionMiddleware,\n AssignAllClientSendContext,\n AssignAllServerContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nconst getRouterInstance = createIsomorphicFn()\n .client(() => window.__TSR_ROUTER__!)\n .server(() => getStartContext({ throwIfNotFound: false })?.router)\n\nexport function createServerFn<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = undefined,\n TValidator = undefined,\n>(\n options?: {\n method?: TMethod\n response?: TServerFnResponseType\n },\n __opts?: ServerFnBaseOptions<\n TMethod,\n TServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >,\n): ServerFnBuilder<TMethod, TServerFnResponseType> {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as TMethod\n }\n\n return {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n return createServerFn<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { middleware })) as any\n },\n validator: (validator) => {\n return createServerFn<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { validator })) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<TResponse, TServerFnResponseType>,\n ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse\n >,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n Object.assign(resolvedOptions, {\n ...extractedFn,\n extractedFn,\n serverFn,\n })\n\n const resolvedMiddleware = [\n ...(resolvedOptions.middleware || []),\n serverFnBaseToMiddleware(resolvedOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...resolvedOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n router: getRouterInstance(),\n }).then((d) => {\n if (resolvedOptions.response === 'full') {\n return d\n }\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts_: any, signal: AbortSignal) => {\n const opts =\n opts_ instanceof FormData ? extractFormDataContext(opts_) : opts_\n\n const ctx = {\n ...extractedFn,\n ...opts,\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n }\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddleware,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n nextMiddleware.options.validator &&\n (env === 'client' ? nextMiddleware.options.validateClient : true)\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(nextMiddleware.options.validator, ctx.data)\n }\n\n const middlewareFn = (\n env === 'client'\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n response?: ServerFnResponseType\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n // router?: AnyRouter\n}\n\nexport type Fetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TValidator>\n ? OptionalFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n : RequiredFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n\nexport interface FetcherBase {\n url: string\n __executeServer: (opts: {\n method: Method\n response?: ServerFnResponseType\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport type FetchResult<\n TMiddlewares,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = TServerFnResponseType extends 'raw'\n ? Promise<Response>\n : TServerFnResponseType extends 'full'\n ? Promise<FullFetcherData<TMiddlewares, TResponse>>\n : Promise<FetcherData<TResponse>>\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface FullFetcherData<TMiddlewares, TResponse> {\n error: unknown\n result: FetcherData<TResponse>\n context: AssignAllClientSendContext<TMiddlewares>\n}\n\nexport type FetcherData<TResponse> =\n TResponse extends JsonResponse<any>\n ? SerializerParse<ReturnType<TResponse['json']>>\n : SerializerParse<TResponse>\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\nexport type ServerFnResponseType = 'data' | 'full' | 'raw'\n\n// see https://h3.unjs.io/guide/event-handler#responses-types\nexport type RawResponse = Response | ReadableStream | Readable | null | string\n\nexport type ServerFnReturnType<\n TServerFnResponseType extends ServerFnResponseType,\n TResponse,\n> = TServerFnResponseType extends 'raw'\n ? RawResponse | Promise<RawResponse>\n : Promise<SerializerStringify<TResponse>> | SerializerStringify<TResponse>\n\nexport type ServerFn<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,\n) => ServerFnReturnType<TServerFnResponseType, TResponse>\n\nexport interface ServerFnCtx<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n method: TMethod\n response: TServerFnResponseType\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TValidator>>\n context: Expand<AssignAllServerContext<TMiddlewares>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = {\n (\n opts: CompiledFetcherFnOptions &\n ServerFnBaseOptions<Method, TServerFnResponseType>,\n ): Promise<TResponse>\n url: string\n}\n\nexport type ServerFnBaseOptions<\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInput = unknown,\n> = {\n method: TMethod\n response?: TServerFnResponseType\n validateClient?: boolean\n middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware>>\n validator?: ConstrainValidator<TInput>\n extractedFn?: CompiledFetcherFn<TResponse, TServerFnResponseType>\n serverFn?: ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TInput,\n TResponse\n >\n functionId: string\n}\n\nexport type ValidatorInputStringify<TValidator> = SerializerStringifyBy<\n ResolveValidatorInput<TValidator>,\n Date | undefined | FormData\n>\n\nexport type ValidatorSerializerStringify<TValidator> =\n ValidatorInputStringify<TValidator> extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<TValidator> =\n | (unknown extends TValidator\n ? TValidator\n : ResolveValidatorInput<TValidator> extends ValidatorInputStringify<TValidator>\n ? TValidator\n : never)\n | ValidatorSerializerStringify<TValidator>\n\nexport interface ServerFnMiddleware<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TValidator,\n> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware>\n >,\n ) => ServerFnAfterMiddleware<\n TMethod,\n TServerFnResponseType,\n TNewMiddlewares,\n TValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnValidator<TMethod, TServerFnResponseType, TMiddlewares>,\n ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}\n\nexport type ValidatorFn<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> = <TValidator>(\n validator: ConstrainValidator<TValidator>,\n) => ServerFnAfterValidator<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n>\n\nexport interface ServerFnValidator<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> {\n validator: ValidatorFn<TMethod, TServerFnResponseType, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnMiddleware<TMethod, TServerFnResponseType, TValidator>,\n ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}\n\nexport interface ServerFnAfterTyper<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnHandler<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TValidator, TNewResponse, TServerFnResponseType>\n}\n\nexport interface ServerFnBuilder<\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n> extends ServerFnMiddleware<TMethod, TServerFnResponseType, undefined>,\n ServerFnValidator<TMethod, TServerFnResponseType, undefined>,\n ServerFnHandler<TMethod, TServerFnResponseType, undefined, undefined> {\n options: ServerFnBaseOptions<\n TMethod,\n TServerFnResponseType,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport function extractFormDataContext(formData: FormData) {\n const serializedContext = formData.get('__TSR_CONTEXT')\n formData.delete('__TSR_CONTEXT')\n\n if (typeof serializedContext !== 'string') {\n return {\n context: {},\n data: formData,\n }\n }\n\n try {\n const context = startSerializer.parse(serializedContext)\n return {\n context,\n data: formData,\n }\n } catch {\n return {\n data: formData,\n }\n }\n}\n\nexport function flattenMiddlewares(\n middlewares: Array<AnyFunctionMiddleware>,\n): Array<AnyFunctionMiddleware> {\n const seen = new Set<AnyFunctionMiddleware>()\n const flattened: Array<AnyFunctionMiddleware> = []\n\n const recurse = (middleware: Array<AnyFunctionMiddleware>) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n response?: ServerFnResponseType\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n router?: AnyRouter\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : ctx.response === 'raw'\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nexport function serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n _types: undefined!,\n options: {\n validator: options.validator,\n validateClient: options.validateClient,\n client: async ({ next, sendContext, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":[],"mappings":"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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'\nimport { globalMiddleware } from './registerGlobalMiddleware'\n\nimport { getRouterInstance } from './getRouterInstance'\nimport type {\n SerializerParse,\n SerializerStringify,\n SerializerStringifyBy,\n} from './serializer'\nimport type {\n AnyRouter,\n AnyValidator,\n Constrain,\n Expand,\n ResolveValidatorInput,\n Validator,\n} from '@tanstack/router-core'\nimport type { JsonResponse } from '@tanstack/router-core/ssr/client'\nimport type { Readable } from 'node:stream'\nimport type {\n AnyFunctionMiddleware,\n AssignAllClientSendContext,\n AssignAllServerContext,\n FunctionMiddlewareClientFnResult,\n FunctionMiddlewareServerFnResult,\n IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\ntype TODO = any\n\nexport function createServerFn<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = undefined,\n TValidator = undefined,\n>(\n options?: {\n method?: TMethod\n response?: TServerFnResponseType\n },\n __opts?: ServerFnBaseOptions<\n TMethod,\n TServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >,\n): ServerFnBuilder<TMethod, TServerFnResponseType> {\n const resolvedOptions = (__opts || options || {}) as ServerFnBaseOptions<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as TMethod\n }\n\n return {\n options: resolvedOptions as any,\n middleware: (middleware) => {\n return createServerFn<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { middleware })) as any\n },\n validator: (validator) => {\n return createServerFn<\n TMethod,\n ServerFnResponseType,\n TResponse,\n TMiddlewares,\n TValidator\n >(undefined, Object.assign(resolvedOptions, { validator })) as any\n },\n handler: (...args) => {\n // This function signature changes due to AST transformations\n // in the babel plugin. We need to cast it to the correct\n // function signature post-transformation\n const [extractedFn, serverFn] = args as unknown as [\n CompiledFetcherFn<TResponse, TServerFnResponseType>,\n ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse\n >,\n ]\n\n // Keep the original function around so we can use it\n // in the server environment\n Object.assign(resolvedOptions, {\n ...extractedFn,\n extractedFn,\n serverFn,\n })\n\n const resolvedMiddleware = [\n ...(resolvedOptions.middleware || []),\n serverFnBaseToMiddleware(resolvedOptions),\n ]\n\n // We want to make sure the new function has the same\n // properties as the original function\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n return executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...resolvedOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n context: {},\n router: getRouterInstance(),\n }).then((d) => {\n if (resolvedOptions.response === 'full') {\n return d\n }\n if (d.error) throw d.error\n return d.result\n })\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any, signal: AbortSignal) => {\n const ctx = {\n ...extractedFn,\n ...opts,\n signal,\n }\n\n return executeMiddleware(resolvedMiddleware, 'server', ctx).then(\n (d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }),\n )\n },\n },\n ) as any\n },\n }\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddleware,\n ...middlewares,\n ])\n\n const next: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n if (\n nextMiddleware.options.validator &&\n (env === 'client' ? nextMiddleware.options.validateClient : true)\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(nextMiddleware.options.validator, ctx.data)\n }\n\n const middlewareFn = (\n env === 'client'\n ? nextMiddleware.options.client\n : nextMiddleware.options.server\n ) as MiddlewareFn | undefined\n\n if (middlewareFn) {\n // Execute the middleware\n return applyMiddleware(middlewareFn, ctx, async (newCtx) => {\n return next(newCtx).catch((error: any) => {\n if (isRedirect(error) || isNotFound(error)) {\n return {\n ...newCtx,\n error,\n }\n }\n\n throw error\n })\n })\n }\n\n return next(ctx)\n }\n\n // Start the middleware chain\n return next({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || {},\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n response?: ServerFnResponseType\n headers?: HeadersInit\n signal?: AbortSignal\n context?: any\n // router?: AnyRouter\n}\n\nexport type Fetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TValidator>\n ? OptionalFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n : RequiredFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType\n >\n\nexport interface FetcherBase {\n url: string\n __executeServer: (opts: {\n method: Method\n response?: ServerFnResponseType\n data: unknown\n headers?: HeadersInit\n context?: any\n signal: AbortSignal\n }) => Promise<unknown>\n}\n\nexport type FetchResult<\n TMiddlewares,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = TServerFnResponseType extends 'raw'\n ? Promise<Response>\n : TServerFnResponseType extends 'full'\n ? Promise<FullFetcherData<TMiddlewares, TResponse>>\n : Promise<FetcherData<TResponse>>\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TValidator,\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TValidator>,\n ): FetchResult<TMiddlewares, TResponse, TServerFnResponseType>\n}\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n}\n\nexport interface OptionalFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<TMiddlewares, TValidator>\n extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>\n}\n\nexport interface FullFetcherData<TMiddlewares, TResponse> {\n error: unknown\n result: FetcherData<TResponse>\n context: AssignAllClientSendContext<TMiddlewares>\n}\n\nexport type FetcherData<TResponse> =\n TResponse extends JsonResponse<any>\n ? SerializerParse<ReturnType<TResponse['json']>>\n : SerializerParse<TResponse>\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\nexport type ServerFnResponseType = 'data' | 'full' | 'raw'\n\n// see https://h3.unjs.io/guide/event-handler#responses-types\nexport type RawResponse = Response | ReadableStream | Readable | null | string\n\nexport type ServerFnReturnType<\n TServerFnResponseType extends ServerFnResponseType,\n TResponse,\n> = TServerFnResponseType extends 'raw'\n ? RawResponse | Promise<RawResponse>\n : Promise<SerializerStringify<TResponse>> | SerializerStringify<TResponse>\n\nexport type ServerFn<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,\n) => ServerFnReturnType<TServerFnResponseType, TResponse>\n\nexport interface ServerFnCtx<\n TMethod,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n method: TMethod\n response: TServerFnResponseType\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TValidator>>\n context: Expand<AssignAllServerContext<TMiddlewares>>\n signal: AbortSignal\n}\n\nexport type CompiledFetcherFn<\n TResponse,\n TServerFnResponseType extends ServerFnResponseType,\n> = {\n (\n opts: CompiledFetcherFnOptions &\n ServerFnBaseOptions<Method, TServerFnResponseType>,\n ): Promise<TResponse>\n url: string\n}\n\nexport type ServerFnBaseOptions<\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInput = unknown,\n> = {\n method: TMethod\n response?: TServerFnResponseType\n validateClient?: boolean\n middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware>>\n validator?: ConstrainValidator<TInput>\n extractedFn?: CompiledFetcherFn<TResponse, TServerFnResponseType>\n serverFn?: ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TInput,\n TResponse\n >\n functionId: string\n}\n\nexport type ValidatorInputStringify<TValidator> = SerializerStringifyBy<\n ResolveValidatorInput<TValidator>,\n Date | undefined | FormData\n>\n\nexport type ValidatorSerializerStringify<TValidator> =\n ValidatorInputStringify<TValidator> extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<TValidator> =\n | (unknown extends TValidator\n ? TValidator\n : ResolveValidatorInput<TValidator> extends ValidatorInputStringify<TValidator>\n ? TValidator\n : never)\n | ValidatorSerializerStringify<TValidator>\n\nexport interface ServerFnMiddleware<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TValidator,\n> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware>\n >,\n ) => ServerFnAfterMiddleware<\n TMethod,\n TServerFnResponseType,\n TNewMiddlewares,\n TValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnValidator<TMethod, TServerFnResponseType, TMiddlewares>,\n ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}\n\nexport type ValidatorFn<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> = <TValidator>(\n validator: ConstrainValidator<TValidator>,\n) => ServerFnAfterValidator<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n>\n\nexport interface ServerFnValidator<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n> {\n validator: ValidatorFn<TMethod, TServerFnResponseType, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnMiddleware<TMethod, TServerFnResponseType, TValidator>,\n ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}\n\nexport interface ServerFnAfterTyper<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> extends ServerFnHandler<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TMethod extends Method,\n TServerFnResponseType extends ServerFnResponseType,\n TMiddlewares,\n TValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TMethod,\n TServerFnResponseType,\n TMiddlewares,\n TValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TValidator, TNewResponse, TServerFnResponseType>\n}\n\nexport interface ServerFnBuilder<\n TMethod extends Method = 'GET',\n TServerFnResponseType extends ServerFnResponseType = 'data',\n> extends ServerFnMiddleware<TMethod, TServerFnResponseType, undefined>,\n ServerFnValidator<TMethod, TServerFnResponseType, undefined>,\n ServerFnHandler<TMethod, TServerFnResponseType, undefined, undefined> {\n options: ServerFnBaseOptions<\n TMethod,\n TServerFnResponseType,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport function flattenMiddlewares(\n middlewares: Array<AnyFunctionMiddleware>,\n): Array<AnyFunctionMiddleware> {\n const seen = new Set<AnyFunctionMiddleware>()\n const flattened: Array<AnyFunctionMiddleware> = []\n\n const recurse = (middleware: Array<AnyFunctionMiddleware>) => {\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n response?: ServerFnResponseType\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n functionId: string\n router?: AnyRouter\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport const applyMiddleware = async (\n middlewareFn: MiddlewareFn,\n ctx: ServerFnMiddlewareOptions,\n nextFn: NextFn,\n) => {\n return middlewareFn({\n ...ctx,\n next: (async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n return nextFn({\n ...ctx,\n ...userCtx,\n context: {\n ...ctx.context,\n ...userCtx.context,\n },\n sendContext: {\n ...ctx.sendContext,\n ...(userCtx.sendContext ?? {}),\n },\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : ctx.response === 'raw'\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n })\n }) as any,\n } as any)\n}\n\nexport function execValidator(\n validator: AnyValidator,\n input: unknown,\n): unknown {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = validator['~standard'].validate(input)\n\n if (result instanceof Promise)\n throw new Error('Async validation not supported')\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nexport function serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n _types: undefined!,\n options: {\n validator: options.validator,\n validateClient: options.validateClient,\n client: async ({ next, sendContext, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res) as unknown as FunctionMiddlewareClientFnResult<\n any,\n any,\n any\n >\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const getRouterInstance: import('./createIsomorphicFn.js').IsomorphicFn<[], import('@tanstack/router-core').AnyRouter, import('@tanstack/router-core').AnyRouter>;
@@ -0,0 +1,7 @@
1
+ import { getStartContext } from "@tanstack/start-storage-context";
2
+ import { createIsomorphicFn } from "./createIsomorphicFn.js";
3
+ const getRouterInstance = createIsomorphicFn().client(() => window.__TSR_ROUTER__).server(() => getStartContext().router);
4
+ export {
5
+ getRouterInstance
6
+ };
7
+ //# sourceMappingURL=getRouterInstance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRouterInstance.js","sources":["../../src/getRouterInstance.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from './createIsomorphicFn'\n\n// TODO should this be a public API\nexport const getRouterInstance = createIsomorphicFn()\n .client(() => window.__TSR_ROUTER__!)\n .server(() => getStartContext().router)\n"],"names":[],"mappings":";;AAIO,MAAM,oBAAoB,qBAC9B,OAAO,MAAM,OAAO,cAAe,EACnC,OAAO,MAAM,gBAAA,EAAkB,MAAM;"}
@@ -1,11 +1,13 @@
1
1
  export type { DehydratedRouter, JsonResponse, } from '@tanstack/router-core/ssr/client';
2
2
  export { hydrate, json, mergeHeaders } from '@tanstack/router-core/ssr/client';
3
- export { startSerializer } from './serializer.js';
4
- export type { StartSerializer, Serializable, SerializerParse, SerializerParseBy, SerializerStringify, SerializerStringifyBy, SerializerExtensions, } from './serializer.js';
3
+ export type { Serializable, SerializerParse, SerializerParseBy, SerializerStringify, SerializerStringifyBy, SerializerExtensions, } from './serializer.js';
5
4
  export { createIsomorphicFn, type IsomorphicFn, type ServerOnlyFn, type ClientOnlyFn, type IsomorphicFnBase, } from './createIsomorphicFn.js';
6
5
  export { serverOnly, clientOnly } from './envOnly.js';
7
6
  export { createServerFn } from './createServerFn.js';
8
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 FunctionMiddlewareClientFnOptions, type FunctionMiddlewareClientFnResult, type FunctionMiddlewareClientNextFn, type FunctionClientResultWithContext, type AssignAllClientContextBeforeNext, type AssignAllMiddleware, type AssignAllServerContext, type FunctionMiddlewareAfterValidator, type FunctionMiddlewareClientFn, type FunctionMiddlewareServerFnResult, type FunctionMiddlewareClient, type FunctionMiddlewareServerFnOptions, type FunctionMiddlewareServerNextFn, type FunctionServerResultWithContext, type AnyRequestMiddleware, } from './createMiddleware.js';
9
8
  export { registerGlobalMiddleware, globalMiddleware, } from './registerGlobalMiddleware.js';
10
9
  export type { CompiledFetcherFnOptions, CompiledFetcherFn, Fetcher, RscStream, FetcherData, FetcherBaseOptions, ServerFn, ServerFnCtx, ServerFnResponseType, MiddlewareFn, ServerFnMiddlewareOptions, ServerFnMiddlewareResult, ServerFnBuilder, ServerFnBaseOptions, NextFn, Method, OptionalFetcher, RequiredFetcher, } from './createServerFn.js';
11
- export { applyMiddleware, execValidator, serverFnBaseToMiddleware, extractFormDataContext, flattenMiddlewares, executeMiddleware, } from './createServerFn.js';
10
+ export { applyMiddleware, execValidator, serverFnBaseToMiddleware, flattenMiddlewares, executeMiddleware, } from './createServerFn.js';
11
+ export { createClientRpc } from './createClientRpc.js';
12
+ export { getDefaultSerovalPlugins } from './serializer/getDefaultSerovalPlugins.js';
13
+ export { TSR_FORMDATA_CONTEXT } from './constants.js';
package/dist/esm/index.js CHANGED
@@ -1,27 +1,30 @@
1
1
  import { hydrate, json, mergeHeaders } from "@tanstack/router-core/ssr/client";
2
- import { startSerializer } from "./serializer.js";
3
2
  import { createIsomorphicFn } from "./createIsomorphicFn.js";
4
3
  import { clientOnly, serverOnly } from "./envOnly.js";
5
- import { applyMiddleware, createServerFn, execValidator, executeMiddleware, extractFormDataContext, flattenMiddlewares, serverFnBaseToMiddleware } from "./createServerFn.js";
4
+ import { applyMiddleware, createServerFn, execValidator, executeMiddleware, flattenMiddlewares, serverFnBaseToMiddleware } from "./createServerFn.js";
6
5
  import { createMiddleware } from "./createMiddleware.js";
7
6
  import { globalMiddleware, registerGlobalMiddleware } from "./registerGlobalMiddleware.js";
7
+ import { createClientRpc } from "./createClientRpc.js";
8
+ import { getDefaultSerovalPlugins } from "./serializer/getDefaultSerovalPlugins.js";
9
+ import { TSR_FORMDATA_CONTEXT } from "./constants.js";
8
10
  export {
11
+ TSR_FORMDATA_CONTEXT,
9
12
  applyMiddleware,
10
13
  clientOnly,
14
+ createClientRpc,
11
15
  createIsomorphicFn,
12
16
  createMiddleware,
13
17
  createServerFn,
14
18
  execValidator,
15
19
  executeMiddleware,
16
- extractFormDataContext,
17
20
  flattenMiddlewares,
21
+ getDefaultSerovalPlugins,
18
22
  globalMiddleware,
19
23
  hydrate,
20
24
  json,
21
25
  mergeHeaders,
22
26
  registerGlobalMiddleware,
23
27
  serverFnBaseToMiddleware,
24
- serverOnly,
25
- startSerializer
28
+ serverOnly
26
29
  };
27
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,5 @@
1
+ export declare const ServerFunctionSerializationAdapter: import('@tanstack/router-core').Transformer<{
2
+ functionId: string;
3
+ }, {
4
+ functionId: string;
5
+ }>;
@@ -0,0 +1,12 @@
1
+ import { createSerializationAdapter } from "@tanstack/router-core";
2
+ import { createClientRpc } from "../createClientRpc.js";
3
+ const ServerFunctionSerializationAdapter = createSerializationAdapter({
4
+ key: "$TSS/serverfn",
5
+ test: (v) => typeof v == "function" && "functionId" in v,
6
+ toSerializable: ({ functionId }) => ({ functionId }),
7
+ fromSerializable: ({ functionId }) => createClientRpc(functionId)
8
+ });
9
+ export {
10
+ ServerFunctionSerializationAdapter
11
+ };
12
+ //# sourceMappingURL=ServerFunctionSerializationAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerFunctionSerializationAdapter.js","sources":["../../../src/serializer/ServerFunctionSerializationAdapter.ts"],"sourcesContent":["import { createSerializationAdapter } from '@tanstack/router-core'\nimport { createClientRpc } from '../createClientRpc'\n\nexport const ServerFunctionSerializationAdapter = createSerializationAdapter({\n key: '$TSS/serverfn',\n test: (v): v is { functionId: string } =>\n typeof v == 'function' && 'functionId' in v,\n toSerializable: ({ functionId }) => ({ functionId }),\n fromSerializable: ({ functionId }) => createClientRpc(functionId),\n})\n"],"names":[],"mappings":";;AAGO,MAAM,qCAAqC,2BAA2B;AAAA,EAC3E,KAAK;AAAA,EACL,MAAM,CAAC,MACL,OAAO,KAAK,cAAc,gBAAgB;AAAA,EAC5C,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,WAAA;AAAA,EACvC,kBAAkB,CAAC,EAAE,WAAA,MAAiB,gBAAgB,UAAU;AAClE,CAAC;"}
@@ -0,0 +1,3 @@
1
+ export declare function getClientSerovalPlugins(): (import('seroval').Plugin<Error, any> | import('seroval').Plugin<ReadableStream<any>, any> | import('seroval').Plugin<FormData, any> | import('seroval').Plugin<any, import('seroval').SerovalNode> | import('seroval').Plugin<{
2
+ functionId: string;
3
+ }, import('seroval').SerovalNode>)[];
@@ -0,0 +1,13 @@
1
+ import { makeSerovalPlugin } from "@tanstack/router-core";
2
+ import { getDefaultSerovalPlugins } from "./getDefaultSerovalPlugins.js";
3
+ import { ServerFunctionSerializationAdapter } from "./ServerFunctionSerializationAdapter.js";
4
+ function getClientSerovalPlugins() {
5
+ return [
6
+ ...getDefaultSerovalPlugins(),
7
+ makeSerovalPlugin(ServerFunctionSerializationAdapter)
8
+ ];
9
+ }
10
+ export {
11
+ getClientSerovalPlugins
12
+ };
13
+ //# sourceMappingURL=getClientSerovalPlugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getClientSerovalPlugins.js","sources":["../../../src/serializer/getClientSerovalPlugins.ts"],"sourcesContent":["import { makeSerovalPlugin } from '@tanstack/router-core'\nimport { getDefaultSerovalPlugins } from './getDefaultSerovalPlugins'\nimport { ServerFunctionSerializationAdapter } from './ServerFunctionSerializationAdapter'\n\nexport function getClientSerovalPlugins() {\n return [\n ...getDefaultSerovalPlugins(),\n makeSerovalPlugin(ServerFunctionSerializationAdapter),\n ]\n}\n"],"names":[],"mappings":";;;AAIO,SAAS,0BAA0B;AACxC,SAAO;AAAA,IACL,GAAG,yBAAA;AAAA,IACH,kBAAkB,kCAAkC;AAAA,EAAA;AAExD;"}
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'seroval';
2
+ export declare const defaultSerovalPlugins: (Plugin<Error, any> | Plugin<ReadableStream<any>, any> | Plugin<FormData, any>)[];
3
+ export declare function getDefaultSerovalPlugins(): (Plugin<Error, any> | Plugin<ReadableStream<any>, any> | Plugin<FormData, any> | Plugin<any, import('seroval').SerovalNode>)[];
@@ -0,0 +1,19 @@
1
+ import invariant from "tiny-invariant";
2
+ import { defaultSerovalPlugins as defaultSerovalPlugins$1, makeSerovalPlugin } from "@tanstack/router-core";
3
+ import { FormDataPlugin } from "seroval-plugins/web";
4
+ import { getRouterInstance } from "../getRouterInstance.js";
5
+ const defaultSerovalPlugins = [
6
+ ...defaultSerovalPlugins$1,
7
+ FormDataPlugin
8
+ ];
9
+ function getDefaultSerovalPlugins() {
10
+ const router = getRouterInstance();
11
+ invariant(router, "Expected router instance to be available");
12
+ const adapters = router.options.serializationAdapters;
13
+ return [...defaultSerovalPlugins, ...adapters?.map(makeSerovalPlugin) ?? []];
14
+ }
15
+ export {
16
+ defaultSerovalPlugins,
17
+ getDefaultSerovalPlugins
18
+ };
19
+ //# sourceMappingURL=getDefaultSerovalPlugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDefaultSerovalPlugins.js","sources":["../../../src/serializer/getDefaultSerovalPlugins.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport {\n makeSerovalPlugin,\n defaultSerovalPlugins as routerDefaultSerovalPlugins,\n} from '@tanstack/router-core'\nimport { FormDataPlugin } from 'seroval-plugins/web'\nimport { getRouterInstance } from '../getRouterInstance'\nimport type { AnyTransformer } from '@tanstack/router-core'\n\nimport type { Plugin } from 'seroval'\n\nexport const defaultSerovalPlugins = [\n ...routerDefaultSerovalPlugins,\n FormDataPlugin as Plugin<FormData, any>,\n]\n\nexport function getDefaultSerovalPlugins() {\n const router = getRouterInstance()\n invariant(router, 'Expected router instance to be available')\n const adapters = router.options.serializationAdapters as\n | Array<AnyTransformer>\n | undefined\n return [...defaultSerovalPlugins, ...(adapters?.map(makeSerovalPlugin) ?? [])]\n}\n"],"names":["routerDefaultSerovalPlugins"],"mappings":";;;;AAWO,MAAM,wBAAwB;AAAA,EACnC,GAAGA;AAAAA,EACH;AACF;AAEO,SAAS,2BAA2B;AACzC,QAAM,SAAS,kBAAA;AACf,YAAU,QAAQ,0CAA0C;AAC5D,QAAM,WAAW,OAAO,QAAQ;AAGhC,SAAO,CAAC,GAAG,uBAAuB,GAAI,UAAU,IAAI,iBAAiB,KAAK,EAAG;AAC/E;"}
@@ -1,9 +1,3 @@
1
- export interface StartSerializer {
2
- stringify: (obj: unknown) => string;
3
- parse: (str: string) => unknown;
4
- encode: <T>(value: T) => T;
5
- decode: <T>(value: T) => T;
6
- }
7
1
  export type SerializerStringifyBy<T, TSerializable> = T extends TSerializable ? T : T extends (...args: Array<any>) => any ? 'Function is not serializable' : {
8
2
  [K in keyof T]: SerializerStringifyBy<T[K], TSerializable>;
9
3
  };
@@ -20,4 +14,3 @@ export interface SerializerExtensions extends DefaultSerializerExtensions {
20
14
  export type Serializable = Date | undefined | Error | FormData | bigint;
21
15
  export type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>;
22
16
  export type SerializerParse<T> = SerializerParseBy<T, Serializable>;
23
- export declare const startSerializer: StartSerializer;
@@ -0,0 +1 @@
1
+ export declare function serverFnFetcher(url: string, args: Array<any>, handler: (url: string, requestInit: RequestInit) => Promise<Response>): Promise<any>;
@@ -0,0 +1,217 @@
1
+ import { isPlainObject, encode, parseRedirect, isNotFound } from "@tanstack/router-core";
2
+ import { fromJSON, toJSONAsync, fromCrossJSON } from "seroval";
3
+ import invariant from "tiny-invariant";
4
+ import { getClientSerovalPlugins } from "./serializer/getClientSerovalPlugins.js";
5
+ import { TSR_FORMDATA_CONTEXT } from "./constants.js";
6
+ let serovalPlugins = null;
7
+ async function serverFnFetcher(url, args, handler) {
8
+ if (!serovalPlugins) {
9
+ serovalPlugins = getClientSerovalPlugins();
10
+ }
11
+ const _first = args[0];
12
+ if (isPlainObject(_first) && _first.method) {
13
+ const first = _first;
14
+ const type = first.data instanceof FormData ? "formData" : "payload";
15
+ const headers = new Headers({
16
+ "x-tsr-redirect": "manual",
17
+ ...type === "payload" ? {
18
+ "content-type": "application/json",
19
+ accept: "application/x-ndjson, application/json"
20
+ } : {},
21
+ ...first.headers instanceof Headers ? Object.fromEntries(first.headers.entries()) : first.headers
22
+ });
23
+ if (first.method === "GET") {
24
+ const encodedPayload = encode({
25
+ payload: await serializePayload(first)
26
+ });
27
+ if (encodedPayload) {
28
+ if (url.includes("?")) {
29
+ url += `&${encodedPayload}`;
30
+ } else {
31
+ url += `?${encodedPayload}`;
32
+ }
33
+ }
34
+ }
35
+ if (url.includes("?")) {
36
+ url += `&createServerFn`;
37
+ } else {
38
+ url += `?createServerFn`;
39
+ }
40
+ if (first.response === "raw") {
41
+ url += `&raw`;
42
+ }
43
+ return await getResponse(
44
+ async () => handler(url, {
45
+ method: first.method,
46
+ headers,
47
+ signal: first.signal,
48
+ ...await getFetcherRequestOptions(first)
49
+ })
50
+ );
51
+ }
52
+ return await getResponse(
53
+ () => handler(url, {
54
+ method: "POST",
55
+ headers: {
56
+ Accept: "application/json",
57
+ "Content-Type": "application/json"
58
+ },
59
+ body: JSON.stringify(args)
60
+ })
61
+ );
62
+ }
63
+ async function serializePayload(opts) {
64
+ const payloadToSerialize = {};
65
+ if (opts.data) {
66
+ payloadToSerialize["data"] = opts.data;
67
+ }
68
+ if (opts.context && Object.keys(opts.context).length > 0) {
69
+ payloadToSerialize["context"] = opts.context;
70
+ }
71
+ return serialize(payloadToSerialize);
72
+ }
73
+ async function serialize(data) {
74
+ return JSON.stringify(
75
+ await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins }))
76
+ );
77
+ }
78
+ async function getFetcherRequestOptions(opts) {
79
+ if (opts.method === "POST") {
80
+ if (opts.data instanceof FormData) {
81
+ opts.data.set(TSR_FORMDATA_CONTEXT, await serialize(opts.context));
82
+ return {
83
+ body: opts.data
84
+ };
85
+ }
86
+ return {
87
+ body: await serializePayload(opts)
88
+ };
89
+ }
90
+ return {};
91
+ }
92
+ async function getResponse(fn) {
93
+ const response = await (async () => {
94
+ try {
95
+ return await fn();
96
+ } catch (error) {
97
+ if (error instanceof Response) {
98
+ return error;
99
+ }
100
+ throw error;
101
+ }
102
+ })();
103
+ const contentType = response.headers.get("content-type");
104
+ invariant(contentType, "expected content-type header to be set");
105
+ const serializedByStart = !!response.headers.get("x-tss-serialized");
106
+ if (!response.ok) {
107
+ if (serializedByStart && contentType.includes("application/json")) {
108
+ const jsonPayload = await response.json();
109
+ const result = fromJSON(jsonPayload, { plugins: serovalPlugins });
110
+ throw result;
111
+ }
112
+ throw new Error(await response.text());
113
+ }
114
+ if (serializedByStart) {
115
+ let result;
116
+ if (contentType.includes("application/x-ndjson")) {
117
+ const refs = /* @__PURE__ */ new Map();
118
+ result = await processServerFnResponse({
119
+ response,
120
+ onMessage: (msg) => fromCrossJSON(msg, { refs, plugins: serovalPlugins }),
121
+ onError(msg, error) {
122
+ console.error(msg, error);
123
+ }
124
+ });
125
+ }
126
+ if (contentType.includes("application/json")) {
127
+ const jsonPayload = await response.json();
128
+ result = fromJSON(jsonPayload, { plugins: serovalPlugins });
129
+ }
130
+ invariant(result, "expected result to be resolved");
131
+ if (result instanceof Error) {
132
+ throw result;
133
+ }
134
+ return result;
135
+ }
136
+ if (contentType.includes("application/json")) {
137
+ const jsonPayload = await response.json();
138
+ const redirect = parseRedirect(jsonPayload);
139
+ if (redirect) {
140
+ throw redirect;
141
+ }
142
+ if (isNotFound(jsonPayload)) {
143
+ throw jsonPayload;
144
+ }
145
+ return jsonPayload;
146
+ }
147
+ return response;
148
+ }
149
+ async function processServerFnResponse({
150
+ response,
151
+ onMessage,
152
+ onError
153
+ }) {
154
+ if (!response.body) {
155
+ throw new Error("No response body");
156
+ }
157
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
158
+ let buffer = "";
159
+ let firstRead = false;
160
+ let firstObject;
161
+ while (!firstRead) {
162
+ const { value, done } = await reader.read();
163
+ if (value) buffer += value;
164
+ if (buffer.length === 0 && done) {
165
+ throw new Error("Stream ended before first object");
166
+ }
167
+ if (buffer.endsWith("\n")) {
168
+ const lines = buffer.split("\n").filter(Boolean);
169
+ const firstLine = lines[0];
170
+ if (!firstLine) throw new Error("No JSON line in the first chunk");
171
+ firstObject = JSON.parse(firstLine);
172
+ firstRead = true;
173
+ buffer = lines.slice(1).join("\n");
174
+ } else {
175
+ const newlineIndex = buffer.indexOf("\n");
176
+ if (newlineIndex >= 0) {
177
+ const line = buffer.slice(0, newlineIndex).trim();
178
+ buffer = buffer.slice(newlineIndex + 1);
179
+ if (line.length > 0) {
180
+ firstObject = JSON.parse(line);
181
+ firstRead = true;
182
+ }
183
+ }
184
+ }
185
+ }
186
+ (async () => {
187
+ try {
188
+ while (true) {
189
+ const { value, done } = await reader.read();
190
+ if (value) buffer += value;
191
+ const lastNewline = buffer.lastIndexOf("\n");
192
+ if (lastNewline >= 0) {
193
+ const chunk = buffer.slice(0, lastNewline);
194
+ buffer = buffer.slice(lastNewline + 1);
195
+ const lines = chunk.split("\n").filter(Boolean);
196
+ for (const line of lines) {
197
+ try {
198
+ onMessage(JSON.parse(line));
199
+ } catch (e) {
200
+ onError?.(`Invalid JSON line: ${line}`, e);
201
+ }
202
+ }
203
+ }
204
+ if (done) {
205
+ break;
206
+ }
207
+ }
208
+ } catch (err) {
209
+ onError?.("Stream processing error:", err);
210
+ }
211
+ })();
212
+ return onMessage(firstObject);
213
+ }
214
+ export {
215
+ serverFnFetcher
216
+ };
217
+ //# sourceMappingURL=serverFnFetcher.js.map