UNPKG

@tanstack/start-server-functions-fetcher

Version:

Modern and scalable routing for applications

1 lines 6.97 kB
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import {\n encode,\n isNotFound,\n isPlainObject,\n isRedirect,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { startSerializer } from '@tanstack/start-client-core'\nimport type { FunctionMiddlewareClientFnOptions } from '@tanstack/start-client-core'\n\nexport async function serverFnFetcher(\n url: string,\n args: Array<any>,\n handler: (url: string, requestInit: RequestInit) => Promise<Response>,\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/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 the method is GET, we need to move the payload to the query string\n const encodedPayload = encode({\n payload: startSerializer.stringify({\n data: first.data,\n context: first.context,\n }),\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 if (first.response === 'raw') {\n url += `&raw`\n }\n\n return await getResponse(() =>\n handler(url, {\n method: first.method,\n headers,\n signal: first.signal,\n ...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 redirect: 'manual',\n }),\n )\n}\n\nfunction getFetcherRequestOptions(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n) {\n if (opts.method === 'POST') {\n if (opts.data instanceof FormData) {\n opts.data.set('__TSR_CONTEXT', startSerializer.stringify(opts.context))\n return {\n body: opts.data,\n }\n }\n\n return {\n body: startSerializer.stringify({\n data: opts.data ?? null,\n context: opts.context,\n }),\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 the response is not ok, throw an error\n if (!response.ok) {\n const contentType = response.headers.get('content-type')\n const isJson = contentType && contentType.includes('application/json')\n\n if (isJson) {\n // If it's JSON, decode it and throw it\n throw startSerializer.decode(await response.json())\n }\n\n throw new Error(await response.text())\n }\n\n // Check if the response is JSON\n if (response.headers.get('content-type')?.includes('application/json')) {\n // Even though the response is JSON, we need to decode it\n // because the server may have transformed it\n let json = startSerializer.decode(await response.json())\n\n const redirect = parseRedirect(json)\n\n if (redirect) json = redirect\n\n // If the response is a redirect or not found, throw it\n // for the router to handle\n if (isRedirect(json) || isNotFound(json) || json instanceof Error) {\n throw json\n }\n\n return json\n }\n\n return response\n}\n"],"names":["isPlainObject","encode","startSerializer","parseRedirect","isRedirect","isNotFound"],"mappings":"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"}