@tanstack/start-client-core
Advanced tools
| import { TSS_SERVER_FUNCTION } from "../constants.js"; | ||
| import { getStartOptions } from "../getStartOptions.js"; | ||
| import { serverFnFetcher } from "./serverFnFetcher.js"; | ||
| //#region src/client-rpc/createClientRpc.ts | ||
| function createClientRpc(functionId) { | ||
| const url = process.env.TSS_SERVER_FN_BASE + functionId; | ||
| const serverFnMeta = { id: functionId }; | ||
| const clientFn = (...args) => { | ||
| const startFetch = getStartOptions()?.serverFns?.fetch; | ||
| return serverFnFetcher(url, args, startFetch ?? fetch); | ||
| }; | ||
| return Object.assign(clientFn, { | ||
| url, | ||
| serverFnMeta, | ||
| [TSS_SERVER_FUNCTION]: true | ||
| }); | ||
| const url = process.env.TSS_SERVER_FN_BASE + functionId; | ||
| const serverFnMeta = { id: functionId }; | ||
| const clientFn = (...args) => { | ||
| const startFetch = getStartOptions()?.serverFns?.fetch; | ||
| return serverFnFetcher(url, args, startFetch ?? fetch); | ||
| }; | ||
| return Object.assign(clientFn, { | ||
| url, | ||
| serverFnMeta, | ||
| [TSS_SERVER_FUNCTION]: true | ||
| }); | ||
| } | ||
| export { | ||
| createClientRpc | ||
| }; | ||
| //# sourceMappingURL=createClientRpc.js.map | ||
| //#endregion | ||
| export { createClientRpc }; | ||
| //# sourceMappingURL=createClientRpc.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"createClientRpc.js","sources":["../../../src/client-rpc/createClientRpc.ts"],"sourcesContent":["import { TSS_SERVER_FUNCTION } from '../constants'\nimport { getStartOptions } from '../getStartOptions'\nimport { serverFnFetcher } from './serverFnFetcher'\nimport type { ClientFnMeta } from '../constants'\n\nexport function createClientRpc(functionId: string) {\n const url = process.env.TSS_SERVER_FN_BASE + functionId\n const serverFnMeta: ClientFnMeta = { id: functionId }\n\n const clientFn = (...args: Array<any>) => {\n const startFetch = getStartOptions()?.serverFns?.fetch\n return serverFnFetcher(url, args, startFetch ?? fetch)\n }\n\n return Object.assign(clientFn, {\n url,\n serverFnMeta,\n [TSS_SERVER_FUNCTION]: true,\n })\n}\n"],"names":[],"mappings":";;;AAKO,SAAS,gBAAgB,YAAoB;AAClD,QAAM,MAAM,QAAQ,IAAI,qBAAqB;AAC7C,QAAM,eAA6B,EAAE,IAAI,WAAA;AAEzC,QAAM,WAAW,IAAI,SAAqB;AACxC,UAAM,aAAa,mBAAmB,WAAW;AACjD,WAAO,gBAAgB,KAAK,MAAM,cAAc,KAAK;AAAA,EACvD;AAEA,SAAO,OAAO,OAAO,UAAU;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,CAAC,mBAAmB,GAAG;AAAA,EAAA,CACxB;AACH;"} | ||
| {"version":3,"file":"createClientRpc.js","names":[],"sources":["../../../src/client-rpc/createClientRpc.ts"],"sourcesContent":["import { TSS_SERVER_FUNCTION } from '../constants'\nimport { getStartOptions } from '../getStartOptions'\nimport { serverFnFetcher } from './serverFnFetcher'\nimport type { ClientFnMeta } from '../constants'\n\nexport function createClientRpc(functionId: string) {\n const url = process.env.TSS_SERVER_FN_BASE + functionId\n const serverFnMeta: ClientFnMeta = { id: functionId }\n\n const clientFn = (...args: Array<any>) => {\n const startFetch = getStartOptions()?.serverFns?.fetch\n return serverFnFetcher(url, args, startFetch ?? fetch)\n }\n\n return Object.assign(clientFn, {\n url,\n serverFnMeta,\n [TSS_SERVER_FUNCTION]: true,\n })\n}\n"],"mappings":";;;;AAKA,SAAgB,gBAAgB,YAAoB;CAClD,MAAM,MAAM,QAAQ,IAAI,qBAAqB;CAC7C,MAAM,eAA6B,EAAE,IAAI,YAAY;CAErD,MAAM,YAAY,GAAG,SAAqB;EACxC,MAAM,aAAa,iBAAiB,EAAE,WAAW;AACjD,SAAO,gBAAgB,KAAK,MAAM,cAAc,MAAM;;AAGxD,QAAO,OAAO,OAAO,UAAU;EAC7B;EACA;GACC,sBAAsB;EACxB,CAAC"} |
@@ -1,243 +0,231 @@ | ||
| import { FrameType, FRAME_HEADER_SIZE } from "../constants.js"; | ||
| const textDecoder = new TextDecoder(); | ||
| const EMPTY_BUFFER = new Uint8Array(0); | ||
| const MAX_FRAME_PAYLOAD_SIZE = 16 * 1024 * 1024; | ||
| const MAX_BUFFERED_BYTES = 32 * 1024 * 1024; | ||
| const MAX_STREAMS = 1024; | ||
| const MAX_FRAMES = 1e5; | ||
| import { FrameType } from "../constants.js"; | ||
| //#region src/client-rpc/frame-decoder.ts | ||
| /** | ||
| * Client-side frame decoder for multiplexed responses. | ||
| * | ||
| * Decodes binary frame protocol and reconstructs: | ||
| * - JSON stream (NDJSON lines for seroval) | ||
| * - Raw streams (binary data as ReadableStream<Uint8Array>) | ||
| */ | ||
| /** Cached TextDecoder for frame decoding */ | ||
| var textDecoder = new TextDecoder(); | ||
| /** Shared empty buffer for empty buffer case - avoids allocation */ | ||
| var EMPTY_BUFFER = new Uint8Array(0); | ||
| /** Hardening limits to prevent memory/CPU DoS */ | ||
| var MAX_FRAME_PAYLOAD_SIZE = 16 * 1024 * 1024; | ||
| var MAX_BUFFERED_BYTES = 32 * 1024 * 1024; | ||
| var MAX_STREAMS = 1024; | ||
| var MAX_FRAMES = 1e5; | ||
| /** | ||
| * Creates a frame decoder that processes a multiplexed response stream. | ||
| * | ||
| * @param input The raw response body stream | ||
| * @returns Decoded JSON stream and stream getter function | ||
| */ | ||
| function createFrameDecoder(input) { | ||
| const streamControllers = /* @__PURE__ */ new Map(); | ||
| const streams = /* @__PURE__ */ new Map(); | ||
| const cancelledStreamIds = /* @__PURE__ */ new Set(); | ||
| let cancelled = false; | ||
| let inputReader = null; | ||
| let frameCount = 0; | ||
| let jsonController; | ||
| const jsonChunks = new ReadableStream({ | ||
| start(controller) { | ||
| jsonController = controller; | ||
| }, | ||
| cancel() { | ||
| cancelled = true; | ||
| try { | ||
| inputReader?.cancel(); | ||
| } catch { | ||
| } | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.error(new Error("Framed response cancelled")); | ||
| } catch { | ||
| } | ||
| }); | ||
| streamControllers.clear(); | ||
| streams.clear(); | ||
| cancelledStreamIds.clear(); | ||
| } | ||
| }); | ||
| function getOrCreateStream(id) { | ||
| const existing = streams.get(id); | ||
| if (existing) { | ||
| return existing; | ||
| } | ||
| if (cancelledStreamIds.has(id)) { | ||
| return new ReadableStream({ | ||
| start(controller) { | ||
| controller.close(); | ||
| } | ||
| }); | ||
| } | ||
| if (streams.size >= MAX_STREAMS) { | ||
| throw new Error( | ||
| `Too many raw streams in framed response (max ${MAX_STREAMS})` | ||
| ); | ||
| } | ||
| const stream = new ReadableStream({ | ||
| start(ctrl) { | ||
| streamControllers.set(id, ctrl); | ||
| }, | ||
| cancel() { | ||
| cancelledStreamIds.add(id); | ||
| streamControllers.delete(id); | ||
| streams.delete(id); | ||
| } | ||
| }); | ||
| streams.set(id, stream); | ||
| return stream; | ||
| } | ||
| function ensureController(id) { | ||
| getOrCreateStream(id); | ||
| return streamControllers.get(id); | ||
| } | ||
| (async () => { | ||
| const reader = input.getReader(); | ||
| inputReader = reader; | ||
| const bufferList = []; | ||
| let totalLength = 0; | ||
| function readHeader() { | ||
| if (totalLength < FRAME_HEADER_SIZE) return null; | ||
| const first = bufferList[0]; | ||
| if (first.length >= FRAME_HEADER_SIZE) { | ||
| const type2 = first[0]; | ||
| const streamId2 = (first[1] << 24 | first[2] << 16 | first[3] << 8 | first[4]) >>> 0; | ||
| const length2 = (first[5] << 24 | first[6] << 16 | first[7] << 8 | first[8]) >>> 0; | ||
| return { type: type2, streamId: streamId2, length: length2 }; | ||
| } | ||
| const headerBytes = new Uint8Array(FRAME_HEADER_SIZE); | ||
| let offset = 0; | ||
| let remaining = FRAME_HEADER_SIZE; | ||
| for (let i = 0; i < bufferList.length && remaining > 0; i++) { | ||
| const chunk = bufferList[i]; | ||
| const toCopy = Math.min(chunk.length, remaining); | ||
| headerBytes.set(chunk.subarray(0, toCopy), offset); | ||
| offset += toCopy; | ||
| remaining -= toCopy; | ||
| } | ||
| const type = headerBytes[0]; | ||
| const streamId = (headerBytes[1] << 24 | headerBytes[2] << 16 | headerBytes[3] << 8 | headerBytes[4]) >>> 0; | ||
| const length = (headerBytes[5] << 24 | headerBytes[6] << 16 | headerBytes[7] << 8 | headerBytes[8]) >>> 0; | ||
| return { type, streamId, length }; | ||
| } | ||
| function extractFlattened(count) { | ||
| if (count === 0) return EMPTY_BUFFER; | ||
| const result = new Uint8Array(count); | ||
| let offset = 0; | ||
| let remaining = count; | ||
| while (remaining > 0 && bufferList.length > 0) { | ||
| const chunk = bufferList[0]; | ||
| if (!chunk) break; | ||
| const toCopy = Math.min(chunk.length, remaining); | ||
| result.set(chunk.subarray(0, toCopy), offset); | ||
| offset += toCopy; | ||
| remaining -= toCopy; | ||
| if (toCopy === chunk.length) { | ||
| bufferList.shift(); | ||
| } else { | ||
| bufferList[0] = chunk.subarray(toCopy); | ||
| } | ||
| } | ||
| totalLength -= count; | ||
| return result; | ||
| } | ||
| try { | ||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (cancelled) break; | ||
| if (done) break; | ||
| if (!value) continue; | ||
| if (totalLength + value.length > MAX_BUFFERED_BYTES) { | ||
| throw new Error( | ||
| `Framed response buffer exceeded ${MAX_BUFFERED_BYTES} bytes` | ||
| ); | ||
| } | ||
| bufferList.push(value); | ||
| totalLength += value.length; | ||
| while (true) { | ||
| const header = readHeader(); | ||
| if (!header) break; | ||
| const { type, streamId, length } = header; | ||
| if (type !== FrameType.JSON && type !== FrameType.CHUNK && type !== FrameType.END && type !== FrameType.ERROR) { | ||
| throw new Error(`Unknown frame type: ${type}`); | ||
| } | ||
| if (type === FrameType.JSON) { | ||
| if (streamId !== 0) { | ||
| throw new Error("Invalid JSON frame streamId (expected 0)"); | ||
| } | ||
| } else { | ||
| if (streamId === 0) { | ||
| throw new Error("Invalid raw frame streamId (expected non-zero)"); | ||
| } | ||
| } | ||
| if (length > MAX_FRAME_PAYLOAD_SIZE) { | ||
| throw new Error( | ||
| `Frame payload too large: ${length} bytes (max ${MAX_FRAME_PAYLOAD_SIZE})` | ||
| ); | ||
| } | ||
| const frameSize = FRAME_HEADER_SIZE + length; | ||
| if (totalLength < frameSize) break; | ||
| if (++frameCount > MAX_FRAMES) { | ||
| throw new Error( | ||
| `Too many frames in framed response (max ${MAX_FRAMES})` | ||
| ); | ||
| } | ||
| extractFlattened(FRAME_HEADER_SIZE); | ||
| const payload = extractFlattened(length); | ||
| switch (type) { | ||
| case FrameType.JSON: { | ||
| try { | ||
| jsonController.enqueue(textDecoder.decode(payload)); | ||
| } catch { | ||
| } | ||
| break; | ||
| } | ||
| case FrameType.CHUNK: { | ||
| const ctrl = ensureController(streamId); | ||
| if (ctrl) { | ||
| ctrl.enqueue(payload); | ||
| } | ||
| break; | ||
| } | ||
| case FrameType.END: { | ||
| const ctrl = ensureController(streamId); | ||
| cancelledStreamIds.add(streamId); | ||
| if (ctrl) { | ||
| try { | ||
| ctrl.close(); | ||
| } catch { | ||
| } | ||
| streamControllers.delete(streamId); | ||
| } | ||
| break; | ||
| } | ||
| case FrameType.ERROR: { | ||
| const ctrl = ensureController(streamId); | ||
| cancelledStreamIds.add(streamId); | ||
| if (ctrl) { | ||
| const message = textDecoder.decode(payload); | ||
| ctrl.error(new Error(message)); | ||
| streamControllers.delete(streamId); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (totalLength !== 0) { | ||
| throw new Error("Incomplete frame at end of framed response"); | ||
| } | ||
| try { | ||
| jsonController.close(); | ||
| } catch { | ||
| } | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.close(); | ||
| } catch { | ||
| } | ||
| }); | ||
| streamControllers.clear(); | ||
| } catch (error) { | ||
| try { | ||
| jsonController.error(error); | ||
| } catch { | ||
| } | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.error(error); | ||
| } catch { | ||
| } | ||
| }); | ||
| streamControllers.clear(); | ||
| } finally { | ||
| try { | ||
| reader.releaseLock(); | ||
| } catch { | ||
| } | ||
| inputReader = null; | ||
| } | ||
| })(); | ||
| return { getOrCreateStream, jsonChunks }; | ||
| const streamControllers = /* @__PURE__ */ new Map(); | ||
| const streams = /* @__PURE__ */ new Map(); | ||
| const cancelledStreamIds = /* @__PURE__ */ new Set(); | ||
| let cancelled = false; | ||
| let inputReader = null; | ||
| let frameCount = 0; | ||
| let jsonController; | ||
| const jsonChunks = new ReadableStream({ | ||
| start(controller) { | ||
| jsonController = controller; | ||
| }, | ||
| cancel() { | ||
| cancelled = true; | ||
| try { | ||
| inputReader?.cancel(); | ||
| } catch {} | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.error(/* @__PURE__ */ new Error("Framed response cancelled")); | ||
| } catch {} | ||
| }); | ||
| streamControllers.clear(); | ||
| streams.clear(); | ||
| cancelledStreamIds.clear(); | ||
| } | ||
| }); | ||
| /** | ||
| * Gets or creates a stream for a given stream ID. | ||
| * Called by deserialize plugin when it encounters a RawStream reference. | ||
| */ | ||
| function getOrCreateStream(id) { | ||
| const existing = streams.get(id); | ||
| if (existing) return existing; | ||
| if (cancelledStreamIds.has(id)) return new ReadableStream({ start(controller) { | ||
| controller.close(); | ||
| } }); | ||
| if (streams.size >= MAX_STREAMS) throw new Error(`Too many raw streams in framed response (max ${MAX_STREAMS})`); | ||
| const stream = new ReadableStream({ | ||
| start(ctrl) { | ||
| streamControllers.set(id, ctrl); | ||
| }, | ||
| cancel() { | ||
| cancelledStreamIds.add(id); | ||
| streamControllers.delete(id); | ||
| streams.delete(id); | ||
| } | ||
| }); | ||
| streams.set(id, stream); | ||
| return stream; | ||
| } | ||
| /** | ||
| * Ensures stream exists and returns its controller for enqueuing data. | ||
| * Used for CHUNK frames where we need to ensure stream is created. | ||
| */ | ||
| function ensureController(id) { | ||
| getOrCreateStream(id); | ||
| return streamControllers.get(id); | ||
| } | ||
| (async () => { | ||
| const reader = input.getReader(); | ||
| inputReader = reader; | ||
| const bufferList = []; | ||
| let totalLength = 0; | ||
| /** | ||
| * Reads header bytes from buffer chunks without flattening. | ||
| * Returns header data or null if not enough bytes available. | ||
| */ | ||
| function readHeader() { | ||
| if (totalLength < 9) return null; | ||
| const first = bufferList[0]; | ||
| if (first.length >= 9) return { | ||
| type: first[0], | ||
| streamId: (first[1] << 24 | first[2] << 16 | first[3] << 8 | first[4]) >>> 0, | ||
| length: (first[5] << 24 | first[6] << 16 | first[7] << 8 | first[8]) >>> 0 | ||
| }; | ||
| const headerBytes = new Uint8Array(9); | ||
| let offset = 0; | ||
| let remaining = 9; | ||
| for (let i = 0; i < bufferList.length && remaining > 0; i++) { | ||
| const chunk = bufferList[i]; | ||
| const toCopy = Math.min(chunk.length, remaining); | ||
| headerBytes.set(chunk.subarray(0, toCopy), offset); | ||
| offset += toCopy; | ||
| remaining -= toCopy; | ||
| } | ||
| return { | ||
| type: headerBytes[0], | ||
| streamId: (headerBytes[1] << 24 | headerBytes[2] << 16 | headerBytes[3] << 8 | headerBytes[4]) >>> 0, | ||
| length: (headerBytes[5] << 24 | headerBytes[6] << 16 | headerBytes[7] << 8 | headerBytes[8]) >>> 0 | ||
| }; | ||
| } | ||
| /** | ||
| * Flattens buffer list into single Uint8Array and removes from list. | ||
| */ | ||
| function extractFlattened(count) { | ||
| if (count === 0) return EMPTY_BUFFER; | ||
| const result = new Uint8Array(count); | ||
| let offset = 0; | ||
| let remaining = count; | ||
| while (remaining > 0 && bufferList.length > 0) { | ||
| const chunk = bufferList[0]; | ||
| if (!chunk) break; | ||
| const toCopy = Math.min(chunk.length, remaining); | ||
| result.set(chunk.subarray(0, toCopy), offset); | ||
| offset += toCopy; | ||
| remaining -= toCopy; | ||
| if (toCopy === chunk.length) bufferList.shift(); | ||
| else bufferList[0] = chunk.subarray(toCopy); | ||
| } | ||
| totalLength -= count; | ||
| return result; | ||
| } | ||
| try { | ||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (cancelled) break; | ||
| if (done) break; | ||
| if (!value) continue; | ||
| if (totalLength + value.length > MAX_BUFFERED_BYTES) throw new Error(`Framed response buffer exceeded ${MAX_BUFFERED_BYTES} bytes`); | ||
| bufferList.push(value); | ||
| totalLength += value.length; | ||
| while (true) { | ||
| const header = readHeader(); | ||
| if (!header) break; | ||
| const { type, streamId, length } = header; | ||
| if (type !== FrameType.JSON && type !== FrameType.CHUNK && type !== FrameType.END && type !== FrameType.ERROR) throw new Error(`Unknown frame type: ${type}`); | ||
| if (type === FrameType.JSON) { | ||
| if (streamId !== 0) throw new Error("Invalid JSON frame streamId (expected 0)"); | ||
| } else if (streamId === 0) throw new Error("Invalid raw frame streamId (expected non-zero)"); | ||
| if (length > MAX_FRAME_PAYLOAD_SIZE) throw new Error(`Frame payload too large: ${length} bytes (max ${MAX_FRAME_PAYLOAD_SIZE})`); | ||
| const frameSize = 9 + length; | ||
| if (totalLength < frameSize) break; | ||
| if (++frameCount > MAX_FRAMES) throw new Error(`Too many frames in framed response (max ${MAX_FRAMES})`); | ||
| extractFlattened(9); | ||
| const payload = extractFlattened(length); | ||
| switch (type) { | ||
| case FrameType.JSON: | ||
| try { | ||
| jsonController.enqueue(textDecoder.decode(payload)); | ||
| } catch {} | ||
| break; | ||
| case FrameType.CHUNK: { | ||
| const ctrl = ensureController(streamId); | ||
| if (ctrl) ctrl.enqueue(payload); | ||
| break; | ||
| } | ||
| case FrameType.END: { | ||
| const ctrl = ensureController(streamId); | ||
| cancelledStreamIds.add(streamId); | ||
| if (ctrl) { | ||
| try { | ||
| ctrl.close(); | ||
| } catch {} | ||
| streamControllers.delete(streamId); | ||
| } | ||
| break; | ||
| } | ||
| case FrameType.ERROR: { | ||
| const ctrl = ensureController(streamId); | ||
| cancelledStreamIds.add(streamId); | ||
| if (ctrl) { | ||
| const message = textDecoder.decode(payload); | ||
| ctrl.error(new Error(message)); | ||
| streamControllers.delete(streamId); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (totalLength !== 0) throw new Error("Incomplete frame at end of framed response"); | ||
| try { | ||
| jsonController.close(); | ||
| } catch {} | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.close(); | ||
| } catch {} | ||
| }); | ||
| streamControllers.clear(); | ||
| } catch (error) { | ||
| try { | ||
| jsonController.error(error); | ||
| } catch {} | ||
| streamControllers.forEach((ctrl) => { | ||
| try { | ||
| ctrl.error(error); | ||
| } catch {} | ||
| }); | ||
| streamControllers.clear(); | ||
| } finally { | ||
| try { | ||
| reader.releaseLock(); | ||
| } catch {} | ||
| inputReader = null; | ||
| } | ||
| })(); | ||
| return { | ||
| getOrCreateStream, | ||
| jsonChunks | ||
| }; | ||
| } | ||
| export { | ||
| createFrameDecoder | ||
| }; | ||
| //# sourceMappingURL=frame-decoder.js.map | ||
| //#endregion | ||
| export { createFrameDecoder }; | ||
| //# sourceMappingURL=frame-decoder.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"frame-decoder.js","sources":["../../../src/client-rpc/frame-decoder.ts"],"sourcesContent":["/**\n * Client-side frame decoder for multiplexed responses.\n *\n * Decodes binary frame protocol and reconstructs:\n * - JSON stream (NDJSON lines for seroval)\n * - Raw streams (binary data as ReadableStream<Uint8Array>)\n */\n\nimport { FRAME_HEADER_SIZE, FrameType } from '../constants'\n\n/** Cached TextDecoder for frame decoding */\nconst textDecoder = new TextDecoder()\n\n/** Shared empty buffer for empty buffer case - avoids allocation */\nconst EMPTY_BUFFER = new Uint8Array(0)\n\n/** Hardening limits to prevent memory/CPU DoS */\nconst MAX_FRAME_PAYLOAD_SIZE = 16 * 1024 * 1024 // 16MiB\nconst MAX_BUFFERED_BYTES = 32 * 1024 * 1024 // 32MiB\nconst MAX_STREAMS = 1024\nconst MAX_FRAMES = 100_000 // Limit total frames to prevent CPU DoS\n\n/**\n * Result of frame decoding.\n */\nexport interface FrameDecoderResult {\n /** Gets or creates a raw stream by ID (for use by deserialize plugin) */\n getOrCreateStream: (id: number) => ReadableStream<Uint8Array>\n /** Stream of JSON strings (NDJSON lines) */\n jsonChunks: ReadableStream<string>\n}\n\n/**\n * Creates a frame decoder that processes a multiplexed response stream.\n *\n * @param input The raw response body stream\n * @returns Decoded JSON stream and stream getter function\n */\nexport function createFrameDecoder(\n input: ReadableStream<Uint8Array>,\n): FrameDecoderResult {\n const streamControllers = new Map<\n number,\n ReadableStreamDefaultController<Uint8Array>\n >()\n const streams = new Map<number, ReadableStream<Uint8Array>>()\n const cancelledStreamIds = new Set<number>()\n\n let cancelled = false as boolean\n let inputReader: ReadableStreamReader<Uint8Array> | null = null\n let frameCount = 0\n\n let jsonController!: ReadableStreamDefaultController<string>\n const jsonChunks = new ReadableStream<string>({\n start(controller) {\n jsonController = controller\n },\n cancel() {\n cancelled = true\n try {\n inputReader?.cancel()\n } catch {\n // Ignore\n }\n\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.error(new Error('Framed response cancelled'))\n } catch {\n // Ignore\n }\n })\n streamControllers.clear()\n streams.clear()\n cancelledStreamIds.clear()\n },\n })\n\n /**\n * Gets or creates a stream for a given stream ID.\n * Called by deserialize plugin when it encounters a RawStream reference.\n */\n function getOrCreateStream(id: number): ReadableStream<Uint8Array> {\n const existing = streams.get(id)\n if (existing) {\n return existing\n }\n\n // If we already received an END/ERROR for this streamId, returning a fresh stream\n // would hang consumers. Return an already-closed stream instead.\n if (cancelledStreamIds.has(id)) {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close()\n },\n })\n }\n\n if (streams.size >= MAX_STREAMS) {\n throw new Error(\n `Too many raw streams in framed response (max ${MAX_STREAMS})`,\n )\n }\n\n const stream = new ReadableStream<Uint8Array>({\n start(ctrl) {\n streamControllers.set(id, ctrl)\n },\n cancel() {\n cancelledStreamIds.add(id)\n streamControllers.delete(id)\n streams.delete(id)\n },\n })\n streams.set(id, stream)\n return stream\n }\n\n /**\n * Ensures stream exists and returns its controller for enqueuing data.\n * Used for CHUNK frames where we need to ensure stream is created.\n */\n function ensureController(\n id: number,\n ): ReadableStreamDefaultController<Uint8Array> | undefined {\n getOrCreateStream(id)\n return streamControllers.get(id)\n }\n\n // Process frames asynchronously\n ;(async () => {\n const reader = input.getReader()\n inputReader = reader\n\n const bufferList: Array<Uint8Array> = []\n let totalLength = 0\n\n /**\n * Reads header bytes from buffer chunks without flattening.\n * Returns header data or null if not enough bytes available.\n */\n function readHeader(): {\n type: number\n streamId: number\n length: number\n } | null {\n if (totalLength < FRAME_HEADER_SIZE) return null\n\n const first = bufferList[0]!\n\n // Fast path: header fits entirely in first chunk (common case)\n if (first.length >= FRAME_HEADER_SIZE) {\n const type = first[0]!\n const streamId =\n ((first[1]! << 24) |\n (first[2]! << 16) |\n (first[3]! << 8) |\n first[4]!) >>>\n 0\n const length =\n ((first[5]! << 24) |\n (first[6]! << 16) |\n (first[7]! << 8) |\n first[8]!) >>>\n 0\n return { type, streamId, length }\n }\n\n // Slow path: header spans multiple chunks - flatten header bytes only\n const headerBytes = new Uint8Array(FRAME_HEADER_SIZE)\n let offset = 0\n let remaining = FRAME_HEADER_SIZE\n for (let i = 0; i < bufferList.length && remaining > 0; i++) {\n const chunk = bufferList[i]!\n const toCopy = Math.min(chunk.length, remaining)\n headerBytes.set(chunk.subarray(0, toCopy), offset)\n offset += toCopy\n remaining -= toCopy\n }\n\n const type = headerBytes[0]!\n const streamId =\n ((headerBytes[1]! << 24) |\n (headerBytes[2]! << 16) |\n (headerBytes[3]! << 8) |\n headerBytes[4]!) >>>\n 0\n const length =\n ((headerBytes[5]! << 24) |\n (headerBytes[6]! << 16) |\n (headerBytes[7]! << 8) |\n headerBytes[8]!) >>>\n 0\n\n return { type, streamId, length }\n }\n\n /**\n * Flattens buffer list into single Uint8Array and removes from list.\n */\n function extractFlattened(count: number): Uint8Array {\n if (count === 0) return EMPTY_BUFFER\n\n const result = new Uint8Array(count)\n let offset = 0\n let remaining = count\n\n while (remaining > 0 && bufferList.length > 0) {\n const chunk = bufferList[0]\n if (!chunk) break\n const toCopy = Math.min(chunk.length, remaining)\n result.set(chunk.subarray(0, toCopy), offset)\n\n offset += toCopy\n remaining -= toCopy\n\n if (toCopy === chunk.length) {\n bufferList.shift()\n } else {\n bufferList[0] = chunk.subarray(toCopy)\n }\n }\n\n totalLength -= count\n return result\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { done, value } = await reader.read()\n if (cancelled) break\n if (done) break\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!value) continue\n\n // Append incoming chunk to buffer list\n if (totalLength + value.length > MAX_BUFFERED_BYTES) {\n throw new Error(\n `Framed response buffer exceeded ${MAX_BUFFERED_BYTES} bytes`,\n )\n }\n bufferList.push(value)\n totalLength += value.length\n\n // Parse complete frames from buffer\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const header = readHeader()\n if (!header) break // Not enough bytes for header\n\n const { type, streamId, length } = header\n\n if (\n type !== FrameType.JSON &&\n type !== FrameType.CHUNK &&\n type !== FrameType.END &&\n type !== FrameType.ERROR\n ) {\n throw new Error(`Unknown frame type: ${type}`)\n }\n\n // Enforce stream id conventions: JSON uses streamId 0, raw streams use non-zero ids\n if (type === FrameType.JSON) {\n if (streamId !== 0) {\n throw new Error('Invalid JSON frame streamId (expected 0)')\n }\n } else {\n if (streamId === 0) {\n throw new Error('Invalid raw frame streamId (expected non-zero)')\n }\n }\n\n if (length > MAX_FRAME_PAYLOAD_SIZE) {\n throw new Error(\n `Frame payload too large: ${length} bytes (max ${MAX_FRAME_PAYLOAD_SIZE})`,\n )\n }\n\n const frameSize = FRAME_HEADER_SIZE + length\n if (totalLength < frameSize) break // Wait for more data\n\n if (++frameCount > MAX_FRAMES) {\n throw new Error(\n `Too many frames in framed response (max ${MAX_FRAMES})`,\n )\n }\n\n // Extract and consume header bytes\n extractFlattened(FRAME_HEADER_SIZE)\n\n // Extract payload\n const payload = extractFlattened(length)\n\n // Process frame by type\n switch (type) {\n case FrameType.JSON: {\n try {\n jsonController.enqueue(textDecoder.decode(payload))\n } catch {\n // JSON stream may be cancelled/closed\n }\n break\n }\n\n case FrameType.CHUNK: {\n const ctrl = ensureController(streamId)\n if (ctrl) {\n ctrl.enqueue(payload)\n }\n break\n }\n\n case FrameType.END: {\n const ctrl = ensureController(streamId)\n cancelledStreamIds.add(streamId)\n if (ctrl) {\n try {\n ctrl.close()\n } catch {\n // Already closed\n }\n streamControllers.delete(streamId)\n }\n break\n }\n\n case FrameType.ERROR: {\n const ctrl = ensureController(streamId)\n cancelledStreamIds.add(streamId)\n if (ctrl) {\n const message = textDecoder.decode(payload)\n ctrl.error(new Error(message))\n streamControllers.delete(streamId)\n }\n break\n }\n }\n }\n }\n\n if (totalLength !== 0) {\n throw new Error('Incomplete frame at end of framed response')\n }\n\n // Close JSON stream when done\n try {\n jsonController.close()\n } catch {\n // JSON stream may be cancelled/closed\n }\n\n // Close any remaining streams (shouldn't happen in normal operation)\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.close()\n } catch {\n // Already closed\n }\n })\n streamControllers.clear()\n } catch (error) {\n // Error reading - propagate to all streams\n try {\n jsonController.error(error)\n } catch {\n // Already errored/closed\n }\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.error(error)\n } catch {\n // Already errored/closed\n }\n })\n streamControllers.clear()\n } finally {\n try {\n reader.releaseLock()\n } catch {\n // Ignore\n }\n inputReader = null\n }\n })()\n\n return { getOrCreateStream, jsonChunks }\n}\n"],"names":["type","streamId","length"],"mappings":"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"} | ||
| {"version":3,"file":"frame-decoder.js","names":[],"sources":["../../../src/client-rpc/frame-decoder.ts"],"sourcesContent":["/**\n * Client-side frame decoder for multiplexed responses.\n *\n * Decodes binary frame protocol and reconstructs:\n * - JSON stream (NDJSON lines for seroval)\n * - Raw streams (binary data as ReadableStream<Uint8Array>)\n */\n\nimport { FRAME_HEADER_SIZE, FrameType } from '../constants'\n\n/** Cached TextDecoder for frame decoding */\nconst textDecoder = new TextDecoder()\n\n/** Shared empty buffer for empty buffer case - avoids allocation */\nconst EMPTY_BUFFER = new Uint8Array(0)\n\n/** Hardening limits to prevent memory/CPU DoS */\nconst MAX_FRAME_PAYLOAD_SIZE = 16 * 1024 * 1024 // 16MiB\nconst MAX_BUFFERED_BYTES = 32 * 1024 * 1024 // 32MiB\nconst MAX_STREAMS = 1024\nconst MAX_FRAMES = 100_000 // Limit total frames to prevent CPU DoS\n\n/**\n * Result of frame decoding.\n */\nexport interface FrameDecoderResult {\n /** Gets or creates a raw stream by ID (for use by deserialize plugin) */\n getOrCreateStream: (id: number) => ReadableStream<Uint8Array>\n /** Stream of JSON strings (NDJSON lines) */\n jsonChunks: ReadableStream<string>\n}\n\n/**\n * Creates a frame decoder that processes a multiplexed response stream.\n *\n * @param input The raw response body stream\n * @returns Decoded JSON stream and stream getter function\n */\nexport function createFrameDecoder(\n input: ReadableStream<Uint8Array>,\n): FrameDecoderResult {\n const streamControllers = new Map<\n number,\n ReadableStreamDefaultController<Uint8Array>\n >()\n const streams = new Map<number, ReadableStream<Uint8Array>>()\n const cancelledStreamIds = new Set<number>()\n\n let cancelled = false as boolean\n let inputReader: ReadableStreamReader<Uint8Array> | null = null\n let frameCount = 0\n\n let jsonController!: ReadableStreamDefaultController<string>\n const jsonChunks = new ReadableStream<string>({\n start(controller) {\n jsonController = controller\n },\n cancel() {\n cancelled = true\n try {\n inputReader?.cancel()\n } catch {\n // Ignore\n }\n\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.error(new Error('Framed response cancelled'))\n } catch {\n // Ignore\n }\n })\n streamControllers.clear()\n streams.clear()\n cancelledStreamIds.clear()\n },\n })\n\n /**\n * Gets or creates a stream for a given stream ID.\n * Called by deserialize plugin when it encounters a RawStream reference.\n */\n function getOrCreateStream(id: number): ReadableStream<Uint8Array> {\n const existing = streams.get(id)\n if (existing) {\n return existing\n }\n\n // If we already received an END/ERROR for this streamId, returning a fresh stream\n // would hang consumers. Return an already-closed stream instead.\n if (cancelledStreamIds.has(id)) {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close()\n },\n })\n }\n\n if (streams.size >= MAX_STREAMS) {\n throw new Error(\n `Too many raw streams in framed response (max ${MAX_STREAMS})`,\n )\n }\n\n const stream = new ReadableStream<Uint8Array>({\n start(ctrl) {\n streamControllers.set(id, ctrl)\n },\n cancel() {\n cancelledStreamIds.add(id)\n streamControllers.delete(id)\n streams.delete(id)\n },\n })\n streams.set(id, stream)\n return stream\n }\n\n /**\n * Ensures stream exists and returns its controller for enqueuing data.\n * Used for CHUNK frames where we need to ensure stream is created.\n */\n function ensureController(\n id: number,\n ): ReadableStreamDefaultController<Uint8Array> | undefined {\n getOrCreateStream(id)\n return streamControllers.get(id)\n }\n\n // Process frames asynchronously\n ;(async () => {\n const reader = input.getReader()\n inputReader = reader\n\n const bufferList: Array<Uint8Array> = []\n let totalLength = 0\n\n /**\n * Reads header bytes from buffer chunks without flattening.\n * Returns header data or null if not enough bytes available.\n */\n function readHeader(): {\n type: number\n streamId: number\n length: number\n } | null {\n if (totalLength < FRAME_HEADER_SIZE) return null\n\n const first = bufferList[0]!\n\n // Fast path: header fits entirely in first chunk (common case)\n if (first.length >= FRAME_HEADER_SIZE) {\n const type = first[0]!\n const streamId =\n ((first[1]! << 24) |\n (first[2]! << 16) |\n (first[3]! << 8) |\n first[4]!) >>>\n 0\n const length =\n ((first[5]! << 24) |\n (first[6]! << 16) |\n (first[7]! << 8) |\n first[8]!) >>>\n 0\n return { type, streamId, length }\n }\n\n // Slow path: header spans multiple chunks - flatten header bytes only\n const headerBytes = new Uint8Array(FRAME_HEADER_SIZE)\n let offset = 0\n let remaining = FRAME_HEADER_SIZE\n for (let i = 0; i < bufferList.length && remaining > 0; i++) {\n const chunk = bufferList[i]!\n const toCopy = Math.min(chunk.length, remaining)\n headerBytes.set(chunk.subarray(0, toCopy), offset)\n offset += toCopy\n remaining -= toCopy\n }\n\n const type = headerBytes[0]!\n const streamId =\n ((headerBytes[1]! << 24) |\n (headerBytes[2]! << 16) |\n (headerBytes[3]! << 8) |\n headerBytes[4]!) >>>\n 0\n const length =\n ((headerBytes[5]! << 24) |\n (headerBytes[6]! << 16) |\n (headerBytes[7]! << 8) |\n headerBytes[8]!) >>>\n 0\n\n return { type, streamId, length }\n }\n\n /**\n * Flattens buffer list into single Uint8Array and removes from list.\n */\n function extractFlattened(count: number): Uint8Array {\n if (count === 0) return EMPTY_BUFFER\n\n const result = new Uint8Array(count)\n let offset = 0\n let remaining = count\n\n while (remaining > 0 && bufferList.length > 0) {\n const chunk = bufferList[0]\n if (!chunk) break\n const toCopy = Math.min(chunk.length, remaining)\n result.set(chunk.subarray(0, toCopy), offset)\n\n offset += toCopy\n remaining -= toCopy\n\n if (toCopy === chunk.length) {\n bufferList.shift()\n } else {\n bufferList[0] = chunk.subarray(toCopy)\n }\n }\n\n totalLength -= count\n return result\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { done, value } = await reader.read()\n if (cancelled) break\n if (done) break\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!value) continue\n\n // Append incoming chunk to buffer list\n if (totalLength + value.length > MAX_BUFFERED_BYTES) {\n throw new Error(\n `Framed response buffer exceeded ${MAX_BUFFERED_BYTES} bytes`,\n )\n }\n bufferList.push(value)\n totalLength += value.length\n\n // Parse complete frames from buffer\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const header = readHeader()\n if (!header) break // Not enough bytes for header\n\n const { type, streamId, length } = header\n\n if (\n type !== FrameType.JSON &&\n type !== FrameType.CHUNK &&\n type !== FrameType.END &&\n type !== FrameType.ERROR\n ) {\n throw new Error(`Unknown frame type: ${type}`)\n }\n\n // Enforce stream id conventions: JSON uses streamId 0, raw streams use non-zero ids\n if (type === FrameType.JSON) {\n if (streamId !== 0) {\n throw new Error('Invalid JSON frame streamId (expected 0)')\n }\n } else {\n if (streamId === 0) {\n throw new Error('Invalid raw frame streamId (expected non-zero)')\n }\n }\n\n if (length > MAX_FRAME_PAYLOAD_SIZE) {\n throw new Error(\n `Frame payload too large: ${length} bytes (max ${MAX_FRAME_PAYLOAD_SIZE})`,\n )\n }\n\n const frameSize = FRAME_HEADER_SIZE + length\n if (totalLength < frameSize) break // Wait for more data\n\n if (++frameCount > MAX_FRAMES) {\n throw new Error(\n `Too many frames in framed response (max ${MAX_FRAMES})`,\n )\n }\n\n // Extract and consume header bytes\n extractFlattened(FRAME_HEADER_SIZE)\n\n // Extract payload\n const payload = extractFlattened(length)\n\n // Process frame by type\n switch (type) {\n case FrameType.JSON: {\n try {\n jsonController.enqueue(textDecoder.decode(payload))\n } catch {\n // JSON stream may be cancelled/closed\n }\n break\n }\n\n case FrameType.CHUNK: {\n const ctrl = ensureController(streamId)\n if (ctrl) {\n ctrl.enqueue(payload)\n }\n break\n }\n\n case FrameType.END: {\n const ctrl = ensureController(streamId)\n cancelledStreamIds.add(streamId)\n if (ctrl) {\n try {\n ctrl.close()\n } catch {\n // Already closed\n }\n streamControllers.delete(streamId)\n }\n break\n }\n\n case FrameType.ERROR: {\n const ctrl = ensureController(streamId)\n cancelledStreamIds.add(streamId)\n if (ctrl) {\n const message = textDecoder.decode(payload)\n ctrl.error(new Error(message))\n streamControllers.delete(streamId)\n }\n break\n }\n }\n }\n }\n\n if (totalLength !== 0) {\n throw new Error('Incomplete frame at end of framed response')\n }\n\n // Close JSON stream when done\n try {\n jsonController.close()\n } catch {\n // JSON stream may be cancelled/closed\n }\n\n // Close any remaining streams (shouldn't happen in normal operation)\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.close()\n } catch {\n // Already closed\n }\n })\n streamControllers.clear()\n } catch (error) {\n // Error reading - propagate to all streams\n try {\n jsonController.error(error)\n } catch {\n // Already errored/closed\n }\n streamControllers.forEach((ctrl) => {\n try {\n ctrl.error(error)\n } catch {\n // Already errored/closed\n }\n })\n streamControllers.clear()\n } finally {\n try {\n reader.releaseLock()\n } catch {\n // Ignore\n }\n inputReader = null\n }\n })()\n\n return { getOrCreateStream, jsonChunks }\n}\n"],"mappings":"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"} |
| import { createClientRpc } from "./createClientRpc.js"; | ||
| export { | ||
| createClientRpc | ||
| }; | ||
| //# sourceMappingURL=index.js.map | ||
| export { createClientRpc }; |
@@ -1,275 +0,226 @@ | ||
| import { encode, createRawStreamDeserializePlugin, parseRedirect, isNotFound } from "@tanstack/router-core"; | ||
| import { TSS_CONTENT_TYPE_FRAMED, TSS_FORMDATA_CONTEXT, validateFramedProtocolVersion } from "../constants.js"; | ||
| import { getDefaultSerovalPlugins } from "../getDefaultSerovalPlugins.js"; | ||
| import { createFrameDecoder } from "./frame-decoder.js"; | ||
| import { createRawStreamDeserializePlugin, encode, isNotFound, parseRedirect } from "@tanstack/router-core"; | ||
| import { fromCrossJSON, toJSONAsync } from "seroval"; | ||
| import invariant from "tiny-invariant"; | ||
| import { getDefaultSerovalPlugins } from "../getDefaultSerovalPlugins.js"; | ||
| import { TSS_CONTENT_TYPE_FRAMED, TSS_FORMDATA_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, validateFramedProtocolVersion } from "../constants.js"; | ||
| import { createFrameDecoder } from "./frame-decoder.js"; | ||
| let serovalPlugins = null; | ||
| const hop = Object.prototype.hasOwnProperty; | ||
| //#region src/client-rpc/serverFnFetcher.ts | ||
| var serovalPlugins = null; | ||
| /** | ||
| * Checks if an object has at least one own enumerable property. | ||
| * More efficient than Object.keys(obj).length > 0 as it short-circuits on first property. | ||
| */ | ||
| var hop = Object.prototype.hasOwnProperty; | ||
| function hasOwnProperties(obj) { | ||
| for (const _ in obj) { | ||
| if (hop.call(obj, _)) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| for (const _ in obj) if (hop.call(obj, _)) return true; | ||
| return false; | ||
| } | ||
| async function serverFnFetcher(url, args, handler) { | ||
| if (!serovalPlugins) { | ||
| serovalPlugins = getDefaultSerovalPlugins(); | ||
| } | ||
| const _first = args[0]; | ||
| const first = _first; | ||
| const fetchImpl = first.fetch ?? handler; | ||
| const type = first.data instanceof FormData ? "formData" : "payload"; | ||
| const headers = first.headers ? new Headers(first.headers) : new Headers(); | ||
| headers.set("x-tsr-serverFn", "true"); | ||
| if (type === "payload") { | ||
| headers.set( | ||
| "accept", | ||
| `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json` | ||
| ); | ||
| } | ||
| if (first.method === "GET") { | ||
| if (type === "formData") { | ||
| throw new Error("FormData is not supported with GET requests"); | ||
| } | ||
| const serializedPayload = await serializePayload(first); | ||
| if (serializedPayload !== void 0) { | ||
| const encodedPayload = encode({ | ||
| payload: serializedPayload | ||
| }); | ||
| if (url.includes("?")) { | ||
| url += `&${encodedPayload}`; | ||
| } else { | ||
| url += `?${encodedPayload}`; | ||
| } | ||
| } | ||
| } | ||
| let body = void 0; | ||
| if (first.method === "POST") { | ||
| const fetchBody = await getFetchBody(first); | ||
| if (fetchBody?.contentType) { | ||
| headers.set("content-type", fetchBody.contentType); | ||
| } | ||
| body = fetchBody?.body; | ||
| } | ||
| return await getResponse( | ||
| async () => fetchImpl(url, { | ||
| method: first.method, | ||
| headers, | ||
| signal: first.signal, | ||
| body | ||
| }) | ||
| ); | ||
| if (!serovalPlugins) serovalPlugins = getDefaultSerovalPlugins(); | ||
| const first = args[0]; | ||
| const fetchImpl = first.fetch ?? handler; | ||
| const type = first.data instanceof FormData ? "formData" : "payload"; | ||
| const headers = first.headers ? new Headers(first.headers) : new Headers(); | ||
| headers.set("x-tsr-serverFn", "true"); | ||
| if (type === "payload") headers.set("accept", `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json`); | ||
| if (first.method === "GET") { | ||
| if (type === "formData") throw new Error("FormData is not supported with GET requests"); | ||
| const serializedPayload = await serializePayload(first); | ||
| if (serializedPayload !== void 0) { | ||
| const encodedPayload = encode({ payload: serializedPayload }); | ||
| if (url.includes("?")) url += `&${encodedPayload}`; | ||
| else url += `?${encodedPayload}`; | ||
| } | ||
| } | ||
| let body = void 0; | ||
| if (first.method === "POST") { | ||
| const fetchBody = await getFetchBody(first); | ||
| if (fetchBody?.contentType) headers.set("content-type", fetchBody.contentType); | ||
| body = fetchBody?.body; | ||
| } | ||
| return await getResponse(async () => fetchImpl(url, { | ||
| method: first.method, | ||
| headers, | ||
| signal: first.signal, | ||
| body | ||
| })); | ||
| } | ||
| async function serializePayload(opts) { | ||
| let payloadAvailable = false; | ||
| const payloadToSerialize = {}; | ||
| if (opts.data !== void 0) { | ||
| payloadAvailable = true; | ||
| payloadToSerialize["data"] = opts.data; | ||
| } | ||
| if (opts.context && hasOwnProperties(opts.context)) { | ||
| payloadAvailable = true; | ||
| payloadToSerialize["context"] = opts.context; | ||
| } | ||
| if (payloadAvailable) { | ||
| return serialize(payloadToSerialize); | ||
| } | ||
| return void 0; | ||
| let payloadAvailable = false; | ||
| const payloadToSerialize = {}; | ||
| if (opts.data !== void 0) { | ||
| payloadAvailable = true; | ||
| payloadToSerialize["data"] = opts.data; | ||
| } | ||
| if (opts.context && hasOwnProperties(opts.context)) { | ||
| payloadAvailable = true; | ||
| payloadToSerialize["context"] = opts.context; | ||
| } | ||
| if (payloadAvailable) return serialize(payloadToSerialize); | ||
| } | ||
| async function serialize(data) { | ||
| return JSON.stringify( | ||
| await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins })) | ||
| ); | ||
| return JSON.stringify(await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins }))); | ||
| } | ||
| async function getFetchBody(opts) { | ||
| if (opts.data instanceof FormData) { | ||
| let serializedContext = void 0; | ||
| if (opts.context && hasOwnProperties(opts.context)) { | ||
| serializedContext = await serialize(opts.context); | ||
| } | ||
| if (serializedContext !== void 0) { | ||
| opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext); | ||
| } | ||
| return { body: opts.data }; | ||
| } | ||
| const serializedBody = await serializePayload(opts); | ||
| if (serializedBody) { | ||
| return { body: serializedBody, contentType: "application/json" }; | ||
| } | ||
| return void 0; | ||
| if (opts.data instanceof FormData) { | ||
| let serializedContext = void 0; | ||
| if (opts.context && hasOwnProperties(opts.context)) serializedContext = await serialize(opts.context); | ||
| if (serializedContext !== void 0) opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext); | ||
| return { body: opts.data }; | ||
| } | ||
| const serializedBody = await serializePayload(opts); | ||
| if (serializedBody) return { | ||
| body: serializedBody, | ||
| contentType: "application/json" | ||
| }; | ||
| } | ||
| /** | ||
| * Retrieves a response from a given function and manages potential errors | ||
| * and special response types including redirects and not found errors. | ||
| * | ||
| * @param fn - The function to execute for obtaining the response. | ||
| * @returns The processed response from the function. | ||
| * @throws If the response is invalid or an error occurs during processing. | ||
| */ | ||
| async function getResponse(fn) { | ||
| let response; | ||
| try { | ||
| response = await fn(); | ||
| } catch (error) { | ||
| if (error instanceof Response) { | ||
| response = error; | ||
| } else { | ||
| console.log(error); | ||
| throw error; | ||
| } | ||
| } | ||
| if (response.headers.get(X_TSS_RAW_RESPONSE) === "true") { | ||
| return response; | ||
| } | ||
| const contentType = response.headers.get("content-type"); | ||
| invariant(contentType, "expected content-type header to be set"); | ||
| const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED); | ||
| if (serializedByStart) { | ||
| let result; | ||
| if (contentType.includes(TSS_CONTENT_TYPE_FRAMED)) { | ||
| validateFramedProtocolVersion(contentType); | ||
| if (!response.body) { | ||
| throw new Error("No response body for framed response"); | ||
| } | ||
| const { getOrCreateStream, jsonChunks } = createFrameDecoder( | ||
| response.body | ||
| ); | ||
| const rawStreamPlugin = createRawStreamDeserializePlugin(getOrCreateStream); | ||
| const plugins = [rawStreamPlugin, ...serovalPlugins || []]; | ||
| const refs = /* @__PURE__ */ new Map(); | ||
| result = await processFramedResponse({ | ||
| jsonStream: jsonChunks, | ||
| onMessage: (msg) => fromCrossJSON(msg, { refs, plugins }), | ||
| onError(msg, error) { | ||
| console.error(msg, error); | ||
| } | ||
| }); | ||
| } else if (contentType.includes("application/x-ndjson")) { | ||
| const refs = /* @__PURE__ */ new Map(); | ||
| result = await processServerFnResponse({ | ||
| response, | ||
| onMessage: (msg) => fromCrossJSON(msg, { refs, plugins: serovalPlugins }), | ||
| onError(msg, error) { | ||
| console.error(msg, error); | ||
| } | ||
| }); | ||
| } else if (contentType.includes("application/json")) { | ||
| const jsonPayload = await response.json(); | ||
| result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins }); | ||
| } | ||
| invariant(result, "expected result to be resolved"); | ||
| if (result instanceof Error) { | ||
| throw result; | ||
| } | ||
| return result; | ||
| } | ||
| if (contentType.includes("application/json")) { | ||
| const jsonPayload = await response.json(); | ||
| const redirect = parseRedirect(jsonPayload); | ||
| if (redirect) { | ||
| throw redirect; | ||
| } | ||
| if (isNotFound(jsonPayload)) { | ||
| throw jsonPayload; | ||
| } | ||
| return jsonPayload; | ||
| } | ||
| if (!response.ok) { | ||
| throw new Error(await response.text()); | ||
| } | ||
| return response; | ||
| let response; | ||
| try { | ||
| response = await fn(); | ||
| } catch (error) { | ||
| if (error instanceof Response) response = error; | ||
| else { | ||
| console.log(error); | ||
| throw error; | ||
| } | ||
| } | ||
| if (response.headers.get("x-tss-raw") === "true") return response; | ||
| const contentType = response.headers.get("content-type"); | ||
| invariant(contentType, "expected content-type header to be set"); | ||
| if (!!response.headers.get("x-tss-serialized")) { | ||
| let result; | ||
| if (contentType.includes("application/x-tss-framed")) { | ||
| validateFramedProtocolVersion(contentType); | ||
| if (!response.body) throw new Error("No response body for framed response"); | ||
| const { getOrCreateStream, jsonChunks } = createFrameDecoder(response.body); | ||
| const plugins = [createRawStreamDeserializePlugin(getOrCreateStream), ...serovalPlugins || []]; | ||
| const refs = /* @__PURE__ */ new Map(); | ||
| result = await processFramedResponse({ | ||
| jsonStream: jsonChunks, | ||
| onMessage: (msg) => fromCrossJSON(msg, { | ||
| refs, | ||
| plugins | ||
| }), | ||
| onError(msg, error) { | ||
| console.error(msg, error); | ||
| } | ||
| }); | ||
| } else if (contentType.includes("application/x-ndjson")) { | ||
| const refs = /* @__PURE__ */ new Map(); | ||
| result = await processServerFnResponse({ | ||
| response, | ||
| onMessage: (msg) => fromCrossJSON(msg, { | ||
| refs, | ||
| plugins: serovalPlugins | ||
| }), | ||
| onError(msg, error) { | ||
| console.error(msg, error); | ||
| } | ||
| }); | ||
| } else if (contentType.includes("application/json")) result = fromCrossJSON(await response.json(), { plugins: serovalPlugins }); | ||
| invariant(result, "expected result to be resolved"); | ||
| if (result instanceof Error) throw result; | ||
| return result; | ||
| } | ||
| if (contentType.includes("application/json")) { | ||
| const jsonPayload = await response.json(); | ||
| const redirect = parseRedirect(jsonPayload); | ||
| if (redirect) throw redirect; | ||
| if (isNotFound(jsonPayload)) throw jsonPayload; | ||
| return jsonPayload; | ||
| } | ||
| if (!response.ok) throw new Error(await response.text()); | ||
| return response; | ||
| } | ||
| async function processServerFnResponse({ | ||
| response, | ||
| onMessage, | ||
| onError | ||
| }) { | ||
| if (!response.body) { | ||
| throw new Error("No response body"); | ||
| } | ||
| const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); | ||
| let buffer = ""; | ||
| let firstRead = false; | ||
| let firstObject; | ||
| while (!firstRead) { | ||
| const { value, done } = await reader.read(); | ||
| if (value) buffer += value; | ||
| if (buffer.length === 0 && done) { | ||
| throw new Error("Stream ended before first object"); | ||
| } | ||
| if (buffer.endsWith("\n")) { | ||
| const lines = buffer.split("\n").filter(Boolean); | ||
| const firstLine = lines[0]; | ||
| if (!firstLine) throw new Error("No JSON line in the first chunk"); | ||
| firstObject = JSON.parse(firstLine); | ||
| firstRead = true; | ||
| buffer = lines.slice(1).join("\n"); | ||
| } else { | ||
| const newlineIndex = buffer.indexOf("\n"); | ||
| if (newlineIndex >= 0) { | ||
| const line = buffer.slice(0, newlineIndex).trim(); | ||
| buffer = buffer.slice(newlineIndex + 1); | ||
| if (line.length > 0) { | ||
| firstObject = JSON.parse(line); | ||
| firstRead = true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| (async () => { | ||
| try { | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (value) buffer += value; | ||
| const lastNewline = buffer.lastIndexOf("\n"); | ||
| if (lastNewline >= 0) { | ||
| const chunk = buffer.slice(0, lastNewline); | ||
| buffer = buffer.slice(lastNewline + 1); | ||
| const lines = chunk.split("\n").filter(Boolean); | ||
| for (const line of lines) { | ||
| try { | ||
| onMessage(JSON.parse(line)); | ||
| } catch (e) { | ||
| onError?.(`Invalid JSON line: ${line}`, e); | ||
| } | ||
| } | ||
| } | ||
| if (done) { | ||
| break; | ||
| } | ||
| } | ||
| } catch (err) { | ||
| onError?.("Stream processing error:", err); | ||
| } | ||
| })(); | ||
| return onMessage(firstObject); | ||
| async function processServerFnResponse({ response, onMessage, onError }) { | ||
| if (!response.body) throw new Error("No response body"); | ||
| const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); | ||
| let buffer = ""; | ||
| let firstRead = false; | ||
| let firstObject; | ||
| while (!firstRead) { | ||
| const { value, done } = await reader.read(); | ||
| if (value) buffer += value; | ||
| if (buffer.length === 0 && done) throw new Error("Stream ended before first object"); | ||
| if (buffer.endsWith("\n")) { | ||
| const lines = buffer.split("\n").filter(Boolean); | ||
| const firstLine = lines[0]; | ||
| if (!firstLine) throw new Error("No JSON line in the first chunk"); | ||
| firstObject = JSON.parse(firstLine); | ||
| firstRead = true; | ||
| buffer = lines.slice(1).join("\n"); | ||
| } else { | ||
| const newlineIndex = buffer.indexOf("\n"); | ||
| if (newlineIndex >= 0) { | ||
| const line = buffer.slice(0, newlineIndex).trim(); | ||
| buffer = buffer.slice(newlineIndex + 1); | ||
| if (line.length > 0) { | ||
| firstObject = JSON.parse(line); | ||
| firstRead = true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| (async () => { | ||
| try { | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (value) buffer += value; | ||
| const lastNewline = buffer.lastIndexOf("\n"); | ||
| if (lastNewline >= 0) { | ||
| const chunk = buffer.slice(0, lastNewline); | ||
| buffer = buffer.slice(lastNewline + 1); | ||
| const lines = chunk.split("\n").filter(Boolean); | ||
| for (const line of lines) try { | ||
| onMessage(JSON.parse(line)); | ||
| } catch (e) { | ||
| onError?.(`Invalid JSON line: ${line}`, e); | ||
| } | ||
| } | ||
| if (done) break; | ||
| } | ||
| } catch (err) { | ||
| onError?.("Stream processing error:", err); | ||
| } | ||
| })(); | ||
| return onMessage(firstObject); | ||
| } | ||
| async function processFramedResponse({ | ||
| jsonStream, | ||
| onMessage, | ||
| onError | ||
| }) { | ||
| const reader = jsonStream.getReader(); | ||
| const { value: firstValue, done: firstDone } = await reader.read(); | ||
| if (firstDone || !firstValue) { | ||
| throw new Error("Stream ended before first object"); | ||
| } | ||
| const firstObject = JSON.parse(firstValue); | ||
| (async () => { | ||
| try { | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| if (value) { | ||
| try { | ||
| onMessage(JSON.parse(value)); | ||
| } catch (e) { | ||
| onError?.(`Invalid JSON: ${value}`, e); | ||
| } | ||
| } | ||
| } | ||
| } catch (err) { | ||
| onError?.("Stream processing error:", err); | ||
| } | ||
| })(); | ||
| return onMessage(firstObject); | ||
| /** | ||
| * Processes a framed response where each JSON chunk is a complete JSON string | ||
| * (already decoded by frame decoder). | ||
| */ | ||
| async function processFramedResponse({ jsonStream, onMessage, onError }) { | ||
| const reader = jsonStream.getReader(); | ||
| const { value: firstValue, done: firstDone } = await reader.read(); | ||
| if (firstDone || !firstValue) throw new Error("Stream ended before first object"); | ||
| const firstObject = JSON.parse(firstValue); | ||
| (async () => { | ||
| try { | ||
| while (true) { | ||
| const { value, done } = await reader.read(); | ||
| if (done) break; | ||
| if (value) try { | ||
| onMessage(JSON.parse(value)); | ||
| } catch (e) { | ||
| onError?.(`Invalid JSON: ${value}`, e); | ||
| } | ||
| } | ||
| } catch (err) { | ||
| onError?.("Stream processing error:", err); | ||
| } | ||
| })(); | ||
| return onMessage(firstObject); | ||
| } | ||
| export { | ||
| serverFnFetcher | ||
| }; | ||
| //# sourceMappingURL=serverFnFetcher.js.map | ||
| //#endregion | ||
| export { serverFnFetcher }; | ||
| //# sourceMappingURL=serverFnFetcher.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"serverFnFetcher.js","sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n createRawStreamDeserializePlugin,\n encode,\n isNotFound,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport {\n TSS_CONTENT_TYPE_FRAMED,\n TSS_FORMDATA_CONTEXT,\n X_TSS_RAW_RESPONSE,\n X_TSS_SERIALIZED,\n validateFramedProtocolVersion,\n} from '../constants'\nimport { createFrameDecoder } from './frame-decoder'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\n\n/**\n * Checks if an object has at least one own enumerable property.\n * More efficient than Object.keys(obj).length > 0 as it short-circuits on first property.\n */\nconst hop = Object.prototype.hasOwnProperty\nfunction hasOwnProperties(obj: object): boolean {\n for (const _ in obj) {\n if (hop.call(obj, _)) {\n return true\n }\n }\n return false\n}\n// caller =>\n// serverFnFetcher =>\n// client =>\n// server =>\n// fn =>\n// seroval =>\n// client middleware =>\n// serverFnFetcher =>\n// caller\n\nexport async function serverFnFetcher(\n url: string,\n args: Array<any>,\n handler: (url: string, requestInit: RequestInit) => Promise<Response>,\n) {\n if (!serovalPlugins) {\n serovalPlugins = getDefaultSerovalPlugins()\n }\n const _first = args[0]\n\n const first = _first as FunctionMiddlewareClientFnOptions<any, any, any> & {\n headers?: HeadersInit\n }\n\n // Use custom fetch if provided, otherwise fall back to the passed handler (global fetch)\n const fetchImpl = first.fetch ?? handler\n\n const type = first.data instanceof FormData ? 'formData' : 'payload'\n\n // Arrange the headers\n const headers = first.headers ? new Headers(first.headers) : new Headers()\n headers.set('x-tsr-serverFn', 'true')\n\n if (type === 'payload') {\n headers.set(\n 'accept',\n `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json`,\n )\n }\n\n // If the method is GET, we need to move the payload to the query string\n if (first.method === 'GET') {\n if (type === 'formData') {\n throw new Error('FormData is not supported with GET requests')\n }\n const serializedPayload = await serializePayload(first)\n if (serializedPayload !== undefined) {\n const encodedPayload = encode({\n payload: serializedPayload,\n })\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n let body = undefined\n if (first.method === 'POST') {\n const fetchBody = await getFetchBody(first)\n if (fetchBody?.contentType) {\n headers.set('content-type', fetchBody.contentType)\n }\n body = fetchBody?.body\n }\n\n return await getResponse(async () =>\n fetchImpl(url, {\n method: first.method,\n headers,\n signal: first.signal,\n body,\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<string | undefined> {\n let payloadAvailable = false\n const payloadToSerialize: any = {}\n if (opts.data !== undefined) {\n payloadAvailable = true\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n payloadAvailable = true\n payloadToSerialize['context'] = opts.context\n }\n\n if (payloadAvailable) {\n return serialize(payloadToSerialize)\n }\n return undefined\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetchBody(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<{ body: FormData | string; contentType?: string } | undefined> {\n if (opts.data instanceof FormData) {\n let serializedContext = undefined\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n serializedContext = await serialize(opts.context)\n }\n if (serializedContext !== undefined) {\n opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext)\n }\n return { body: opts.data }\n }\n const serializedBody = await serializePayload(opts)\n if (serializedBody) {\n return { body: serializedBody, contentType: 'application/json' }\n }\n return undefined\n}\n\n/**\n * Retrieves a response from a given function and manages potential errors\n * and special response types including redirects and not found errors.\n *\n * @param fn - The function to execute for obtaining the response.\n * @returns The processed response from the function.\n * @throws If the response is invalid or an error occurs during processing.\n */\nasync function getResponse(fn: () => Promise<Response>) {\n let response: Response\n try {\n response = await fn() // client => server => fn => server => client\n } catch (error) {\n if (error instanceof Response) {\n response = error\n } else {\n console.log(error)\n throw error\n }\n }\n\n if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {\n return response\n }\n\n const contentType = response.headers.get('content-type')\n invariant(contentType, 'expected content-type header to be set')\n const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED)\n\n // If the response is serialized by the start server, we need to process it\n // differently than a normal response.\n if (serializedByStart) {\n let result\n\n // If it's a framed response (contains RawStream), use frame decoder\n if (contentType.includes(TSS_CONTENT_TYPE_FRAMED)) {\n // Validate protocol version compatibility\n validateFramedProtocolVersion(contentType)\n\n if (!response.body) {\n throw new Error('No response body for framed response')\n }\n\n const { getOrCreateStream, jsonChunks } = createFrameDecoder(\n response.body,\n )\n\n // Create deserialize plugin that wires up the raw streams\n const rawStreamPlugin =\n createRawStreamDeserializePlugin(getOrCreateStream)\n const plugins = [rawStreamPlugin, ...(serovalPlugins || [])]\n\n const refs = new Map()\n result = await processFramedResponse({\n jsonStream: jsonChunks,\n onMessage: (msg: any) => fromCrossJSON(msg, { refs, plugins }),\n onError(msg, error) {\n console.error(msg, error)\n },\n })\n }\n // If it's a stream from the start serializer, process it as such\n else if (contentType.includes('application/x-ndjson')) {\n const refs = new Map()\n result = await processServerFnResponse({\n response,\n onMessage: (msg) =>\n fromCrossJSON(msg, { refs, plugins: serovalPlugins! }),\n onError(msg, error) {\n // TODO how could we notify consumer that an error occurred?\n console.error(msg, error)\n },\n })\n }\n // If it's a JSON response, it can be simpler\n else if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n\n return result\n }\n\n // If it wasn't processed by the start serializer, check\n // if it's JSON\n if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const redirect = parseRedirect(jsonPayload)\n if (redirect) {\n throw redirect\n }\n if (isNotFound(jsonPayload)) {\n throw jsonPayload\n }\n return jsonPayload\n }\n\n // Otherwise, if it's not OK, throw the content\n if (!response.ok) {\n throw new Error(await response.text())\n }\n\n // Or return the response itself\n return response\n}\n\nasync function processServerFnResponse({\n response,\n onMessage,\n onError,\n}: {\n response: Response\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n if (!response.body) {\n throw new Error('No response body')\n }\n\n const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()\n\n let buffer = ''\n let firstRead = false\n let firstObject\n\n while (!firstRead) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n if (buffer.length === 0 && done) {\n throw new Error('Stream ended before first object')\n }\n\n // common case: buffer ends with newline\n if (buffer.endsWith('\\n')) {\n const lines = buffer.split('\\n').filter(Boolean)\n const firstLine = lines[0]\n if (!firstLine) throw new Error('No JSON line in the first chunk')\n firstObject = JSON.parse(firstLine)\n firstRead = true\n buffer = lines.slice(1).join('\\n')\n } else {\n // fallback: wait for a newline to parse first object safely\n const newlineIndex = buffer.indexOf('\\n')\n if (newlineIndex >= 0) {\n const line = buffer.slice(0, newlineIndex).trim()\n buffer = buffer.slice(newlineIndex + 1)\n if (line.length > 0) {\n firstObject = JSON.parse(line)\n firstRead = true\n }\n }\n }\n }\n\n // process rest of the stream asynchronously\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n const lastNewline = buffer.lastIndexOf('\\n')\n if (lastNewline >= 0) {\n const chunk = buffer.slice(0, lastNewline)\n buffer = buffer.slice(lastNewline + 1)\n const lines = chunk.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n try {\n onMessage(JSON.parse(line))\n } catch (e) {\n onError?.(`Invalid JSON line: ${line}`, e)\n }\n }\n }\n\n if (done) {\n break\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n\n/**\n * Processes a framed response where each JSON chunk is a complete JSON string\n * (already decoded by frame decoder).\n */\nasync function processFramedResponse({\n jsonStream,\n onMessage,\n onError,\n}: {\n jsonStream: ReadableStream<string>\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n const reader = jsonStream.getReader()\n\n // Read first JSON frame - this is the main result\n const { value: firstValue, done: firstDone } = await reader.read()\n if (firstDone || !firstValue) {\n throw new Error('Stream ended before first object')\n }\n\n // Each frame is a complete JSON string\n const firstObject = JSON.parse(firstValue)\n\n // Process remaining frames asynchronously (for streaming refs like RawStream)\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n try {\n onMessage(JSON.parse(value))\n } catch (e) {\n onError?.(`Invalid JSON: ${value}`, e)\n }\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"serverFnFetcher.js","names":[],"sources":["../../../src/client-rpc/serverFnFetcher.ts"],"sourcesContent":["import {\n createRawStreamDeserializePlugin,\n encode,\n isNotFound,\n parseRedirect,\n} from '@tanstack/router-core'\nimport { fromCrossJSON, toJSONAsync } from 'seroval'\nimport invariant from 'tiny-invariant'\nimport { getDefaultSerovalPlugins } from '../getDefaultSerovalPlugins'\nimport {\n TSS_CONTENT_TYPE_FRAMED,\n TSS_FORMDATA_CONTEXT,\n X_TSS_RAW_RESPONSE,\n X_TSS_SERIALIZED,\n validateFramedProtocolVersion,\n} from '../constants'\nimport { createFrameDecoder } from './frame-decoder'\nimport type { FunctionMiddlewareClientFnOptions } from '../createMiddleware'\nimport type { Plugin as SerovalPlugin } from 'seroval'\n\nlet serovalPlugins: Array<SerovalPlugin<any, any>> | null = null\n\n/**\n * Checks if an object has at least one own enumerable property.\n * More efficient than Object.keys(obj).length > 0 as it short-circuits on first property.\n */\nconst hop = Object.prototype.hasOwnProperty\nfunction hasOwnProperties(obj: object): boolean {\n for (const _ in obj) {\n if (hop.call(obj, _)) {\n return true\n }\n }\n return false\n}\n// caller =>\n// serverFnFetcher =>\n// client =>\n// server =>\n// fn =>\n// seroval =>\n// client middleware =>\n// serverFnFetcher =>\n// caller\n\nexport async function serverFnFetcher(\n url: string,\n args: Array<any>,\n handler: (url: string, requestInit: RequestInit) => Promise<Response>,\n) {\n if (!serovalPlugins) {\n serovalPlugins = getDefaultSerovalPlugins()\n }\n const _first = args[0]\n\n const first = _first as FunctionMiddlewareClientFnOptions<any, any, any> & {\n headers?: HeadersInit\n }\n\n // Use custom fetch if provided, otherwise fall back to the passed handler (global fetch)\n const fetchImpl = first.fetch ?? handler\n\n const type = first.data instanceof FormData ? 'formData' : 'payload'\n\n // Arrange the headers\n const headers = first.headers ? new Headers(first.headers) : new Headers()\n headers.set('x-tsr-serverFn', 'true')\n\n if (type === 'payload') {\n headers.set(\n 'accept',\n `${TSS_CONTENT_TYPE_FRAMED}, application/x-ndjson, application/json`,\n )\n }\n\n // If the method is GET, we need to move the payload to the query string\n if (first.method === 'GET') {\n if (type === 'formData') {\n throw new Error('FormData is not supported with GET requests')\n }\n const serializedPayload = await serializePayload(first)\n if (serializedPayload !== undefined) {\n const encodedPayload = encode({\n payload: serializedPayload,\n })\n if (url.includes('?')) {\n url += `&${encodedPayload}`\n } else {\n url += `?${encodedPayload}`\n }\n }\n }\n\n let body = undefined\n if (first.method === 'POST') {\n const fetchBody = await getFetchBody(first)\n if (fetchBody?.contentType) {\n headers.set('content-type', fetchBody.contentType)\n }\n body = fetchBody?.body\n }\n\n return await getResponse(async () =>\n fetchImpl(url, {\n method: first.method,\n headers,\n signal: first.signal,\n body,\n }),\n )\n}\n\nasync function serializePayload(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<string | undefined> {\n let payloadAvailable = false\n const payloadToSerialize: any = {}\n if (opts.data !== undefined) {\n payloadAvailable = true\n payloadToSerialize['data'] = opts.data\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n payloadAvailable = true\n payloadToSerialize['context'] = opts.context\n }\n\n if (payloadAvailable) {\n return serialize(payloadToSerialize)\n }\n return undefined\n}\n\nasync function serialize(data: any) {\n return JSON.stringify(\n await Promise.resolve(toJSONAsync(data, { plugins: serovalPlugins! })),\n )\n}\n\nasync function getFetchBody(\n opts: FunctionMiddlewareClientFnOptions<any, any, any>,\n): Promise<{ body: FormData | string; contentType?: string } | undefined> {\n if (opts.data instanceof FormData) {\n let serializedContext = undefined\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (opts.context && hasOwnProperties(opts.context)) {\n serializedContext = await serialize(opts.context)\n }\n if (serializedContext !== undefined) {\n opts.data.set(TSS_FORMDATA_CONTEXT, serializedContext)\n }\n return { body: opts.data }\n }\n const serializedBody = await serializePayload(opts)\n if (serializedBody) {\n return { body: serializedBody, contentType: 'application/json' }\n }\n return undefined\n}\n\n/**\n * Retrieves a response from a given function and manages potential errors\n * and special response types including redirects and not found errors.\n *\n * @param fn - The function to execute for obtaining the response.\n * @returns The processed response from the function.\n * @throws If the response is invalid or an error occurs during processing.\n */\nasync function getResponse(fn: () => Promise<Response>) {\n let response: Response\n try {\n response = await fn() // client => server => fn => server => client\n } catch (error) {\n if (error instanceof Response) {\n response = error\n } else {\n console.log(error)\n throw error\n }\n }\n\n if (response.headers.get(X_TSS_RAW_RESPONSE) === 'true') {\n return response\n }\n\n const contentType = response.headers.get('content-type')\n invariant(contentType, 'expected content-type header to be set')\n const serializedByStart = !!response.headers.get(X_TSS_SERIALIZED)\n\n // If the response is serialized by the start server, we need to process it\n // differently than a normal response.\n if (serializedByStart) {\n let result\n\n // If it's a framed response (contains RawStream), use frame decoder\n if (contentType.includes(TSS_CONTENT_TYPE_FRAMED)) {\n // Validate protocol version compatibility\n validateFramedProtocolVersion(contentType)\n\n if (!response.body) {\n throw new Error('No response body for framed response')\n }\n\n const { getOrCreateStream, jsonChunks } = createFrameDecoder(\n response.body,\n )\n\n // Create deserialize plugin that wires up the raw streams\n const rawStreamPlugin =\n createRawStreamDeserializePlugin(getOrCreateStream)\n const plugins = [rawStreamPlugin, ...(serovalPlugins || [])]\n\n const refs = new Map()\n result = await processFramedResponse({\n jsonStream: jsonChunks,\n onMessage: (msg: any) => fromCrossJSON(msg, { refs, plugins }),\n onError(msg, error) {\n console.error(msg, error)\n },\n })\n }\n // If it's a stream from the start serializer, process it as such\n else if (contentType.includes('application/x-ndjson')) {\n const refs = new Map()\n result = await processServerFnResponse({\n response,\n onMessage: (msg) =>\n fromCrossJSON(msg, { refs, plugins: serovalPlugins! }),\n onError(msg, error) {\n // TODO how could we notify consumer that an error occurred?\n console.error(msg, error)\n },\n })\n }\n // If it's a JSON response, it can be simpler\n else if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n result = fromCrossJSON(jsonPayload, { plugins: serovalPlugins! })\n }\n\n invariant(result, 'expected result to be resolved')\n if (result instanceof Error) {\n throw result\n }\n\n return result\n }\n\n // If it wasn't processed by the start serializer, check\n // if it's JSON\n if (contentType.includes('application/json')) {\n const jsonPayload = await response.json()\n const redirect = parseRedirect(jsonPayload)\n if (redirect) {\n throw redirect\n }\n if (isNotFound(jsonPayload)) {\n throw jsonPayload\n }\n return jsonPayload\n }\n\n // Otherwise, if it's not OK, throw the content\n if (!response.ok) {\n throw new Error(await response.text())\n }\n\n // Or return the response itself\n return response\n}\n\nasync function processServerFnResponse({\n response,\n onMessage,\n onError,\n}: {\n response: Response\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n if (!response.body) {\n throw new Error('No response body')\n }\n\n const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()\n\n let buffer = ''\n let firstRead = false\n let firstObject\n\n while (!firstRead) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n if (buffer.length === 0 && done) {\n throw new Error('Stream ended before first object')\n }\n\n // common case: buffer ends with newline\n if (buffer.endsWith('\\n')) {\n const lines = buffer.split('\\n').filter(Boolean)\n const firstLine = lines[0]\n if (!firstLine) throw new Error('No JSON line in the first chunk')\n firstObject = JSON.parse(firstLine)\n firstRead = true\n buffer = lines.slice(1).join('\\n')\n } else {\n // fallback: wait for a newline to parse first object safely\n const newlineIndex = buffer.indexOf('\\n')\n if (newlineIndex >= 0) {\n const line = buffer.slice(0, newlineIndex).trim()\n buffer = buffer.slice(newlineIndex + 1)\n if (line.length > 0) {\n firstObject = JSON.parse(line)\n firstRead = true\n }\n }\n }\n }\n\n // process rest of the stream asynchronously\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (value) buffer += value\n\n const lastNewline = buffer.lastIndexOf('\\n')\n if (lastNewline >= 0) {\n const chunk = buffer.slice(0, lastNewline)\n buffer = buffer.slice(lastNewline + 1)\n const lines = chunk.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n try {\n onMessage(JSON.parse(line))\n } catch (e) {\n onError?.(`Invalid JSON line: ${line}`, e)\n }\n }\n }\n\n if (done) {\n break\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n\n/**\n * Processes a framed response where each JSON chunk is a complete JSON string\n * (already decoded by frame decoder).\n */\nasync function processFramedResponse({\n jsonStream,\n onMessage,\n onError,\n}: {\n jsonStream: ReadableStream<string>\n onMessage: (msg: any) => any\n onError?: (msg: string, error?: any) => void\n}) {\n const reader = jsonStream.getReader()\n\n // Read first JSON frame - this is the main result\n const { value: firstValue, done: firstDone } = await reader.read()\n if (firstDone || !firstValue) {\n throw new Error('Stream ended before first object')\n }\n\n // Each frame is a complete JSON string\n const firstObject = JSON.parse(firstValue)\n\n // Process remaining frames asynchronously (for streaming refs like RawStream)\n ;(async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n if (value) {\n try {\n onMessage(JSON.parse(value))\n } catch (e) {\n onError?.(`Invalid JSON: ${value}`, e)\n }\n }\n }\n } catch (err) {\n onError?.('Stream processing error:', err)\n }\n })()\n\n return onMessage(firstObject)\n}\n"],"mappings":"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"} |
@@ -0,36 +1,31 @@ | ||
| import { ServerFunctionSerializationAdapter } from "./ServerFunctionSerializationAdapter.js"; | ||
| import { hydrate } from "@tanstack/router-core/ssr/client"; | ||
| import { ServerFunctionSerializationAdapter } from "./ServerFunctionSerializationAdapter.js"; | ||
| import { getRouter } from "#tanstack-router-entry"; | ||
| import { startInstance } from "#tanstack-start-entry"; | ||
| //#region src/client/hydrateStart.ts | ||
| async function hydrateStart() { | ||
| const router = await getRouter(); | ||
| let serializationAdapters; | ||
| if (startInstance) { | ||
| const startOptions = await startInstance.getOptions(); | ||
| startOptions.serializationAdapters = startOptions.serializationAdapters ?? []; | ||
| window.__TSS_START_OPTIONS__ = startOptions; | ||
| serializationAdapters = startOptions.serializationAdapters; | ||
| router.options.defaultSsr = startOptions.defaultSsr; | ||
| } else { | ||
| serializationAdapters = []; | ||
| window.__TSS_START_OPTIONS__ = { | ||
| serializationAdapters | ||
| }; | ||
| } | ||
| serializationAdapters.push(ServerFunctionSerializationAdapter); | ||
| if (router.options.serializationAdapters) { | ||
| serializationAdapters.push(...router.options.serializationAdapters); | ||
| } | ||
| router.update({ | ||
| basepath: process.env.TSS_ROUTER_BASEPATH, | ||
| ...{ serializationAdapters } | ||
| }); | ||
| if (!router.state.matches.length) { | ||
| await hydrate(router); | ||
| } | ||
| return router; | ||
| const router = await getRouter(); | ||
| let serializationAdapters; | ||
| if (startInstance) { | ||
| const startOptions = await startInstance.getOptions(); | ||
| startOptions.serializationAdapters = startOptions.serializationAdapters ?? []; | ||
| window.__TSS_START_OPTIONS__ = startOptions; | ||
| serializationAdapters = startOptions.serializationAdapters; | ||
| router.options.defaultSsr = startOptions.defaultSsr; | ||
| } else { | ||
| serializationAdapters = []; | ||
| window.__TSS_START_OPTIONS__ = { serializationAdapters }; | ||
| } | ||
| serializationAdapters.push(ServerFunctionSerializationAdapter); | ||
| if (router.options.serializationAdapters) serializationAdapters.push(...router.options.serializationAdapters); | ||
| router.update({ | ||
| basepath: process.env.TSS_ROUTER_BASEPATH, | ||
| serializationAdapters | ||
| }); | ||
| if (!router.state.matches.length) await hydrate(router); | ||
| return router; | ||
| } | ||
| export { | ||
| hydrateStart | ||
| }; | ||
| //# sourceMappingURL=hydrateStart.js.map | ||
| //#endregion | ||
| export { hydrateStart }; | ||
| //# sourceMappingURL=hydrateStart.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"hydrateStart.js","sources":["../../../src/client/hydrateStart.ts"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\n\nimport { ServerFunctionSerializationAdapter } from './ServerFunctionSerializationAdapter'\nimport type { AnyStartInstanceOptions } from '../createStart'\nimport type { AnyRouter, AnySerializationAdapter } from '@tanstack/router-core'\n// eslint-disable-next-line import/no-duplicates,import/order\nimport { getRouter } from '#tanstack-router-entry'\n// eslint-disable-next-line import/no-duplicates,import/order\nimport { startInstance } from '#tanstack-start-entry'\n\nexport async function hydrateStart(): Promise<AnyRouter> {\n const router = await getRouter()\n\n let serializationAdapters: Array<AnySerializationAdapter>\n if (startInstance) {\n const startOptions = await startInstance.getOptions()\n startOptions.serializationAdapters =\n startOptions.serializationAdapters ?? []\n window.__TSS_START_OPTIONS__ = startOptions as AnyStartInstanceOptions\n serializationAdapters = startOptions.serializationAdapters\n router.options.defaultSsr = startOptions.defaultSsr\n } else {\n serializationAdapters = []\n window.__TSS_START_OPTIONS__ = {\n serializationAdapters,\n } as AnyStartInstanceOptions\n }\n\n serializationAdapters.push(ServerFunctionSerializationAdapter)\n if (router.options.serializationAdapters) {\n serializationAdapters.push(...router.options.serializationAdapters)\n }\n\n router.update({\n basepath: process.env.TSS_ROUTER_BASEPATH,\n ...{ serializationAdapters },\n })\n if (!router.state.matches.length) {\n await hydrate(router)\n }\n\n return router\n}\n"],"names":[],"mappings":";;;;AAUA,eAAsB,eAAmC;AACvD,QAAM,SAAS,MAAM,UAAA;AAErB,MAAI;AACJ,MAAI,eAAe;AACjB,UAAM,eAAe,MAAM,cAAc,WAAA;AACzC,iBAAa,wBACX,aAAa,yBAAyB,CAAA;AACxC,WAAO,wBAAwB;AAC/B,4BAAwB,aAAa;AACrC,WAAO,QAAQ,aAAa,aAAa;AAAA,EAC3C,OAAO;AACL,4BAAwB,CAAA;AACxB,WAAO,wBAAwB;AAAA,MAC7B;AAAA,IAAA;AAAA,EAEJ;AAEA,wBAAsB,KAAK,kCAAkC;AAC7D,MAAI,OAAO,QAAQ,uBAAuB;AACxC,0BAAsB,KAAK,GAAG,OAAO,QAAQ,qBAAqB;AAAA,EACpE;AAEA,SAAO,OAAO;AAAA,IACZ,UAAU,QAAQ,IAAI;AAAA,IACtB,GAAG,EAAE,sBAAA;AAAA,EAAsB,CAC5B;AACD,MAAI,CAAC,OAAO,MAAM,QAAQ,QAAQ;AAChC,UAAM,QAAQ,MAAM;AAAA,EACtB;AAEA,SAAO;AACT;"} | ||
| {"version":3,"file":"hydrateStart.js","names":[],"sources":["../../../src/client/hydrateStart.ts"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\n\nimport { ServerFunctionSerializationAdapter } from './ServerFunctionSerializationAdapter'\nimport type { AnyStartInstanceOptions } from '../createStart'\nimport type { AnyRouter, AnySerializationAdapter } from '@tanstack/router-core'\n// eslint-disable-next-line import/no-duplicates,import/order\nimport { getRouter } from '#tanstack-router-entry'\n// eslint-disable-next-line import/no-duplicates,import/order\nimport { startInstance } from '#tanstack-start-entry'\n\nexport async function hydrateStart(): Promise<AnyRouter> {\n const router = await getRouter()\n\n let serializationAdapters: Array<AnySerializationAdapter>\n if (startInstance) {\n const startOptions = await startInstance.getOptions()\n startOptions.serializationAdapters =\n startOptions.serializationAdapters ?? []\n window.__TSS_START_OPTIONS__ = startOptions as AnyStartInstanceOptions\n serializationAdapters = startOptions.serializationAdapters\n router.options.defaultSsr = startOptions.defaultSsr\n } else {\n serializationAdapters = []\n window.__TSS_START_OPTIONS__ = {\n serializationAdapters,\n } as AnyStartInstanceOptions\n }\n\n serializationAdapters.push(ServerFunctionSerializationAdapter)\n if (router.options.serializationAdapters) {\n serializationAdapters.push(...router.options.serializationAdapters)\n }\n\n router.update({\n basepath: process.env.TSS_ROUTER_BASEPATH,\n ...{ serializationAdapters },\n })\n if (!router.state.matches.length) {\n await hydrate(router)\n }\n\n return router\n}\n"],"mappings":";;;;;AAUA,eAAsB,eAAmC;CACvD,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI;AACJ,KAAI,eAAe;EACjB,MAAM,eAAe,MAAM,cAAc,YAAY;AACrD,eAAa,wBACX,aAAa,yBAAyB,EAAE;AAC1C,SAAO,wBAAwB;AAC/B,0BAAwB,aAAa;AACrC,SAAO,QAAQ,aAAa,aAAa;QACpC;AACL,0BAAwB,EAAE;AAC1B,SAAO,wBAAwB,EAC7B,uBACD;;AAGH,uBAAsB,KAAK,mCAAmC;AAC9D,KAAI,OAAO,QAAQ,sBACjB,uBAAsB,KAAK,GAAG,OAAO,QAAQ,sBAAsB;AAGrE,QAAO,OAAO;EACZ,UAAU,QAAQ,IAAI;EACjB;EACN,CAAC;AACF,KAAI,CAAC,OAAO,MAAM,QAAQ,OACxB,OAAM,QAAQ,OAAO;AAGvB,QAAO"} |
| import { hydrateStart } from "./hydrateStart.js"; | ||
| export { | ||
| hydrateStart | ||
| }; | ||
| //# sourceMappingURL=index.js.map | ||
| export { hydrateStart }; |
@@ -1,17 +0,18 @@ | ||
| import { createSerializationAdapter } from "@tanstack/router-core"; | ||
| import { TSS_SERVER_FUNCTION } from "../constants.js"; | ||
| import { createClientRpc } from "../client-rpc/createClientRpc.js"; | ||
| const ServerFunctionSerializationAdapter = createSerializationAdapter({ | ||
| key: "$TSS/serverfn", | ||
| test: (v) => { | ||
| if (typeof v !== "function") return false; | ||
| if (!(TSS_SERVER_FUNCTION in v)) return false; | ||
| return !!v[TSS_SERVER_FUNCTION]; | ||
| }, | ||
| toSerializable: ({ serverFnMeta }) => ({ functionId: serverFnMeta.id }), | ||
| fromSerializable: ({ functionId }) => createClientRpc(functionId) | ||
| import { createSerializationAdapter } from "@tanstack/router-core"; | ||
| //#region src/client/ServerFunctionSerializationAdapter.ts | ||
| var ServerFunctionSerializationAdapter = createSerializationAdapter({ | ||
| key: "$TSS/serverfn", | ||
| test: (v) => { | ||
| if (typeof v !== "function") return false; | ||
| if (!(TSS_SERVER_FUNCTION in v)) return false; | ||
| return !!v[TSS_SERVER_FUNCTION]; | ||
| }, | ||
| toSerializable: ({ serverFnMeta }) => ({ functionId: serverFnMeta.id }), | ||
| fromSerializable: ({ functionId }) => createClientRpc(functionId) | ||
| }); | ||
| export { | ||
| ServerFunctionSerializationAdapter | ||
| }; | ||
| //# sourceMappingURL=ServerFunctionSerializationAdapter.js.map | ||
| //#endregion | ||
| export { ServerFunctionSerializationAdapter }; | ||
| //# sourceMappingURL=ServerFunctionSerializationAdapter.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"ServerFunctionSerializationAdapter.js","sources":["../../../src/client/ServerFunctionSerializationAdapter.ts"],"sourcesContent":["import { createSerializationAdapter } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION } from '../constants'\nimport { createClientRpc } from '../client-rpc/createClientRpc'\n\nexport const ServerFunctionSerializationAdapter = createSerializationAdapter({\n key: '$TSS/serverfn',\n test: (v): v is { serverFnMeta: { id: string } } => {\n if (typeof v !== 'function') return false\n\n if (!(TSS_SERVER_FUNCTION in v)) return false\n\n return !!v[TSS_SERVER_FUNCTION]\n },\n toSerializable: ({ serverFnMeta }) => ({ functionId: serverFnMeta.id }),\n fromSerializable: ({ functionId }) => createClientRpc(functionId),\n})\n"],"names":[],"mappings":";;;AAIO,MAAM,qCAAqC,2BAA2B;AAAA,EAC3E,KAAK;AAAA,EACL,MAAM,CAAC,MAA6C;AAClD,QAAI,OAAO,MAAM,WAAY,QAAO;AAEpC,QAAI,EAAE,uBAAuB,GAAI,QAAO;AAExC,WAAO,CAAC,CAAC,EAAE,mBAAmB;AAAA,EAChC;AAAA,EACA,gBAAgB,CAAC,EAAE,aAAA,OAAoB,EAAE,YAAY,aAAa;EAClE,kBAAkB,CAAC,EAAE,WAAA,MAAiB,gBAAgB,UAAU;AAClE,CAAC;"} | ||
| {"version":3,"file":"ServerFunctionSerializationAdapter.js","names":[],"sources":["../../../src/client/ServerFunctionSerializationAdapter.ts"],"sourcesContent":["import { createSerializationAdapter } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION } from '../constants'\nimport { createClientRpc } from '../client-rpc/createClientRpc'\n\nexport const ServerFunctionSerializationAdapter = createSerializationAdapter({\n key: '$TSS/serverfn',\n test: (v): v is { serverFnMeta: { id: string } } => {\n if (typeof v !== 'function') return false\n\n if (!(TSS_SERVER_FUNCTION in v)) return false\n\n return !!v[TSS_SERVER_FUNCTION]\n },\n toSerializable: ({ serverFnMeta }) => ({ functionId: serverFnMeta.id }),\n fromSerializable: ({ functionId }) => createClientRpc(functionId),\n})\n"],"mappings":";;;;AAIA,IAAa,qCAAqC,2BAA2B;CAC3E,KAAK;CACL,OAAO,MAA6C;AAClD,MAAI,OAAO,MAAM,WAAY,QAAO;AAEpC,MAAI,EAAE,uBAAuB,GAAI,QAAO;AAExC,SAAO,CAAC,CAAC,EAAE;;CAEb,iBAAiB,EAAE,oBAAoB,EAAE,YAAY,aAAa,IAAI;CACtE,mBAAmB,EAAE,iBAAiB,gBAAgB,WAAW;CAClE,CAAC"} |
+41
-49
@@ -1,54 +0,46 @@ | ||
| const TSS_FORMDATA_CONTEXT = "__TSS_CONTEXT"; | ||
| const TSS_SERVER_FUNCTION = /* @__PURE__ */ Symbol.for("TSS_SERVER_FUNCTION"); | ||
| const TSS_SERVER_FUNCTION_FACTORY = /* @__PURE__ */ Symbol.for( | ||
| "TSS_SERVER_FUNCTION_FACTORY" | ||
| ); | ||
| const X_TSS_SERIALIZED = "x-tss-serialized"; | ||
| const X_TSS_RAW_RESPONSE = "x-tss-raw"; | ||
| const X_TSS_CONTEXT = "x-tss-context"; | ||
| const TSS_CONTENT_TYPE_FRAMED = "application/x-tss-framed"; | ||
| const FrameType = { | ||
| /** Seroval JSON chunk (NDJSON line) */ | ||
| JSON: 0, | ||
| /** Raw stream data chunk */ | ||
| CHUNK: 1, | ||
| /** Raw stream end (EOF) */ | ||
| END: 2, | ||
| /** Raw stream error */ | ||
| ERROR: 3 | ||
| //#region src/constants.ts | ||
| var TSS_FORMDATA_CONTEXT = "__TSS_CONTEXT"; | ||
| var TSS_SERVER_FUNCTION = Symbol.for("TSS_SERVER_FUNCTION"); | ||
| var TSS_SERVER_FUNCTION_FACTORY = Symbol.for("TSS_SERVER_FUNCTION_FACTORY"); | ||
| var X_TSS_SERIALIZED = "x-tss-serialized"; | ||
| var X_TSS_RAW_RESPONSE = "x-tss-raw"; | ||
| var X_TSS_CONTEXT = "x-tss-context"; | ||
| /** Content-Type for multiplexed framed responses (RawStream support) */ | ||
| var TSS_CONTENT_TYPE_FRAMED = "application/x-tss-framed"; | ||
| /** | ||
| * Frame types for binary multiplexing protocol. | ||
| */ | ||
| var FrameType = { | ||
| JSON: 0, | ||
| CHUNK: 1, | ||
| END: 2, | ||
| ERROR: 3 | ||
| }; | ||
| const FRAME_HEADER_SIZE = 9; | ||
| const TSS_FRAMED_PROTOCOL_VERSION = 1; | ||
| const TSS_CONTENT_TYPE_FRAMED_VERSIONED = `${TSS_CONTENT_TYPE_FRAMED}; v=${TSS_FRAMED_PROTOCOL_VERSION}`; | ||
| const FRAMED_VERSION_REGEX = /;\s*v=(\d+)/; | ||
| /** Header size in bytes: type(1) + streamId(4) + length(4) */ | ||
| var FRAME_HEADER_SIZE = 9; | ||
| /** Current protocol version for framed responses */ | ||
| var TSS_FRAMED_PROTOCOL_VERSION = 1; | ||
| /** Full Content-Type header value with version parameter */ | ||
| var TSS_CONTENT_TYPE_FRAMED_VERSIONED = `${TSS_CONTENT_TYPE_FRAMED}; v=1`; | ||
| /** | ||
| * Parses the version parameter from a framed Content-Type header. | ||
| * Returns undefined if no version parameter is present. | ||
| */ | ||
| var FRAMED_VERSION_REGEX = /;\s*v=(\d+)/; | ||
| function parseFramedProtocolVersion(contentType) { | ||
| const match = contentType.match(FRAMED_VERSION_REGEX); | ||
| return match ? parseInt(match[1], 10) : void 0; | ||
| const match = contentType.match(FRAMED_VERSION_REGEX); | ||
| return match ? parseInt(match[1], 10) : void 0; | ||
| } | ||
| /** | ||
| * Validates that the server's protocol version is compatible with this client. | ||
| * Throws an error if versions are incompatible. | ||
| */ | ||
| function validateFramedProtocolVersion(contentType) { | ||
| const serverVersion = parseFramedProtocolVersion(contentType); | ||
| if (serverVersion === void 0) { | ||
| return; | ||
| } | ||
| if (serverVersion !== TSS_FRAMED_PROTOCOL_VERSION) { | ||
| throw new Error( | ||
| `Incompatible framed protocol version: server=${serverVersion}, client=${TSS_FRAMED_PROTOCOL_VERSION}. Please ensure client and server are using compatible versions.` | ||
| ); | ||
| } | ||
| const serverVersion = parseFramedProtocolVersion(contentType); | ||
| if (serverVersion === void 0) return; | ||
| if (serverVersion !== 1) throw new Error(`Incompatible framed protocol version: server=${serverVersion}, client=1. Please ensure client and server are using compatible versions.`); | ||
| } | ||
| export { | ||
| FRAME_HEADER_SIZE, | ||
| FrameType, | ||
| TSS_CONTENT_TYPE_FRAMED, | ||
| TSS_CONTENT_TYPE_FRAMED_VERSIONED, | ||
| TSS_FORMDATA_CONTEXT, | ||
| TSS_FRAMED_PROTOCOL_VERSION, | ||
| TSS_SERVER_FUNCTION, | ||
| TSS_SERVER_FUNCTION_FACTORY, | ||
| X_TSS_CONTEXT, | ||
| X_TSS_RAW_RESPONSE, | ||
| X_TSS_SERIALIZED, | ||
| parseFramedProtocolVersion, | ||
| validateFramedProtocolVersion | ||
| }; | ||
| //# sourceMappingURL=constants.js.map | ||
| //#endregion | ||
| export { FRAME_HEADER_SIZE, FrameType, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, TSS_SERVER_FUNCTION_FACTORY, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, validateFramedProtocolVersion }; | ||
| //# sourceMappingURL=constants.js.map |
@@ -1,1 +0,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 const X_TSS_CONTEXT = 'x-tss-context'\n\n/** Content-Type for multiplexed framed responses (RawStream support) */\nexport const TSS_CONTENT_TYPE_FRAMED = 'application/x-tss-framed'\n\n/**\n * Frame types for binary multiplexing protocol.\n */\nexport const FrameType = {\n /** Seroval JSON chunk (NDJSON line) */\n JSON: 0,\n /** Raw stream data chunk */\n CHUNK: 1,\n /** Raw stream end (EOF) */\n END: 2,\n /** Raw stream error */\n ERROR: 3,\n} as const\n\nexport type FrameType = (typeof FrameType)[keyof typeof FrameType]\n\n/** Header size in bytes: type(1) + streamId(4) + length(4) */\nexport const FRAME_HEADER_SIZE = 9\n\n/** Current protocol version for framed responses */\nexport const TSS_FRAMED_PROTOCOL_VERSION = 1\n\n/** Full Content-Type header value with version parameter */\nexport const TSS_CONTENT_TYPE_FRAMED_VERSIONED = `${TSS_CONTENT_TYPE_FRAMED}; v=${TSS_FRAMED_PROTOCOL_VERSION}`\n\n/**\n * Parses the version parameter from a framed Content-Type header.\n * Returns undefined if no version parameter is present.\n */\nconst FRAMED_VERSION_REGEX = /;\\s*v=(\\d+)/\nexport function parseFramedProtocolVersion(\n contentType: string,\n): number | undefined {\n // Match \"v=<number>\" in the content-type parameters\n const match = contentType.match(FRAMED_VERSION_REGEX)\n return match ? parseInt(match[1]!, 10) : undefined\n}\n\n/**\n * Validates that the server's protocol version is compatible with this client.\n * Throws an error if versions are incompatible.\n */\nexport function validateFramedProtocolVersion(contentType: string): void {\n const serverVersion = parseFramedProtocolVersion(contentType)\n if (serverVersion === undefined) {\n // No version specified - assume compatible (backwards compat)\n return\n }\n if (serverVersion !== TSS_FRAMED_PROTOCOL_VERSION) {\n throw new Error(\n `Incompatible framed protocol version: server=${serverVersion}, client=${TSS_FRAMED_PROTOCOL_VERSION}. ` +\n `Please ensure client and server are using compatible versions.`,\n )\n }\n}\n\n/**\n * Minimal metadata about a server function, available to client middleware.\n * Only contains the function ID since name/filename may expose server internals.\n */\nexport interface ClientFnMeta {\n /** The unique identifier for this server function */\n id: string\n}\n\n/**\n * Full metadata about a server function, available to server middleware and server functions.\n * This information is embedded at compile time by the TanStack Start compiler.\n */\nexport interface ServerFnMeta extends ClientFnMeta {\n /** The original variable name of the server function (e.g., \"myServerFn\") */\n name: string\n /** The source file path relative to the project root (e.g., \"src/routes/api.ts\") */\n filename: string\n}\n\nexport {}\n"],"names":[],"mappings":"AAAO,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB,uBAAO,IAAI,qBAAqB;AAC5D,MAAM,8BAA8B,uBAAO;AAAA,EAChD;AACF;AAEO,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AAGtB,MAAM,0BAA0B;AAKhC,MAAM,YAAY;AAAA;AAAA,EAEvB,MAAM;AAAA;AAAA,EAEN,OAAO;AAAA;AAAA,EAEP,KAAK;AAAA;AAAA,EAEL,OAAO;AACT;AAKO,MAAM,oBAAoB;AAG1B,MAAM,8BAA8B;AAGpC,MAAM,oCAAoC,GAAG,uBAAuB,OAAO,2BAA2B;AAM7G,MAAM,uBAAuB;AACtB,SAAS,2BACd,aACoB;AAEpB,QAAM,QAAQ,YAAY,MAAM,oBAAoB;AACpD,SAAO,QAAQ,SAAS,MAAM,CAAC,GAAI,EAAE,IAAI;AAC3C;AAMO,SAAS,8BAA8B,aAA2B;AACvE,QAAM,gBAAgB,2BAA2B,WAAW;AAC5D,MAAI,kBAAkB,QAAW;AAE/B;AAAA,EACF;AACA,MAAI,kBAAkB,6BAA6B;AACjD,UAAM,IAAI;AAAA,MACR,gDAAgD,aAAa,YAAY,2BAA2B;AAAA,IAAA;AAAA,EAGxG;AACF;"} | ||
| {"version":3,"file":"constants.js","names":[],"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 const X_TSS_CONTEXT = 'x-tss-context'\n\n/** Content-Type for multiplexed framed responses (RawStream support) */\nexport const TSS_CONTENT_TYPE_FRAMED = 'application/x-tss-framed'\n\n/**\n * Frame types for binary multiplexing protocol.\n */\nexport const FrameType = {\n /** Seroval JSON chunk (NDJSON line) */\n JSON: 0,\n /** Raw stream data chunk */\n CHUNK: 1,\n /** Raw stream end (EOF) */\n END: 2,\n /** Raw stream error */\n ERROR: 3,\n} as const\n\nexport type FrameType = (typeof FrameType)[keyof typeof FrameType]\n\n/** Header size in bytes: type(1) + streamId(4) + length(4) */\nexport const FRAME_HEADER_SIZE = 9\n\n/** Current protocol version for framed responses */\nexport const TSS_FRAMED_PROTOCOL_VERSION = 1\n\n/** Full Content-Type header value with version parameter */\nexport const TSS_CONTENT_TYPE_FRAMED_VERSIONED = `${TSS_CONTENT_TYPE_FRAMED}; v=${TSS_FRAMED_PROTOCOL_VERSION}`\n\n/**\n * Parses the version parameter from a framed Content-Type header.\n * Returns undefined if no version parameter is present.\n */\nconst FRAMED_VERSION_REGEX = /;\\s*v=(\\d+)/\nexport function parseFramedProtocolVersion(\n contentType: string,\n): number | undefined {\n // Match \"v=<number>\" in the content-type parameters\n const match = contentType.match(FRAMED_VERSION_REGEX)\n return match ? parseInt(match[1]!, 10) : undefined\n}\n\n/**\n * Validates that the server's protocol version is compatible with this client.\n * Throws an error if versions are incompatible.\n */\nexport function validateFramedProtocolVersion(contentType: string): void {\n const serverVersion = parseFramedProtocolVersion(contentType)\n if (serverVersion === undefined) {\n // No version specified - assume compatible (backwards compat)\n return\n }\n if (serverVersion !== TSS_FRAMED_PROTOCOL_VERSION) {\n throw new Error(\n `Incompatible framed protocol version: server=${serverVersion}, client=${TSS_FRAMED_PROTOCOL_VERSION}. ` +\n `Please ensure client and server are using compatible versions.`,\n )\n }\n}\n\n/**\n * Minimal metadata about a server function, available to client middleware.\n * Only contains the function ID since name/filename may expose server internals.\n */\nexport interface ClientFnMeta {\n /** The unique identifier for this server function */\n id: string\n}\n\n/**\n * Full metadata about a server function, available to server middleware and server functions.\n * This information is embedded at compile time by the TanStack Start compiler.\n */\nexport interface ServerFnMeta extends ClientFnMeta {\n /** The original variable name of the server function (e.g., \"myServerFn\") */\n name: string\n /** The source file path relative to the project root (e.g., \"src/routes/api.ts\") */\n filename: string\n}\n\nexport {}\n"],"mappings":";AAAA,IAAa,uBAAuB;AACpC,IAAa,sBAAsB,OAAO,IAAI,sBAAsB;AACpE,IAAa,8BAA8B,OAAO,IAChD,8BACD;AAED,IAAa,mBAAmB;AAChC,IAAa,qBAAqB;AAClC,IAAa,gBAAgB;;AAG7B,IAAa,0BAA0B;;;;AAKvC,IAAa,YAAY;CAEvB,MAAM;CAEN,OAAO;CAEP,KAAK;CAEL,OAAO;CACR;;AAKD,IAAa,oBAAoB;;AAGjC,IAAa,8BAA8B;;AAG3C,IAAa,oCAAoC,GAAG,wBAAwB;;;;;AAM5E,IAAM,uBAAuB;AAC7B,SAAgB,2BACd,aACoB;CAEpB,MAAM,QAAQ,YAAY,MAAM,qBAAqB;AACrD,QAAO,QAAQ,SAAS,MAAM,IAAK,GAAG,GAAG,KAAA;;;;;;AAO3C,SAAgB,8BAA8B,aAA2B;CACvE,MAAM,gBAAgB,2BAA2B,YAAY;AAC7D,KAAI,kBAAkB,KAAA,EAEpB;AAEF,KAAI,kBAAA,EACF,OAAM,IAAI,MACR,gDAAgD,cAAc,4EAE/D"} |
@@ -1,37 +0,26 @@ | ||
| const createMiddleware = (options, __opts) => { | ||
| const resolvedOptions = { | ||
| type: "request", | ||
| ...__opts || options | ||
| }; | ||
| return { | ||
| options: resolvedOptions, | ||
| middleware: (middleware) => { | ||
| return createMiddleware( | ||
| {}, | ||
| Object.assign(resolvedOptions, { middleware }) | ||
| ); | ||
| }, | ||
| inputValidator: (inputValidator) => { | ||
| return createMiddleware( | ||
| {}, | ||
| Object.assign(resolvedOptions, { inputValidator }) | ||
| ); | ||
| }, | ||
| client: (client) => { | ||
| return createMiddleware( | ||
| {}, | ||
| Object.assign(resolvedOptions, { client }) | ||
| ); | ||
| }, | ||
| server: (server) => { | ||
| return createMiddleware( | ||
| {}, | ||
| Object.assign(resolvedOptions, { server }) | ||
| ); | ||
| } | ||
| }; | ||
| //#region src/createMiddleware.ts | ||
| var createMiddleware = (options, __opts) => { | ||
| const resolvedOptions = { | ||
| type: "request", | ||
| ...__opts || options | ||
| }; | ||
| return { | ||
| options: resolvedOptions, | ||
| middleware: (middleware) => { | ||
| return createMiddleware({}, Object.assign(resolvedOptions, { middleware })); | ||
| }, | ||
| inputValidator: (inputValidator) => { | ||
| return createMiddleware({}, Object.assign(resolvedOptions, { inputValidator })); | ||
| }, | ||
| client: (client) => { | ||
| return createMiddleware({}, Object.assign(resolvedOptions, { client })); | ||
| }, | ||
| server: (server) => { | ||
| return createMiddleware({}, Object.assign(resolvedOptions, { server })); | ||
| } | ||
| }; | ||
| }; | ||
| export { | ||
| createMiddleware | ||
| }; | ||
| //# sourceMappingURL=createMiddleware.js.map | ||
| //#endregion | ||
| export { createMiddleware }; | ||
| //# sourceMappingURL=createMiddleware.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"createMiddleware.js","sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { middleware }),\n ) as any\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { inputValidator }),\n ) as any\n },\n client: (client: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { client }),\n ) as any\n },\n server: (server: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { server }),\n ) as any\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n inputValidator: <TNewValidator>(\n inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"names":[],"mappings":"AAiCO,MAAM,mBAA2C,CAAC,SAAS,WAAW;AAC3E,QAAM,kBAAkB;AAAA,IACtB,MAAM;AAAA,IACN,GAAI,UAAU;AAAA,EAAA;AAGhB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,CAAC,eAAoB;AAC/B,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,YAAY;AAAA,MAAA;AAAA,IAEjD;AAAA,IACA,gBAAgB,CAAC,mBAAwB;AACvC,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,gBAAgB;AAAA,MAAA;AAAA,IAErD;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,IACA,QAAQ,CAAC,WAAgB;AACvB,aAAO;AAAA,QACL,CAAA;AAAA,QACA,OAAO,OAAO,iBAAiB,EAAE,QAAQ;AAAA,MAAA;AAAA,IAE7C;AAAA,EAAA;AAEJ;"} | ||
| {"version":3,"file":"createMiddleware.js","names":[],"sources":["../../src/createMiddleware.ts"],"sourcesContent":["import type { StartInstanceOptions } from './createStart'\nimport type {\n AnyServerFn,\n ConstrainValidator,\n CustomFetch,\n Method,\n} from './createServerFn'\nimport type { ClientFnMeta, ServerFnMeta } from './constants'\nimport type {\n AnyContext,\n Assign,\n Constrain,\n Expand,\n IntersectAssign,\n Register,\n ResolveValidatorInput,\n ResolveValidatorOutput,\n ValidateSerializableInput,\n} from '@tanstack/router-core'\n\nexport type CreateMiddlewareFn<TRegister> = <TType extends MiddlewareType>(\n options?: {\n type?: TType\n },\n __opts?: FunctionMiddlewareOptions<\n TRegister,\n unknown,\n undefined,\n undefined,\n undefined\n >,\n) => CreateMiddlewareResult<TRegister, TType>\n\nexport const createMiddleware: CreateMiddlewareFn<{}> = (options, __opts) => {\n const resolvedOptions = {\n type: 'request',\n ...(__opts || options),\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { middleware }),\n ) as any\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { inputValidator }),\n ) as any\n },\n client: (client: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { client }),\n ) as any\n },\n server: (server: any) => {\n return createMiddleware(\n {} as any,\n Object.assign(resolvedOptions, { server }),\n ) as any\n },\n } as any\n}\n\nexport type MiddlewareType = 'request' | 'function'\n\nexport type CreateMiddlewareResult<\n TRegister,\n TType extends MiddlewareType,\n> = 'request' extends TType\n ? RequestMiddleware<TRegister>\n : FunctionMiddleware<TRegister>\n\nexport interface FunctionMiddleware<\n TRegister,\n> extends FunctionMiddlewareAfterMiddleware<TRegister, unknown> {\n middleware: <const TNewMiddlewares = undefined>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyRequestMiddleware | AnyFunctionMiddleware>\n >,\n ) => FunctionMiddlewareAfterMiddleware<TRegister, TNewMiddlewares>\n}\n\nexport interface FunctionMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, undefined>,\n FunctionMiddlewareValidator<TRegister, TMiddlewares> {}\n\nexport interface FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> {\n '~types': FunctionMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n >\n options: FunctionMiddlewareOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n}\n\nexport interface FunctionMiddlewareTypes<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TServerSendContext,\n in out TClientContext,\n in out TClientSendContext,\n> {\n type: 'function'\n middlewares: TMiddlewares\n input: ResolveValidatorInput<TInputValidator>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n output: ResolveValidatorOutput<TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n clientContext: TClientContext\n allClientContextBeforeNext: AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext\n >\n allClientContextAfterNext: AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext,\n TClientSendContext\n >\n serverContext: TServerContext\n serverSendContext: TServerSendContext\n allServerSendContext: AssignAllServerSendContext<\n TMiddlewares,\n TServerSendContext\n >\n allServerContext: AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n clientSendContext: TClientSendContext\n allClientSendContext: AssignAllClientSendContext<\n TMiddlewares,\n TClientSendContext\n >\n inputValidator: TInputValidator\n}\n\n/**\n * Recursively resolve the input type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorInputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allInput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allInput'>,\n ResolveValidatorInput<TInputValidator>\n >\n\nexport type IntersectAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? IntersectAllMiddleware<\n TRest,\n TType,\n IntersectAssign<\n TAcc,\n TMiddleware['~types'][TType & keyof TMiddleware['~types']]\n >\n >\n : TAcc\n : TAcc\n\nexport type AnyFunctionMiddleware = FunctionMiddlewareWithTypes<\n any,\n any,\n any,\n any,\n any,\n any,\n any\n>\n\n/**\n * Recursively merge the output type produced by a sequence of middleware\n */\nexport type IntersectAllValidatorOutputs<TMiddlewares, TInputValidator> =\n unknown extends TInputValidator\n ? TInputValidator\n : TInputValidator extends undefined\n ? IntersectAllMiddleware<TMiddlewares, 'allOutput'>\n : IntersectAssign<\n IntersectAllMiddleware<TMiddlewares, 'allOutput'>,\n Awaited<ResolveValidatorOutput<TInputValidator>>\n >\n\n/**\n * Recursively resolve the client context type produced by a sequence of middleware\n */\nexport type AssignAllClientContextBeforeNext<\n TMiddlewares,\n TClientContext = undefined,\n> = unknown extends TClientContext\n ? TClientContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextBeforeNext'>,\n TClientContext\n >\n\nexport type AssignAllMiddleware<\n TMiddlewares,\n TType extends\n | keyof AnyFunctionMiddleware['~types']\n | keyof AnyRequestMiddleware['~types']\n | keyof AnyServerFn['~types'],\n TAcc = undefined,\n> = TMiddlewares extends readonly [infer TMiddleware, ...infer TRest]\n ? TMiddleware extends\n | AnyFunctionMiddleware\n | AnyRequestMiddleware\n | AnyServerFn\n ? AssignAllMiddleware<\n TRest,\n TType,\n Assign<TAcc, TMiddleware['~types'][TType & keyof TMiddleware['~types']]>\n >\n : TAcc\n : TAcc\n\nexport type AssignAllClientContextAfterNext<\n TMiddlewares,\n TClientContext = undefined,\n TSendContext = undefined,\n> = unknown extends TClientContext\n ? Assign<TClientContext, TSendContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientContextAfterNext'>,\n Assign<TClientContext, TSendContext>\n >\n\nexport type AssignAllServerSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerSendContext'>,\n TSendContext\n >\n\nexport type AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n // Fetch Request Context\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>,\n __AssignAllServerRequestContext<TMiddlewares, TSendContext, TServerContext>\n >\n>\n\n// export type GlobalFetchRequestContext<TRegister> = AnyContext\nexport type GlobalFetchRequestContext = Register extends {\n server: { requestContext: infer TRequestContext }\n}\n ? TRequestContext\n : AnyContext\n\nexport type GlobalServerRequestContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, infer TRequestMiddlewares, any>\n}\n ? AssignAllMiddleware<TRequestMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerRequestContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = Assign<\n GlobalFetchRequestContext,\n Assign<\n GlobalServerRequestContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,\n Assign<\n GlobalServerFnContext<TRegister>, // TODO: This enabled global middleware\n // type inference, but creates a circular types issue. No idea how to fix this.\n // AnyContext,/\n __AssignAllServerFnContext<TMiddlewares, TSendContext, TServerContext>\n >\n >\n>\n\ntype GlobalServerFnContext<TRegister> = TRegister extends {\n config: StartInstanceOptions<any, any, any, infer TFunctionMiddlewares>\n}\n ? AssignAllMiddleware<TFunctionMiddlewares, 'allServerContext'>\n : AnyContext\n\ntype __AssignAllServerFnContext<\n TMiddlewares,\n TSendContext = undefined,\n TServerContext = undefined,\n> = unknown extends TSendContext\n ? Assign<TSendContext, TServerContext>\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allServerContext'>,\n Assign<TSendContext, TServerContext>\n >\n\nexport type AssignAllClientSendContext<\n TMiddlewares,\n TSendContext = undefined,\n> = unknown extends TSendContext\n ? TSendContext\n : Assign<\n AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>,\n TSendContext\n >\n\nexport interface FunctionMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerContext,\n in out TClientContext,\n> {\n middleware?: TMiddlewares\n inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n client?: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TClientContext\n >\n server?: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n unknown,\n unknown\n >\n}\n\nexport type FunctionMiddlewareClientNextFn<TRegister, TMiddlewares> = <\n TSendContext = undefined,\n TNewClientContext = undefined,\n>(ctx?: {\n context?: TNewClientContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n headers?: HeadersInit\n fetch?: CustomFetch\n}) => Promise<\n FunctionClientResultWithContext<TMiddlewares, TSendContext, TNewClientContext>\n>\n\nexport interface FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n> {\n server: <TNewServerContext = undefined, TSendContext = undefined>(\n server: FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >,\n ) => FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TNewServerContext,\n TServerSendContext,\n TClientContext,\n TSendContext\n >\n}\n\nexport type FunctionMiddlewareServerFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TNewServerContext,\n TSendContext,\n> = (\n options: FunctionMiddlewareServerFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext\n >,\n) => FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n>\n\nexport type FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n> = <TNewServerContext = undefined, TSendContext = undefined>(ctx?: {\n context?: TNewServerContext\n sendContext?: ValidateSerializableInput<TRegister, TSendContext>\n}) => Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TNewServerContext,\n TSendContext\n >\n>\n\nexport type FunctionServerResultWithContext<\n in out TRegister,\n in out TMiddlewares,\n in out TServerSendContext,\n in out TServerContext,\n in out TSendContext,\n> = {\n 'use functions must return the result of next()': true\n '~types': {\n context: TServerContext\n sendContext: TSendContext\n }\n context: Expand<\n AssignAllServerFnContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext\n >\n >\n sendContext: Expand<AssignAllClientSendContext<TMiddlewares, TSendContext>>\n}\n\nexport interface FunctionMiddlewareServerFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n in out TServerSendContext,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n context: Expand<\n AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext>\n >\n next: FunctionMiddlewareServerNextFn<\n TRegister,\n TMiddlewares,\n TServerSendContext\n >\n method: Method\n serverFnMeta: ServerFnMeta\n signal: AbortSignal\n}\n\nexport type FunctionMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext,\n> =\n | Promise<\n FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n >\n | FunctionServerResultWithContext<\n TRegister,\n TMiddlewares,\n TServerSendContext,\n TServerContext,\n TSendContext\n >\n\nexport interface FunctionMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext,\n> extends FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerContext,\n TServerSendContext,\n TClientContext,\n TClientSendContext\n> {}\n\nexport interface FunctionMiddlewareClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n> {\n client: <TSendServerContext = undefined, TNewClientContext = undefined>(\n client: FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >,\n ) => FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendServerContext,\n TNewClientContext\n >\n}\n\nexport type FunctionMiddlewareClientFn<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TSendContext,\n TClientContext,\n> = (\n options: FunctionMiddlewareClientFnOptions<\n TRegister,\n TMiddlewares,\n TInputValidator\n >,\n) => FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext\n>\n\nexport interface FunctionMiddlewareClientFnOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TInputValidator,\n> {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n context: Expand<AssignAllClientContextBeforeNext<TMiddlewares>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares>>\n method: Method\n signal: AbortSignal\n serverFnMeta: ClientFnMeta\n next: FunctionMiddlewareClientNextFn<TRegister, TMiddlewares>\n filename: string\n fetch?: CustomFetch\n}\n\nexport type FunctionMiddlewareClientFnResult<\n TMiddlewares,\n TSendContext,\n TClientContext,\n> =\n | Promise<\n FunctionClientResultWithContext<\n TMiddlewares,\n TSendContext,\n TClientContext\n >\n >\n | FunctionClientResultWithContext<TMiddlewares, TSendContext, TClientContext>\n\nexport type FunctionClientResultWithContext<\n in out TMiddlewares,\n in out TSendContext,\n in out TClientContext,\n> = {\n 'use functions must return the result of next()': true\n context: Expand<AssignAllClientContextAfterNext<TMiddlewares, TClientContext>>\n sendContext: Expand<AssignAllServerSendContext<TMiddlewares, TSendContext>>\n headers: HeadersInit\n fetch?: CustomFetch\n}\n\nexport interface FunctionMiddlewareAfterClient<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n TServerSendContext,\n TClientContext,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n TServerSendContext,\n TClientContext\n > {}\n\nexport interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {\n inputValidator: <TNewValidator>(\n inputValidator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n}\n\nexport interface FunctionMiddlewareAfterValidator<\n TRegister,\n TMiddlewares,\n TInputValidator,\n>\n extends\n FunctionMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined,\n undefined,\n undefined\n >,\n FunctionMiddlewareServer<\n TRegister,\n TMiddlewares,\n TInputValidator,\n undefined,\n undefined\n >,\n FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {}\n\nexport interface RequestMiddleware<\n TRegister,\n> extends RequestMiddlewareAfterMiddleware<TRegister, undefined> {\n middleware: <const TMiddlewares = undefined>(\n middlewares: Constrain<TMiddlewares, ReadonlyArray<AnyRequestMiddleware>>,\n ) => RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n}\n\nexport type AnyRequestMiddleware = RequestMiddlewareWithTypes<any, any, any>\n\nexport interface RequestMiddlewareWithTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n '~types': RequestMiddlewareTypes<TRegister, TMiddlewares, TServerContext>\n options: RequestMiddlewareOptions<TRegister, TMiddlewares, TServerContext>\n}\n\nexport interface RequestMiddlewareOptions<\n in out TRegister,\n in out TMiddlewares,\n in out TServerContext,\n> {\n middleware?: TMiddlewares\n server?: RequestServerFn<TRegister, TMiddlewares, TServerContext>\n}\nexport interface RequestMiddlewareTypes<\n TRegister,\n TMiddlewares,\n TServerContext,\n> {\n type: 'request'\n // this only exists so we can use request middlewares in server functions\n allInput: undefined\n // this only exists so we can use request middlewares in server functions\n allOutput: undefined\n middlewares: TMiddlewares\n serverContext: TServerContext\n allServerContext: AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n}\n\nexport interface RequestMiddlewareAfterMiddleware<TRegister, TMiddlewares>\n extends\n RequestMiddlewareWithTypes<TRegister, TMiddlewares, undefined>,\n RequestMiddlewareServer<TRegister, TMiddlewares> {}\n\nexport interface RequestMiddlewareServer<TRegister, TMiddlewares> {\n server: <TServerContext = undefined>(\n fn: RequestServerFn<TRegister, TMiddlewares, TServerContext>,\n ) => RequestMiddlewareAfterServer<TRegister, TMiddlewares, TServerContext>\n}\n\nexport type RequestServerFn<TRegister, TMiddlewares, TServerContext> = (\n options: RequestServerOptions<TRegister, TMiddlewares>,\n) => RequestMiddlewareServerFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerOptions<TRegister, TMiddlewares> {\n request: Request\n pathname: string\n context: Expand<AssignAllServerRequestContext<TRegister, TMiddlewares>>\n next: RequestServerNextFn<TRegister, TMiddlewares>\n /**\n * Metadata about the server function being invoked.\n * This is only present when the request is handling a server function call.\n * For regular page requests, this will be undefined.\n */\n serverFnMeta?: ServerFnMeta\n}\n\nexport type RequestServerNextFn<TRegister, TMiddlewares> = <\n TServerContext = undefined,\n>(\n options?: RequestServerNextFnOptions<TServerContext>,\n) => RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext>\n\nexport interface RequestServerNextFnOptions<TServerContext> {\n context?: TServerContext\n}\n\nexport type RequestServerNextFnResult<TRegister, TMiddlewares, TServerContext> =\n | Promise<RequestServerResult<TRegister, TMiddlewares, TServerContext>>\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n\nexport type RequestMiddlewareServerFnResult<\n TRegister,\n TMiddlewares,\n TServerContext,\n> =\n | Promise<\n RequestServerResult<TRegister, TMiddlewares, TServerContext> | Response\n >\n | RequestServerResult<TRegister, TMiddlewares, TServerContext>\n | Response\n\nexport interface RequestServerResult<TRegister, TMiddlewares, TServerContext> {\n request: Request\n pathname: string\n context: Expand<\n AssignAllServerRequestContext<\n TRegister,\n TMiddlewares,\n undefined,\n TServerContext\n >\n >\n response: Response\n}\n\nexport interface RequestMiddlewareAfterServer<\n TRegister,\n TMiddlewares,\n TServerContext,\n> extends RequestMiddlewareWithTypes<TRegister, TMiddlewares, TServerContext> {}\n"],"mappings":";AAiCA,IAAa,oBAA4C,SAAS,WAAW;CAC3E,MAAM,kBAAkB;EACtB,MAAM;EACN,GAAI,UAAU;EACf;AAED,QAAO;EACL,SAAS;EACT,aAAa,eAAoB;AAC/B,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,YAAY,CAAC,CAC/C;;EAEH,iBAAiB,mBAAwB;AACvC,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,gBAAgB,CAAC,CACnD;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEH,SAAS,WAAgB;AACvB,UAAO,iBACL,EAAE,EACF,OAAO,OAAO,iBAAiB,EAAE,QAAQ,CAAC,CAC3C;;EAEJ"} |
+187
-261
@@ -1,3 +0,1 @@ | ||
| import { mergeHeaders } from "@tanstack/router-core/ssr/client"; | ||
| import { parseRedirect, isRedirect } from "@tanstack/router-core"; | ||
| import { TSS_SERVER_FUNCTION_FACTORY } from "./constants.js"; | ||
@@ -7,269 +5,197 @@ import { getStartOptions } from "./getStartOptions.js"; | ||
| import { createNullProtoObject, safeObjectMerge } from "./safeObjectMerge.js"; | ||
| const createServerFn = (options, __opts) => { | ||
| const resolvedOptions = __opts || options || {}; | ||
| if (typeof resolvedOptions.method === "undefined") { | ||
| resolvedOptions.method = "GET"; | ||
| } | ||
| const res = { | ||
| options: resolvedOptions, | ||
| middleware: (middleware) => { | ||
| const newMiddleware = [...resolvedOptions.middleware || []]; | ||
| middleware.map((m) => { | ||
| if (TSS_SERVER_FUNCTION_FACTORY in m) { | ||
| if (m.options.middleware) { | ||
| newMiddleware.push(...m.options.middleware); | ||
| } | ||
| } else { | ||
| newMiddleware.push(m); | ||
| } | ||
| }); | ||
| const newOptions = { | ||
| ...resolvedOptions, | ||
| middleware: newMiddleware | ||
| }; | ||
| const res2 = createServerFn(void 0, newOptions); | ||
| res2[TSS_SERVER_FUNCTION_FACTORY] = true; | ||
| return res2; | ||
| }, | ||
| inputValidator: (inputValidator) => { | ||
| const newOptions = { ...resolvedOptions, inputValidator }; | ||
| return createServerFn(void 0, newOptions); | ||
| }, | ||
| handler: (...args) => { | ||
| const [extractedFn, serverFn] = args; | ||
| const newOptions = { ...resolvedOptions, extractedFn, serverFn }; | ||
| const resolvedMiddleware = [ | ||
| ...newOptions.middleware || [], | ||
| serverFnBaseToMiddleware(newOptions) | ||
| ]; | ||
| extractedFn.method = resolvedOptions.method; | ||
| return Object.assign( | ||
| async (opts) => { | ||
| const result = await executeMiddleware(resolvedMiddleware, "client", { | ||
| ...extractedFn, | ||
| ...newOptions, | ||
| data: opts?.data, | ||
| headers: opts?.headers, | ||
| signal: opts?.signal, | ||
| fetch: opts?.fetch, | ||
| context: createNullProtoObject() | ||
| }); | ||
| const redirect = parseRedirect(result.error); | ||
| if (redirect) { | ||
| throw redirect; | ||
| } | ||
| if (result.error) throw result.error; | ||
| return result.result; | ||
| }, | ||
| { | ||
| // This copies over the URL, function ID | ||
| ...extractedFn, | ||
| // Expose the declared HTTP method so the server handler | ||
| // can reject mismatched methods before parsing payloads | ||
| method: resolvedOptions.method, | ||
| // The extracted function on the server-side calls | ||
| // this function | ||
| __executeServer: async (opts) => { | ||
| const startContext = getStartContextServerOnly(); | ||
| const serverContextAfterGlobalMiddlewares = startContext.contextAfterGlobalMiddlewares; | ||
| const ctx = { | ||
| ...extractedFn, | ||
| ...opts, | ||
| // Ensure we use the full serverFnMeta from the provider file's extractedFn | ||
| // (which has id, name, filename) rather than the partial one from SSR/client | ||
| // callers (which only has id) | ||
| serverFnMeta: extractedFn.serverFnMeta, | ||
| // Use safeObjectMerge for opts.context which comes from client | ||
| context: safeObjectMerge( | ||
| serverContextAfterGlobalMiddlewares, | ||
| opts.context | ||
| ), | ||
| request: startContext.request | ||
| }; | ||
| const result = await executeMiddleware( | ||
| resolvedMiddleware, | ||
| "server", | ||
| ctx | ||
| ).then((d) => ({ | ||
| // Only send the result and sendContext back to the client | ||
| result: d.result, | ||
| error: d.error, | ||
| context: d.sendContext | ||
| })); | ||
| return result; | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| }; | ||
| const fun = (options2) => { | ||
| const newOptions = { | ||
| ...resolvedOptions, | ||
| ...options2 | ||
| }; | ||
| return createServerFn(void 0, newOptions); | ||
| }; | ||
| return Object.assign(fun, res); | ||
| import { mergeHeaders } from "@tanstack/router-core/ssr/client"; | ||
| import { isRedirect, parseRedirect } from "@tanstack/router-core"; | ||
| //#region src/createServerFn.ts | ||
| var createServerFn = (options, __opts) => { | ||
| const resolvedOptions = __opts || options || {}; | ||
| if (typeof resolvedOptions.method === "undefined") resolvedOptions.method = "GET"; | ||
| const res = { | ||
| options: resolvedOptions, | ||
| middleware: (middleware) => { | ||
| const newMiddleware = [...resolvedOptions.middleware || []]; | ||
| middleware.map((m) => { | ||
| if (TSS_SERVER_FUNCTION_FACTORY in m) { | ||
| if (m.options.middleware) newMiddleware.push(...m.options.middleware); | ||
| } else newMiddleware.push(m); | ||
| }); | ||
| const res = createServerFn(void 0, { | ||
| ...resolvedOptions, | ||
| middleware: newMiddleware | ||
| }); | ||
| res[TSS_SERVER_FUNCTION_FACTORY] = true; | ||
| return res; | ||
| }, | ||
| inputValidator: (inputValidator) => { | ||
| return createServerFn(void 0, { | ||
| ...resolvedOptions, | ||
| inputValidator | ||
| }); | ||
| }, | ||
| handler: (...args) => { | ||
| const [extractedFn, serverFn] = args; | ||
| const newOptions = { | ||
| ...resolvedOptions, | ||
| extractedFn, | ||
| serverFn | ||
| }; | ||
| const resolvedMiddleware = [...newOptions.middleware || [], serverFnBaseToMiddleware(newOptions)]; | ||
| extractedFn.method = resolvedOptions.method; | ||
| return Object.assign(async (opts) => { | ||
| const result = await executeMiddleware(resolvedMiddleware, "client", { | ||
| ...extractedFn, | ||
| ...newOptions, | ||
| data: opts?.data, | ||
| headers: opts?.headers, | ||
| signal: opts?.signal, | ||
| fetch: opts?.fetch, | ||
| context: createNullProtoObject() | ||
| }); | ||
| const redirect = parseRedirect(result.error); | ||
| if (redirect) throw redirect; | ||
| if (result.error) throw result.error; | ||
| return result.result; | ||
| }, { | ||
| ...extractedFn, | ||
| method: resolvedOptions.method, | ||
| __executeServer: async (opts) => { | ||
| const startContext = getStartContextServerOnly(); | ||
| const serverContextAfterGlobalMiddlewares = startContext.contextAfterGlobalMiddlewares; | ||
| return await executeMiddleware(resolvedMiddleware, "server", { | ||
| ...extractedFn, | ||
| ...opts, | ||
| serverFnMeta: extractedFn.serverFnMeta, | ||
| context: safeObjectMerge(serverContextAfterGlobalMiddlewares, opts.context), | ||
| request: startContext.request | ||
| }).then((d) => ({ | ||
| result: d.result, | ||
| error: d.error, | ||
| context: d.sendContext | ||
| })); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| const fun = (options) => { | ||
| return createServerFn(void 0, { | ||
| ...resolvedOptions, | ||
| ...options | ||
| }); | ||
| }; | ||
| return Object.assign(fun, res); | ||
| }; | ||
| async function executeMiddleware(middlewares, env, opts) { | ||
| const globalMiddlewares = getStartOptions()?.functionMiddleware || []; | ||
| let flattenedMiddlewares = flattenMiddlewares([ | ||
| ...globalMiddlewares, | ||
| ...middlewares | ||
| ]); | ||
| if (env === "server") { | ||
| const startContext = getStartContextServerOnly({ throwIfNotFound: false }); | ||
| if (startContext?.executedRequestMiddlewares) { | ||
| flattenedMiddlewares = flattenedMiddlewares.filter( | ||
| (m) => !startContext.executedRequestMiddlewares.has(m) | ||
| ); | ||
| } | ||
| } | ||
| const callNextMiddleware = async (ctx) => { | ||
| const nextMiddleware = flattenedMiddlewares.shift(); | ||
| if (!nextMiddleware) { | ||
| return ctx; | ||
| } | ||
| try { | ||
| if ("inputValidator" in nextMiddleware.options && nextMiddleware.options.inputValidator && env === "server") { | ||
| ctx.data = await execValidator( | ||
| nextMiddleware.options.inputValidator, | ||
| ctx.data | ||
| ); | ||
| } | ||
| let middlewareFn = void 0; | ||
| if (env === "client") { | ||
| if ("client" in nextMiddleware.options) { | ||
| middlewareFn = nextMiddleware.options.client; | ||
| } | ||
| } else if ("server" in nextMiddleware.options) { | ||
| middlewareFn = nextMiddleware.options.server; | ||
| } | ||
| if (middlewareFn) { | ||
| const userNext = async (userCtx = {}) => { | ||
| const nextCtx = { | ||
| ...ctx, | ||
| ...userCtx, | ||
| context: safeObjectMerge(ctx.context, userCtx.context), | ||
| sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext), | ||
| headers: mergeHeaders(ctx.headers, userCtx.headers), | ||
| _callSiteFetch: ctx._callSiteFetch, | ||
| fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch, | ||
| result: userCtx.result !== void 0 ? userCtx.result : userCtx instanceof Response ? userCtx : ctx.result, | ||
| error: userCtx.error ?? ctx.error | ||
| }; | ||
| const result2 = await callNextMiddleware(nextCtx); | ||
| if (result2.error) { | ||
| throw result2.error; | ||
| } | ||
| return result2; | ||
| }; | ||
| const result = await middlewareFn({ | ||
| ...ctx, | ||
| next: userNext | ||
| }); | ||
| if (isRedirect(result)) { | ||
| return { | ||
| ...ctx, | ||
| error: result | ||
| }; | ||
| } | ||
| if (result instanceof Response) { | ||
| return { | ||
| ...ctx, | ||
| result | ||
| }; | ||
| } | ||
| if (!result) { | ||
| throw new Error( | ||
| "User middleware returned undefined. You must call next() or return a result in your middlewares." | ||
| ); | ||
| } | ||
| return result; | ||
| } | ||
| return callNextMiddleware(ctx); | ||
| } catch (error) { | ||
| return { | ||
| ...ctx, | ||
| error | ||
| }; | ||
| } | ||
| }; | ||
| return callNextMiddleware({ | ||
| ...opts, | ||
| headers: opts.headers || {}, | ||
| sendContext: opts.sendContext || {}, | ||
| context: opts.context || createNullProtoObject(), | ||
| _callSiteFetch: opts.fetch | ||
| }); | ||
| let flattenedMiddlewares = flattenMiddlewares([...getStartOptions()?.functionMiddleware || [], ...middlewares]); | ||
| if (env === "server") { | ||
| const startContext = getStartContextServerOnly({ throwIfNotFound: false }); | ||
| if (startContext?.executedRequestMiddlewares) flattenedMiddlewares = flattenedMiddlewares.filter((m) => !startContext.executedRequestMiddlewares.has(m)); | ||
| } | ||
| const callNextMiddleware = async (ctx) => { | ||
| const nextMiddleware = flattenedMiddlewares.shift(); | ||
| if (!nextMiddleware) return ctx; | ||
| try { | ||
| if ("inputValidator" in nextMiddleware.options && nextMiddleware.options.inputValidator && env === "server") ctx.data = await execValidator(nextMiddleware.options.inputValidator, ctx.data); | ||
| let middlewareFn = void 0; | ||
| if (env === "client") { | ||
| if ("client" in nextMiddleware.options) middlewareFn = nextMiddleware.options.client; | ||
| } else if ("server" in nextMiddleware.options) middlewareFn = nextMiddleware.options.server; | ||
| if (middlewareFn) { | ||
| const userNext = async (userCtx = {}) => { | ||
| const result = await callNextMiddleware({ | ||
| ...ctx, | ||
| ...userCtx, | ||
| context: safeObjectMerge(ctx.context, userCtx.context), | ||
| sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext), | ||
| headers: mergeHeaders(ctx.headers, userCtx.headers), | ||
| _callSiteFetch: ctx._callSiteFetch, | ||
| fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch, | ||
| result: userCtx.result !== void 0 ? userCtx.result : userCtx instanceof Response ? userCtx : ctx.result, | ||
| error: userCtx.error ?? ctx.error | ||
| }); | ||
| if (result.error) throw result.error; | ||
| return result; | ||
| }; | ||
| const result = await middlewareFn({ | ||
| ...ctx, | ||
| next: userNext | ||
| }); | ||
| if (isRedirect(result)) return { | ||
| ...ctx, | ||
| error: result | ||
| }; | ||
| if (result instanceof Response) return { | ||
| ...ctx, | ||
| result | ||
| }; | ||
| if (!result) throw new Error("User middleware returned undefined. You must call next() or return a result in your middlewares."); | ||
| return result; | ||
| } | ||
| return callNextMiddleware(ctx); | ||
| } catch (error) { | ||
| return { | ||
| ...ctx, | ||
| error | ||
| }; | ||
| } | ||
| }; | ||
| return callNextMiddleware({ | ||
| ...opts, | ||
| headers: opts.headers || {}, | ||
| sendContext: opts.sendContext || {}, | ||
| context: opts.context || createNullProtoObject(), | ||
| _callSiteFetch: opts.fetch | ||
| }); | ||
| } | ||
| function flattenMiddlewares(middlewares, maxDepth = 100) { | ||
| const seen = /* @__PURE__ */ new Set(); | ||
| const flattened = []; | ||
| const recurse = (middleware, depth) => { | ||
| if (depth > maxDepth) { | ||
| throw new Error( | ||
| `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.` | ||
| ); | ||
| } | ||
| middleware.forEach((m) => { | ||
| if (m.options.middleware) { | ||
| recurse(m.options.middleware, depth + 1); | ||
| } | ||
| if (!seen.has(m)) { | ||
| seen.add(m); | ||
| flattened.push(m); | ||
| } | ||
| }); | ||
| }; | ||
| recurse(middlewares, 0); | ||
| return flattened; | ||
| const seen = /* @__PURE__ */ new Set(); | ||
| const flattened = []; | ||
| const recurse = (middleware, depth) => { | ||
| if (depth > maxDepth) throw new Error(`Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`); | ||
| middleware.forEach((m) => { | ||
| if (m.options.middleware) recurse(m.options.middleware, depth + 1); | ||
| if (!seen.has(m)) { | ||
| seen.add(m); | ||
| flattened.push(m); | ||
| } | ||
| }); | ||
| }; | ||
| recurse(middlewares, 0); | ||
| return flattened; | ||
| } | ||
| async function execValidator(validator, input) { | ||
| if (validator == null) return {}; | ||
| if ("~standard" in validator) { | ||
| const result = await validator["~standard"].validate(input); | ||
| if (result.issues) | ||
| throw new Error(JSON.stringify(result.issues, void 0, 2)); | ||
| return result.value; | ||
| } | ||
| if ("parse" in validator) { | ||
| return validator.parse(input); | ||
| } | ||
| if (typeof validator === "function") { | ||
| return validator(input); | ||
| } | ||
| throw new Error("Invalid validator type!"); | ||
| if (validator == null) return {}; | ||
| if ("~standard" in validator) { | ||
| const result = await validator["~standard"].validate(input); | ||
| if (result.issues) throw new Error(JSON.stringify(result.issues, void 0, 2)); | ||
| return result.value; | ||
| } | ||
| if ("parse" in validator) return validator.parse(input); | ||
| if (typeof validator === "function") return validator(input); | ||
| throw new Error("Invalid validator type!"); | ||
| } | ||
| function serverFnBaseToMiddleware(options) { | ||
| return { | ||
| "~types": void 0, | ||
| options: { | ||
| inputValidator: options.inputValidator, | ||
| client: async ({ next, sendContext, fetch, ...ctx }) => { | ||
| const payload = { | ||
| ...ctx, | ||
| // switch the sendContext over to context | ||
| context: sendContext, | ||
| fetch | ||
| }; | ||
| const res = await options.extractedFn?.(payload); | ||
| return next(res); | ||
| }, | ||
| server: async ({ next, ...ctx }) => { | ||
| const result = await options.serverFn?.(ctx); | ||
| return next({ | ||
| ...ctx, | ||
| result | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
| return { | ||
| "~types": void 0, | ||
| options: { | ||
| inputValidator: options.inputValidator, | ||
| client: async ({ next, sendContext, fetch, ...ctx }) => { | ||
| const payload = { | ||
| ...ctx, | ||
| context: sendContext, | ||
| fetch | ||
| }; | ||
| return next(await options.extractedFn?.(payload)); | ||
| }, | ||
| server: async ({ next, ...ctx }) => { | ||
| const result = await options.serverFn?.(ctx); | ||
| return next({ | ||
| ...ctx, | ||
| result | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| export { | ||
| createServerFn, | ||
| execValidator, | ||
| executeMiddleware, | ||
| flattenMiddlewares | ||
| }; | ||
| //# sourceMappingURL=createServerFn.js.map | ||
| //#endregion | ||
| export { createServerFn, execValidator, executeMiddleware, flattenMiddlewares }; | ||
| //# sourceMappingURL=createServerFn.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"createServerFn.js","sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n 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,\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 // Propagate the declared HTTP method onto the extracted handler\n // so the manifest-exported symbol (resolved by getServerFnById)\n // carries `method`, enabling the server handler to reject\n // mismatched HTTP methods before parsing request payloads.\n ;(extractedFn as any).method = resolvedOptions.method\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n fetch: opts?.fetch,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // Expose the declared HTTP method so the server handler\n // can reject mismatched methods before parsing payloads\n method: resolvedOptions.method,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n // Use safeObjectMerge for opts.context which comes from client\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Use safeObjectMerge for opts.context which comes from client\n context: safeObjectMerge(\n serverContextAfterGlobalMiddlewares,\n opts.context,\n ),\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions) as any\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n if (\n 'inputValidator' in nextMiddleware.options &&\n nextMiddleware.options.inputValidator &&\n env === 'server'\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(\n nextMiddleware.options.inputValidator,\n ctx.data,\n )\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n _callSiteFetch: ctx._callSiteFetch,\n fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext,\n })\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n _callSiteFetch: opts.fetch,\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n method: Method\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport type CustomFetch = typeof globalThis.fetch\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n> = {\n method: TMethod\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> = TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {\n <TNewMethod extends Method = TMethod>(options?: {\n method?: TNewMethod\n }): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator\n >\n}\n\nexport type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares> = <\n TInputValidator,\n>(\n inputValidator: ConstrainValidator<TRegister, TMethod, TInputValidator>,\n) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>\n extends\n ServerFnWithTypes<TRegister, TMethod, undefined, undefined, undefined>,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined>,\n ServerFnValidator<TRegister, TMethod, undefined>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined> {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n method: TMethod\n middlewares: TMiddlewares\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n fetch?: CustomFetch\n /** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */\n _callSiteFetch?: CustomFetch\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n '~types': undefined!,\n options: {\n inputValidator: options.inputValidator,\n client: async ({ next, sendContext, fetch, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n fetch,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res)\n },\n server: async ({ next, ...ctx }) => {\n // Execute the server function\n const result = await options.serverFn?.(ctx as TODO)\n\n return next({\n ...ctx,\n result,\n } as any) as unknown as FunctionMiddlewareServerFnResult<\n any,\n any,\n any,\n any,\n any\n >\n },\n },\n }\n}\n"],"names":["res","options","result"],"mappings":"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"} | ||
| {"version":3,"file":"createServerFn.js","names":[],"sources":["../../src/createServerFn.ts"],"sourcesContent":["import { mergeHeaders } from '@tanstack/router-core/ssr/client'\n\nimport { isRedirect, parseRedirect } from '@tanstack/router-core'\nimport { TSS_SERVER_FUNCTION_FACTORY } from './constants'\nimport { getStartOptions } from './getStartOptions'\nimport { getStartContextServerOnly } from './getStartContextServerOnly'\nimport { createNullProtoObject, safeObjectMerge } from './safeObjectMerge'\nimport type {\n ClientFnMeta,\n ServerFnMeta,\n TSS_SERVER_FUNCTION,\n} from './constants'\nimport type {\n AnyValidator,\n Constrain,\n Expand,\n Register,\n RegisteredSerializableInput,\n ResolveValidatorInput,\n ValidateSerializable,\n ValidateSerializableInput,\n Validator,\n} from '@tanstack/router-core'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n AssignAllServerFnContext,\n 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,\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 // Propagate the declared HTTP method onto the extracted handler\n // so the manifest-exported symbol (resolved by getServerFnById)\n // carries `method`, enabling the server handler to reject\n // mismatched HTTP methods before parsing request payloads.\n ;(extractedFn as any).method = resolvedOptions.method\n\n return Object.assign(\n async (opts?: CompiledFetcherFnOptions) => {\n // Start by executing the client-side middleware chain\n const result = await executeMiddleware(resolvedMiddleware, 'client', {\n ...extractedFn,\n ...newOptions,\n data: opts?.data as any,\n headers: opts?.headers,\n signal: opts?.signal,\n fetch: opts?.fetch,\n context: createNullProtoObject(),\n })\n\n const redirect = parseRedirect(result.error)\n if (redirect) {\n throw redirect\n }\n\n if (result.error) throw result.error\n return result.result\n },\n {\n // This copies over the URL, function ID\n ...extractedFn,\n // Expose the declared HTTP method so the server handler\n // can reject mismatched methods before parsing payloads\n method: resolvedOptions.method,\n // The extracted function on the server-side calls\n // this function\n __executeServer: async (opts: any) => {\n const startContext = getStartContextServerOnly()\n const serverContextAfterGlobalMiddlewares =\n startContext.contextAfterGlobalMiddlewares\n // Use safeObjectMerge for opts.context which comes from client\n const ctx = {\n ...extractedFn,\n ...opts,\n // Ensure we use the full serverFnMeta from the provider file's extractedFn\n // (which has id, name, filename) rather than the partial one from SSR/client\n // callers (which only has id)\n serverFnMeta: extractedFn.serverFnMeta,\n // Use safeObjectMerge for opts.context which comes from client\n context: safeObjectMerge(\n serverContextAfterGlobalMiddlewares,\n opts.context,\n ),\n request: startContext.request,\n }\n\n const result = await executeMiddleware(\n resolvedMiddleware,\n 'server',\n ctx,\n ).then((d) => ({\n // Only send the result and sendContext back to the client\n result: d.result,\n error: d.error,\n context: d.sendContext,\n }))\n\n return result\n },\n },\n ) as any\n },\n } as ServerFnBuilder<Register, Method>\n const fun = (options?: { method?: Method }) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions) as any\n }\n return Object.assign(fun, res) as any\n}\n\nexport async function executeMiddleware(\n middlewares: Array<AnyFunctionMiddleware | AnyRequestMiddleware>,\n env: 'client' | 'server',\n opts: ServerFnMiddlewareOptions,\n): Promise<ServerFnMiddlewareResult> {\n const globalMiddlewares = getStartOptions()?.functionMiddleware || []\n let flattenedMiddlewares = flattenMiddlewares([\n ...globalMiddlewares,\n ...middlewares,\n ])\n\n // On server, filter out middlewares that already executed in the request phase\n // to prevent duplicate execution (issue #5239)\n if (env === 'server') {\n const startContext = getStartContextServerOnly({ throwIfNotFound: false })\n if (startContext?.executedRequestMiddlewares) {\n flattenedMiddlewares = flattenedMiddlewares.filter(\n (m) => !startContext.executedRequestMiddlewares.has(m),\n )\n }\n }\n\n const callNextMiddleware: NextFn = async (ctx) => {\n // Get the next middleware\n const nextMiddleware = flattenedMiddlewares.shift()\n\n // If there are no more middlewares, return the context\n if (!nextMiddleware) {\n return ctx\n }\n\n // Execute the middleware\n try {\n if (\n 'inputValidator' in nextMiddleware.options &&\n nextMiddleware.options.inputValidator &&\n env === 'server'\n ) {\n // Execute the middleware's input function\n ctx.data = await execValidator(\n nextMiddleware.options.inputValidator,\n ctx.data,\n )\n }\n\n let middlewareFn: MiddlewareFn | undefined = undefined\n if (env === 'client') {\n if ('client' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.client as\n | MiddlewareFn\n | undefined\n }\n }\n // env === 'server'\n else if ('server' in nextMiddleware.options) {\n middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined\n }\n\n if (middlewareFn) {\n const userNext = async (\n userCtx: ServerFnMiddlewareResult | undefined = {} as any,\n ) => {\n // Return the next middleware\n // Use safeObjectMerge for context objects to prevent prototype pollution\n const nextCtx = {\n ...ctx,\n ...userCtx,\n context: safeObjectMerge(ctx.context, userCtx.context),\n sendContext: safeObjectMerge(ctx.sendContext, userCtx.sendContext),\n headers: mergeHeaders(ctx.headers, userCtx.headers),\n _callSiteFetch: ctx._callSiteFetch,\n fetch: ctx._callSiteFetch ?? userCtx.fetch ?? ctx.fetch,\n result:\n userCtx.result !== undefined\n ? userCtx.result\n : userCtx instanceof Response\n ? userCtx\n : (ctx as any).result,\n error: userCtx.error ?? (ctx as any).error,\n }\n\n const result = await callNextMiddleware(nextCtx)\n\n if (result.error) {\n throw result.error\n }\n\n return result\n }\n\n // Execute the middleware\n const result = await middlewareFn({\n ...ctx,\n next: userNext,\n })\n\n // If result is NOT a ctx object, we need to return it as\n // the { result }\n if (isRedirect(result)) {\n return {\n ...ctx,\n error: result,\n }\n }\n\n if (result instanceof Response) {\n return {\n ...ctx,\n result,\n }\n }\n\n if (!(result as any)) {\n throw new Error(\n 'User middleware returned undefined. You must call next() or return a result in your middlewares.',\n )\n }\n\n return result\n }\n\n return callNextMiddleware(ctx)\n } catch (error: any) {\n return {\n ...ctx,\n error,\n }\n }\n }\n\n // Start the middleware chain\n return callNextMiddleware({\n ...opts,\n headers: opts.headers || {},\n sendContext: opts.sendContext || {},\n context: opts.context || createNullProtoObject(),\n _callSiteFetch: opts.fetch,\n })\n}\n\nexport type CompiledFetcherFnOptions = {\n method: Method\n data: unknown\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n context?: any\n}\n\nexport type Fetcher<TMiddlewares, TInputValidator, TResponse> =\n undefined extends IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n ? OptionalFetcher<TMiddlewares, TInputValidator, TResponse>\n : RequiredFetcher<TMiddlewares, TInputValidator, TResponse>\n\nexport interface FetcherBase {\n [TSS_SERVER_FUNCTION]: true\n url: string\n method: Method\n __executeServer: (opts: {\n method: Method\n data: unknown\n headers?: HeadersInit\n context?: any\n }) => Promise<unknown>\n}\n\nexport interface OptionalFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n options?: OptionalFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport interface RequiredFetcher<\n TMiddlewares,\n TInputValidator,\n TResponse,\n> extends FetcherBase {\n (\n opts: RequiredFetcherDataOptions<TMiddlewares, TInputValidator>,\n ): Promise<Awaited<TResponse>>\n}\n\nexport type CustomFetch = typeof globalThis.fetch\n\nexport type FetcherBaseOptions = {\n headers?: HeadersInit\n signal?: AbortSignal\n fetch?: CustomFetch\n}\n\nexport interface OptionalFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport interface RequiredFetcherDataOptions<\n TMiddlewares,\n TInputValidator,\n> extends FetcherBaseOptions {\n data: Expand<IntersectAllValidatorInputs<TMiddlewares, TInputValidator>>\n}\n\nexport type RscStream<T> = {\n __cacheState: T\n}\n\nexport type Method = 'GET' | 'POST'\n\nexport type ServerFnReturnType<TRegister, TResponse> =\n TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U>>\n : TResponse extends Response\n ? TResponse\n : ValidateSerializableInput<TRegister, TResponse>\n\nexport type ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse>\n\nexport interface ServerFnCtx<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n> {\n data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>\n serverFnMeta: ServerFnMeta\n context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>\n method: TMethod\n}\n\nexport type CompiledFetcherFn<TRegister, TResponse> = {\n (\n opts: CompiledFetcherFnOptions & ServerFnBaseOptions<TRegister, Method>,\n ): Promise<TResponse>\n url: string\n serverFnMeta: ServerFnMeta\n}\n\nexport type ServerFnBaseOptions<\n TRegister,\n TMethod extends Method = 'GET',\n TResponse = unknown,\n TMiddlewares = unknown,\n TInputValidator = unknown,\n> = {\n method: TMethod\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator>\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> = TMethod extends 'POST'\n ? ResolveValidatorInput<TInputValidator> extends FormData\n ? ResolveValidatorInput<TInputValidator>\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n : ValidateSerializable<\n ResolveValidatorInput<TInputValidator>,\n RegisteredSerializableInput<TRegister>\n >\n\nexport type ValidateValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator>\n\nexport type AppendMiddlewares<TMiddlewares, TNewMiddlewares> =\n TMiddlewares extends ReadonlyArray<any>\n ? TNewMiddlewares extends ReadonlyArray<any>\n ? readonly [...TMiddlewares, ...TNewMiddlewares]\n : TMiddlewares\n : TNewMiddlewares\n\nexport interface ServerFnMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n middleware: <const TNewMiddlewares>(\n middlewares: Constrain<\n TNewMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware | AnyServerFn>\n >,\n ) => ServerFnAfterMiddleware<\n TRegister,\n TMethod,\n AppendMiddlewares<TMiddlewares, TNewMiddlewares>,\n TInputValidator\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {\n <TNewMethod extends Method = TMethod>(options?: {\n method?: TNewMethod\n }): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator\n >\n}\n\nexport type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares> = <\n TInputValidator,\n>(\n inputValidator: ConstrainValidator<TRegister, TMethod, TInputValidator>,\n) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator>,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined\n >,\n ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator> {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<TRegister, TMethod extends Method = 'GET'>\n extends\n ServerFnWithTypes<TRegister, TMethod, undefined, undefined, undefined>,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined>,\n ServerFnValidator<TRegister, TMethod, undefined>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined> {\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n}\n\nexport interface ServerFnWithTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, any, any, any, any>\n\nexport interface ServerFnTypes<\n in out TRegister,\n in out TMethod extends Method,\n in out TMiddlewares,\n in out TInputValidator,\n in out TResponse,\n> {\n method: TMethod\n middlewares: TMiddlewares\n inputValidator: TInputValidator\n response: TResponse\n allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>\n allInput: IntersectAllValidatorInputs<TMiddlewares, TInputValidator>\n allOutput: IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>\n}\n\nexport function flattenMiddlewares<\n T extends AnyFunctionMiddleware | AnyRequestMiddleware,\n>(middlewares: Array<T>, maxDepth: number = 100): Array<T> {\n const seen = new Set<T>()\n const flattened: Array<T> = []\n\n const recurse = (middleware: Array<T>, depth: number) => {\n if (depth > maxDepth) {\n throw new Error(\n `Middleware nesting depth exceeded maximum of ${maxDepth}. Check for circular references.`,\n )\n }\n middleware.forEach((m) => {\n if (m.options.middleware) {\n recurse(m.options.middleware as Array<T>, depth + 1)\n }\n\n if (!seen.has(m)) {\n seen.add(m)\n flattened.push(m)\n }\n })\n }\n\n recurse(middlewares, 0)\n\n return flattened\n}\n\nexport type ServerFnMiddlewareOptions = {\n method: Method\n data: any\n headers?: HeadersInit\n signal?: AbortSignal\n sendContext?: any\n context?: any\n serverFnMeta: ClientFnMeta\n fetch?: CustomFetch\n /** @internal - Preserves the call-site fetch to ensure it has highest priority over middleware */\n _callSiteFetch?: CustomFetch\n}\n\nexport type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {\n result?: unknown\n error?: unknown\n}\n\nexport type NextFn = (\n ctx: ServerFnMiddlewareResult,\n) => Promise<ServerFnMiddlewareResult>\n\nexport type MiddlewareFn = (\n ctx: ServerFnMiddlewareOptions & {\n next: NextFn\n },\n) => Promise<ServerFnMiddlewareResult>\n\nexport async function execValidator(\n validator: AnyValidator,\n input: unknown,\n): Promise<unknown> {\n if (validator == null) return {}\n\n if ('~standard' in validator) {\n const result = await validator['~standard'].validate(input)\n\n if (result.issues)\n throw new Error(JSON.stringify(result.issues, undefined, 2))\n\n return result.value\n }\n\n if ('parse' in validator) {\n return validator.parse(input)\n }\n\n if (typeof validator === 'function') {\n return validator(input)\n }\n\n throw new Error('Invalid validator type!')\n}\n\nfunction serverFnBaseToMiddleware(\n options: ServerFnBaseOptions<any, any, any, any, any>,\n): AnyFunctionMiddleware {\n return {\n '~types': undefined!,\n options: {\n inputValidator: options.inputValidator,\n client: async ({ next, sendContext, fetch, ...ctx }) => {\n const payload = {\n ...ctx,\n // switch the sendContext over to context\n context: sendContext,\n fetch,\n } as any\n\n // Execute the extracted function\n // but not before serializing the context\n const res = await options.extractedFn?.(payload)\n\n return next(res)\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"],"mappings":"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"} |
+25
-29
| import { createMiddleware } from "./createMiddleware.js"; | ||
| //#region src/createStart.ts | ||
| function dedupeSerializationAdapters(deduped, serializationAdapters) { | ||
| for (let i = 0, len = serializationAdapters.length; i < len; i++) { | ||
| const current = serializationAdapters[i]; | ||
| if (!deduped.has(current)) { | ||
| deduped.add(current); | ||
| if (current.extends) { | ||
| dedupeSerializationAdapters(deduped, current.extends); | ||
| } | ||
| } | ||
| } | ||
| for (let i = 0, len = serializationAdapters.length; i < len; i++) { | ||
| const current = serializationAdapters[i]; | ||
| if (!deduped.has(current)) { | ||
| deduped.add(current); | ||
| if (current.extends) dedupeSerializationAdapters(deduped, current.extends); | ||
| } | ||
| } | ||
| } | ||
| const createStart = (getOptions) => { | ||
| return { | ||
| getOptions: async () => { | ||
| const options = await getOptions(); | ||
| if (options.serializationAdapters) { | ||
| const deduped = /* @__PURE__ */ new Set(); | ||
| dedupeSerializationAdapters( | ||
| deduped, | ||
| options.serializationAdapters | ||
| ); | ||
| options.serializationAdapters = Array.from(deduped); | ||
| } | ||
| return options; | ||
| }, | ||
| createMiddleware | ||
| }; | ||
| var createStart = (getOptions) => { | ||
| return { | ||
| getOptions: async () => { | ||
| const options = await getOptions(); | ||
| if (options.serializationAdapters) { | ||
| const deduped = /* @__PURE__ */ new Set(); | ||
| dedupeSerializationAdapters(deduped, options.serializationAdapters); | ||
| options.serializationAdapters = Array.from(deduped); | ||
| } | ||
| return options; | ||
| }, | ||
| createMiddleware | ||
| }; | ||
| }; | ||
| export { | ||
| createStart | ||
| }; | ||
| //# sourceMappingURL=createStart.js.map | ||
| //#endregion | ||
| export { createStart }; | ||
| //# sourceMappingURL=createStart.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"createStart.js","sources":["../../src/createStart.ts"],"sourcesContent":["import { createMiddleware } from './createMiddleware'\nimport type { TSS_SERVER_FUNCTION } from './constants'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n CreateMiddlewareFn,\n} from './createMiddleware'\nimport type { CustomFetch } from './createServerFn'\nimport type {\n AnySerializationAdapter,\n Register,\n SSROption,\n} from '@tanstack/router-core'\n\nexport interface StartInstanceOptions<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n '~types': StartInstanceTypes<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n serializationAdapters?: TSerializationAdapters\n defaultSsr?: TDefaultSsr\n requestMiddleware?: TRequestMiddlewares\n functionMiddleware?: TFunctionMiddlewares\n /**\n * Configuration options for server functions.\n */\n serverFns?: {\n /**\n * A custom fetch implementation to use for all server function calls.\n * This can be overridden by middleware or at the call site.\n *\n * Precedence (highest to lowest):\n * 1. Call site: `serverFn({ fetch: customFetch })`\n * 2. Later middleware: Last middleware in chain that provides `fetch`\n * 3. Earlier middleware: First middleware in chain that provides `fetch`\n * 4. createStart: `createStart({ serverFns: { fetch: customFetch } })`\n * 5. Default: Global `fetch` function\n *\n * @note Only applies on the client side. During SSR, server functions are called directly.\n */\n fetch?: CustomFetch\n }\n}\n\nexport interface StartInstance<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n getOptions: () =>\n | Promise<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n >\n | StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n createMiddleware: CreateMiddlewareFn<Register>\n}\n\nexport interface StartInstanceTypes<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n serializationAdapters: TSerializationAdapters\n defaultSsr: TDefaultSsr\n requestMiddleware: TRequestMiddlewares\n functionMiddleware: TFunctionMiddlewares\n}\n\nfunction dedupeSerializationAdapters(\n deduped: Set<AnySerializationAdapter>,\n serializationAdapters: Array<AnySerializationAdapter>,\n): void {\n for (let i = 0, len = serializationAdapters.length; i < len; i++) {\n const current = serializationAdapters[i]!\n if (!deduped.has(current)) {\n deduped.add(current)\n if (current.extends) {\n dedupeSerializationAdapters(deduped, current.extends)\n }\n }\n }\n}\n\nexport const createStart = <\n const TSerializationAdapters extends ReadonlyArray<AnySerializationAdapter> =\n [],\n TDefaultSsr extends SSROption = SSROption,\n const TRequestMiddlewares extends ReadonlyArray<AnyRequestMiddleware> = [],\n const TFunctionMiddlewares extends ReadonlyArray<AnyFunctionMiddleware> = [],\n>(\n getOptions: () =>\n | Promise<\n Omit<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >,\n '~types'\n >\n >\n | Omit<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >,\n '~types'\n >,\n): StartInstance<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n> => {\n return {\n getOptions: async () => {\n const options = await getOptions()\n if (options.serializationAdapters) {\n const deduped = new Set<AnySerializationAdapter>()\n dedupeSerializationAdapters(\n deduped,\n options.serializationAdapters as unknown as Array<AnySerializationAdapter>,\n )\n options.serializationAdapters = Array.from(deduped) as any\n }\n return options\n },\n createMiddleware: createMiddleware,\n } as StartInstance<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n}\n\nexport type AnyStartInstance = StartInstance<any, any, any, any>\nexport type AnyStartInstanceOptions = StartInstanceOptions<any, any, any, any>\n\ndeclare module '@tanstack/router-core' {\n interface SerializableExtensions {\n serverFn: { [TSS_SERVER_FUNCTION]: true }\n }\n}\n"],"names":[],"mappings":";AAuFA,SAAS,4BACP,SACA,uBACM;AACN,WAAS,IAAI,GAAG,MAAM,sBAAsB,QAAQ,IAAI,KAAK,KAAK;AAChE,UAAM,UAAU,sBAAsB,CAAC;AACvC,QAAI,CAAC,QAAQ,IAAI,OAAO,GAAG;AACzB,cAAQ,IAAI,OAAO;AACnB,UAAI,QAAQ,SAAS;AACnB,oCAA4B,SAAS,QAAQ,OAAO;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,cAAc,CAOzB,eA0BG;AACH,SAAO;AAAA,IACL,YAAY,YAAY;AACtB,YAAM,UAAU,MAAM,WAAA;AACtB,UAAI,QAAQ,uBAAuB;AACjC,cAAM,8BAAc,IAAA;AACpB;AAAA,UACE;AAAA,UACA,QAAQ;AAAA,QAAA;AAEV,gBAAQ,wBAAwB,MAAM,KAAK,OAAO;AAAA,MACpD;AACA,aAAO;AAAA,IACT;AAAA,IACA;AAAA,EAAA;AAOJ;"} | ||
| {"version":3,"file":"createStart.js","names":[],"sources":["../../src/createStart.ts"],"sourcesContent":["import { createMiddleware } from './createMiddleware'\nimport type { TSS_SERVER_FUNCTION } from './constants'\nimport type {\n AnyFunctionMiddleware,\n AnyRequestMiddleware,\n CreateMiddlewareFn,\n} from './createMiddleware'\nimport type { CustomFetch } from './createServerFn'\nimport type {\n AnySerializationAdapter,\n Register,\n SSROption,\n} from '@tanstack/router-core'\n\nexport interface StartInstanceOptions<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n '~types': StartInstanceTypes<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n serializationAdapters?: TSerializationAdapters\n defaultSsr?: TDefaultSsr\n requestMiddleware?: TRequestMiddlewares\n functionMiddleware?: TFunctionMiddlewares\n /**\n * Configuration options for server functions.\n */\n serverFns?: {\n /**\n * A custom fetch implementation to use for all server function calls.\n * This can be overridden by middleware or at the call site.\n *\n * Precedence (highest to lowest):\n * 1. Call site: `serverFn({ fetch: customFetch })`\n * 2. Later middleware: Last middleware in chain that provides `fetch`\n * 3. Earlier middleware: First middleware in chain that provides `fetch`\n * 4. createStart: `createStart({ serverFns: { fetch: customFetch } })`\n * 5. Default: Global `fetch` function\n *\n * @note Only applies on the client side. During SSR, server functions are called directly.\n */\n fetch?: CustomFetch\n }\n}\n\nexport interface StartInstance<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n getOptions: () =>\n | Promise<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n >\n | StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n createMiddleware: CreateMiddlewareFn<Register>\n}\n\nexport interface StartInstanceTypes<\n in out TSerializationAdapters,\n in out TDefaultSsr,\n in out TRequestMiddlewares,\n in out TFunctionMiddlewares,\n> {\n serializationAdapters: TSerializationAdapters\n defaultSsr: TDefaultSsr\n requestMiddleware: TRequestMiddlewares\n functionMiddleware: TFunctionMiddlewares\n}\n\nfunction dedupeSerializationAdapters(\n deduped: Set<AnySerializationAdapter>,\n serializationAdapters: Array<AnySerializationAdapter>,\n): void {\n for (let i = 0, len = serializationAdapters.length; i < len; i++) {\n const current = serializationAdapters[i]!\n if (!deduped.has(current)) {\n deduped.add(current)\n if (current.extends) {\n dedupeSerializationAdapters(deduped, current.extends)\n }\n }\n }\n}\n\nexport const createStart = <\n const TSerializationAdapters extends ReadonlyArray<AnySerializationAdapter> =\n [],\n TDefaultSsr extends SSROption = SSROption,\n const TRequestMiddlewares extends ReadonlyArray<AnyRequestMiddleware> = [],\n const TFunctionMiddlewares extends ReadonlyArray<AnyFunctionMiddleware> = [],\n>(\n getOptions: () =>\n | Promise<\n Omit<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >,\n '~types'\n >\n >\n | Omit<\n StartInstanceOptions<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >,\n '~types'\n >,\n): StartInstance<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n> => {\n return {\n getOptions: async () => {\n const options = await getOptions()\n if (options.serializationAdapters) {\n const deduped = new Set<AnySerializationAdapter>()\n dedupeSerializationAdapters(\n deduped,\n options.serializationAdapters as unknown as Array<AnySerializationAdapter>,\n )\n options.serializationAdapters = Array.from(deduped) as any\n }\n return options\n },\n createMiddleware: createMiddleware,\n } as StartInstance<\n TSerializationAdapters,\n TDefaultSsr,\n TRequestMiddlewares,\n TFunctionMiddlewares\n >\n}\n\nexport type AnyStartInstance = StartInstance<any, any, any, any>\nexport type AnyStartInstanceOptions = StartInstanceOptions<any, any, any, any>\n\ndeclare module '@tanstack/router-core' {\n interface SerializableExtensions {\n serverFn: { [TSS_SERVER_FUNCTION]: true }\n }\n}\n"],"mappings":";;AAuFA,SAAS,4BACP,SACA,uBACM;AACN,MAAK,IAAI,IAAI,GAAG,MAAM,sBAAsB,QAAQ,IAAI,KAAK,KAAK;EAChE,MAAM,UAAU,sBAAsB;AACtC,MAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE;AACzB,WAAQ,IAAI,QAAQ;AACpB,OAAI,QAAQ,QACV,6BAA4B,SAAS,QAAQ,QAAQ;;;;AAM7D,IAAa,eAOX,eA0BG;AACH,QAAO;EACL,YAAY,YAAY;GACtB,MAAM,UAAU,MAAM,YAAY;AAClC,OAAI,QAAQ,uBAAuB;IACjC,MAAM,0BAAU,IAAI,KAA8B;AAClD,gCACE,SACA,QAAQ,sBACT;AACD,YAAQ,wBAAwB,MAAM,KAAK,QAAQ;;AAErD,UAAO;;EAES;EACnB"} |
@@ -1,8 +0,7 @@ | ||
| const startInstance = void 0; | ||
| const getRouter = () => { | ||
| }; | ||
| export { | ||
| getRouter, | ||
| startInstance | ||
| }; | ||
| //# sourceMappingURL=fake-start-entry.js.map | ||
| //#region src/fake-start-entry.ts | ||
| var startInstance = void 0; | ||
| var getRouter = () => {}; | ||
| //#endregion | ||
| export { getRouter, startInstance }; | ||
| //# sourceMappingURL=fake-start-entry.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"fake-start-entry.js","sources":["../../src/fake-start-entry.ts"],"sourcesContent":["export const startInstance = undefined\nexport const getRouter = () => {}\n"],"names":[],"mappings":"AAAO,MAAM,gBAAgB;AACtB,MAAM,YAAY,MAAM;AAAC;"} | ||
| {"version":3,"file":"fake-start-entry.js","names":[],"sources":["../../src/fake-start-entry.ts"],"sourcesContent":["export const startInstance = undefined\nexport const getRouter = () => {}\n"],"mappings":";AAAA,IAAa,gBAAgB,KAAA;AAC7B,IAAa,kBAAkB"} |
@@ -0,14 +1,10 @@ | ||
| import { getStartOptions } from "./getStartOptions.js"; | ||
| import { defaultSerovalPlugins, makeSerovalPlugin } from "@tanstack/router-core"; | ||
| import { getStartOptions } from "./getStartOptions.js"; | ||
| //#region src/getDefaultSerovalPlugins.ts | ||
| function getDefaultSerovalPlugins() { | ||
| const start = getStartOptions(); | ||
| const adapters = start?.serializationAdapters; | ||
| return [ | ||
| ...adapters?.map(makeSerovalPlugin) ?? [], | ||
| ...defaultSerovalPlugins | ||
| ]; | ||
| return [...(getStartOptions()?.serializationAdapters)?.map(makeSerovalPlugin) ?? [], ...defaultSerovalPlugins]; | ||
| } | ||
| export { | ||
| getDefaultSerovalPlugins | ||
| }; | ||
| //# sourceMappingURL=getDefaultSerovalPlugins.js.map | ||
| //#endregion | ||
| export { getDefaultSerovalPlugins }; | ||
| //# sourceMappingURL=getDefaultSerovalPlugins.js.map |
@@ -1,1 +0,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;"} | ||
| {"version":3,"file":"getDefaultSerovalPlugins.js","names":[],"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"],"mappings":";;;AAOA,SAAgB,2BAA2B;AAKzC,QAAO,CACL,IALY,iBAAiB,EACP,wBAIR,IAAI,kBAAkB,IAAI,EAAE,EAC1C,GAAG,sBACJ"} |
@@ -0,15 +1,12 @@ | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| import { getStartContext } from "@tanstack/start-storage-context"; | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| const getGlobalStartContext = createIsomorphicFn().client(() => void 0).server(() => { | ||
| const context = getStartContext().contextAfterGlobalMiddlewares; | ||
| if (!context) { | ||
| throw new Error( | ||
| `Global context not set yet, you are calling getGlobalStartContext() before the global middlewares are applied.` | ||
| ); | ||
| } | ||
| return context; | ||
| //#region src/getGlobalStartContext.ts | ||
| var getGlobalStartContext = createIsomorphicFn().client(() => void 0).server(() => { | ||
| const context = getStartContext().contextAfterGlobalMiddlewares; | ||
| if (!context) throw new Error(`Global context not set yet, you are calling getGlobalStartContext() before the global middlewares are applied.`); | ||
| return context; | ||
| }); | ||
| export { | ||
| getGlobalStartContext | ||
| }; | ||
| //# sourceMappingURL=getGlobalStartContext.js.map | ||
| //#endregion | ||
| export { getGlobalStartContext }; | ||
| //# sourceMappingURL=getGlobalStartContext.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"getGlobalStartContext.js","sources":["../../src/getGlobalStartContext.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport type { AssignAllServerRequestContext } from './createMiddleware'\nimport type { Expand, Register } from '@tanstack/router-core'\n\nexport const getGlobalStartContext: () =>\n | Expand<AssignAllServerRequestContext<Register, []>>\n | undefined = createIsomorphicFn()\n .client(() => undefined)\n .server(() => {\n const context = getStartContext().contextAfterGlobalMiddlewares\n if (!context) {\n throw new Error(\n `Global context not set yet, you are calling getGlobalStartContext() before the global middlewares are applied.`,\n )\n }\n return context\n })\n"],"names":[],"mappings":";;AAKO,MAAM,wBAEG,qBACb,OAAO,MAAM,MAAS,EACtB,OAAO,MAAM;AACZ,QAAM,UAAU,kBAAkB;AAClC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACA,SAAO;AACT,CAAC;"} | ||
| {"version":3,"file":"getGlobalStartContext.js","names":[],"sources":["../../src/getGlobalStartContext.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport type { AssignAllServerRequestContext } from './createMiddleware'\nimport type { Expand, Register } from '@tanstack/router-core'\n\nexport const getGlobalStartContext: () =>\n | Expand<AssignAllServerRequestContext<Register, []>>\n | undefined = createIsomorphicFn()\n .client(() => undefined)\n .server(() => {\n const context = getStartContext().contextAfterGlobalMiddlewares\n if (!context) {\n throw new Error(\n `Global context not set yet, you are calling getGlobalStartContext() before the global middlewares are applied.`,\n )\n }\n return context\n })\n"],"mappings":";;;AAKA,IAAa,wBAEG,oBAAoB,CACjC,aAAa,KAAA,EAAU,CACvB,aAAa;CACZ,MAAM,UAAU,iBAAiB,CAAC;AAClC,KAAI,CAAC,QACH,OAAM,IAAI,MACR,iHACD;AAEH,QAAO;EACP"} |
@@ -0,7 +1,8 @@ | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| import { getStartContext } from "@tanstack/start-storage-context"; | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| const getRouterInstance = createIsomorphicFn().client(() => window.__TSR_ROUTER__).server(() => getStartContext().getRouter()); | ||
| export { | ||
| getRouterInstance | ||
| }; | ||
| //# sourceMappingURL=getRouterInstance.js.map | ||
| //#region src/getRouterInstance.ts | ||
| var getRouterInstance = createIsomorphicFn().client(() => window.__TSR_ROUTER__).server(() => getStartContext().getRouter()); | ||
| //#endregion | ||
| export { getRouterInstance }; | ||
| //# sourceMappingURL=getRouterInstance.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"getRouterInstance.js","sources":["../../src/getRouterInstance.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport type { Awaitable, RegisteredRouter } from '@tanstack/router-core'\n\nexport const getRouterInstance: () => Awaitable<RegisteredRouter> =\n createIsomorphicFn()\n .client(() => window.__TSR_ROUTER__!)\n .server(() => getStartContext().getRouter())\n"],"names":[],"mappings":";;AAIO,MAAM,oBACX,mBAAA,EACG,OAAO,MAAM,OAAO,cAAe,EACnC,OAAO,MAAM,gBAAA,EAAkB,WAAW;"} | ||
| {"version":3,"file":"getRouterInstance.js","names":[],"sources":["../../src/getRouterInstance.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport type { Awaitable, RegisteredRouter } from '@tanstack/router-core'\n\nexport const getRouterInstance: () => Awaitable<RegisteredRouter> =\n createIsomorphicFn()\n .client(() => window.__TSR_ROUTER__!)\n .server(() => getStartContext().getRouter())\n"],"mappings":";;;AAIA,IAAa,oBACX,oBAAoB,CACjB,aAAa,OAAO,eAAgB,CACpC,aAAa,iBAAiB,CAAC,WAAW,CAAC"} |
@@ -0,7 +1,8 @@ | ||
| import { createServerOnlyFn } from "@tanstack/start-fn-stubs"; | ||
| import { getStartContext } from "@tanstack/start-storage-context"; | ||
| import { createServerOnlyFn } from "@tanstack/start-fn-stubs"; | ||
| const getStartContextServerOnly = createServerOnlyFn(getStartContext); | ||
| export { | ||
| getStartContextServerOnly | ||
| }; | ||
| //# sourceMappingURL=getStartContextServerOnly.js.map | ||
| //#region src/getStartContextServerOnly.ts | ||
| var getStartContextServerOnly = createServerOnlyFn(getStartContext); | ||
| //#endregion | ||
| export { getStartContextServerOnly }; | ||
| //# sourceMappingURL=getStartContextServerOnly.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"getStartContextServerOnly.js","sources":["../../src/getStartContextServerOnly.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createServerOnlyFn } from '@tanstack/start-fn-stubs'\n\nexport const getStartContextServerOnly = createServerOnlyFn(getStartContext)\n"],"names":[],"mappings":";;AAGO,MAAM,4BAA4B,mBAAmB,eAAe;"} | ||
| {"version":3,"file":"getStartContextServerOnly.js","names":[],"sources":["../../src/getStartContextServerOnly.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createServerOnlyFn } from '@tanstack/start-fn-stubs'\n\nexport const getStartContextServerOnly = createServerOnlyFn(getStartContext)\n"],"mappings":";;;AAGA,IAAa,4BAA4B,mBAAmB,gBAAgB"} |
@@ -0,7 +1,8 @@ | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| import { getStartContext } from "@tanstack/start-storage-context"; | ||
| import { createIsomorphicFn } from "@tanstack/start-fn-stubs"; | ||
| const getStartOptions = createIsomorphicFn().client(() => window.__TSS_START_OPTIONS__).server(() => getStartContext().startOptions); | ||
| export { | ||
| getStartOptions | ||
| }; | ||
| //# sourceMappingURL=getStartOptions.js.map | ||
| //#region src/getStartOptions.ts | ||
| var getStartOptions = createIsomorphicFn().client(() => window.__TSS_START_OPTIONS__).server(() => getStartContext().startOptions); | ||
| //#endregion | ||
| export { getStartOptions }; | ||
| //# sourceMappingURL=getStartOptions.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"getStartOptions.js","sources":["../../src/getStartOptions.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\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;"} | ||
| {"version":3,"file":"getStartOptions.js","names":[],"sources":["../../src/getStartOptions.ts"],"sourcesContent":["import { getStartContext } from '@tanstack/start-storage-context'\nimport { createIsomorphicFn } from '@tanstack/start-fn-stubs'\nimport type { AnyStartInstanceOptions } from './createStart'\n\nexport const getStartOptions: () => AnyStartInstanceOptions | undefined =\n createIsomorphicFn()\n .client(() => window.__TSS_START_OPTIONS__)\n .server(() => getStartContext().startOptions)\n"],"mappings":";;;AAIA,IAAa,kBACX,oBAAoB,CACjB,aAAa,OAAO,sBAAsB,CAC1C,aAAa,iBAAiB,CAAC,aAAa"} |
+6
-37
@@ -1,7 +0,5 @@ | ||
| import { hydrate, json, mergeHeaders } from "@tanstack/router-core/ssr/client"; | ||
| import { RawStream } from "@tanstack/router-core"; | ||
| import { createClientOnlyFn, createIsomorphicFn, createServerOnlyFn } from "@tanstack/start-fn-stubs"; | ||
| import { FRAME_HEADER_SIZE, FrameType, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, validateFramedProtocolVersion } from "./constants.js"; | ||
| import { createNullProtoObject, safeObjectMerge } from "./safeObjectMerge.js"; | ||
| import { createServerFn, execValidator, executeMiddleware, flattenMiddlewares } from "./createServerFn.js"; | ||
| import { createMiddleware } from "./createMiddleware.js"; | ||
| import { FRAME_HEADER_SIZE, FrameType, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, validateFramedProtocolVersion } from "./constants.js"; | ||
| import { createStart } from "./createStart.js"; | ||
@@ -11,34 +9,5 @@ import { getRouterInstance } from "./getRouterInstance.js"; | ||
| import { getGlobalStartContext } from "./getGlobalStartContext.js"; | ||
| import { createNullProtoObject, safeObjectMerge } from "./safeObjectMerge.js"; | ||
| export { | ||
| FRAME_HEADER_SIZE, | ||
| FrameType, | ||
| RawStream, | ||
| TSS_CONTENT_TYPE_FRAMED, | ||
| TSS_CONTENT_TYPE_FRAMED_VERSIONED, | ||
| TSS_FORMDATA_CONTEXT, | ||
| TSS_FRAMED_PROTOCOL_VERSION, | ||
| TSS_SERVER_FUNCTION, | ||
| X_TSS_CONTEXT, | ||
| X_TSS_RAW_RESPONSE, | ||
| X_TSS_SERIALIZED, | ||
| createClientOnlyFn, | ||
| createIsomorphicFn, | ||
| createMiddleware, | ||
| createNullProtoObject, | ||
| createServerFn, | ||
| createServerOnlyFn, | ||
| createStart, | ||
| execValidator, | ||
| executeMiddleware, | ||
| flattenMiddlewares, | ||
| getDefaultSerovalPlugins, | ||
| getGlobalStartContext, | ||
| getRouterInstance, | ||
| hydrate, | ||
| json, | ||
| mergeHeaders, | ||
| safeObjectMerge, | ||
| validateFramedProtocolVersion | ||
| }; | ||
| //# sourceMappingURL=index.js.map | ||
| import { hydrate, json, mergeHeaders } from "@tanstack/router-core/ssr/client"; | ||
| import { RawStream } from "@tanstack/router-core"; | ||
| import { createClientOnlyFn, createIsomorphicFn, createServerOnlyFn } from "@tanstack/start-fn-stubs"; | ||
| export { FRAME_HEADER_SIZE, FrameType, RawStream, TSS_CONTENT_TYPE_FRAMED, TSS_CONTENT_TYPE_FRAMED_VERSIONED, TSS_FORMDATA_CONTEXT, TSS_FRAMED_PROTOCOL_VERSION, TSS_SERVER_FUNCTION, X_TSS_CONTEXT, X_TSS_RAW_RESPONSE, X_TSS_SERIALIZED, createClientOnlyFn, createIsomorphicFn, createMiddleware, createNullProtoObject, createServerFn, createServerOnlyFn, createStart, execValidator, executeMiddleware, flattenMiddlewares, getDefaultSerovalPlugins, getGlobalStartContext, getRouterInstance, hydrate, json, mergeHeaders, safeObjectMerge, validateFramedProtocolVersion }; |
@@ -0,30 +1,30 @@ | ||
| //#region src/safeObjectMerge.ts | ||
| function isSafeKey(key) { | ||
| return key !== "__proto__" && key !== "constructor" && key !== "prototype"; | ||
| return key !== "__proto__" && key !== "constructor" && key !== "prototype"; | ||
| } | ||
| /** | ||
| * Merge target and source into a new null-proto object, filtering dangerous keys. | ||
| */ | ||
| function safeObjectMerge(target, source) { | ||
| const result = /* @__PURE__ */ Object.create(null); | ||
| if (target) { | ||
| for (const key of Object.keys(target)) { | ||
| if (isSafeKey(key)) result[key] = target[key]; | ||
| } | ||
| } | ||
| if (source && typeof source === "object") { | ||
| for (const key of Object.keys(source)) { | ||
| if (isSafeKey(key)) result[key] = source[key]; | ||
| } | ||
| } | ||
| return result; | ||
| const result = Object.create(null); | ||
| if (target) { | ||
| for (const key of Object.keys(target)) if (isSafeKey(key)) result[key] = target[key]; | ||
| } | ||
| if (source && typeof source === "object") { | ||
| for (const key of Object.keys(source)) if (isSafeKey(key)) result[key] = source[key]; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Create a null-prototype object, optionally copying from source. | ||
| */ | ||
| function createNullProtoObject(source) { | ||
| if (!source) return /* @__PURE__ */ Object.create(null); | ||
| const obj = /* @__PURE__ */ Object.create(null); | ||
| for (const key of Object.keys(source)) { | ||
| if (isSafeKey(key)) obj[key] = source[key]; | ||
| } | ||
| return obj; | ||
| if (!source) return Object.create(null); | ||
| const obj = Object.create(null); | ||
| for (const key of Object.keys(source)) if (isSafeKey(key)) obj[key] = source[key]; | ||
| return obj; | ||
| } | ||
| export { | ||
| createNullProtoObject, | ||
| safeObjectMerge | ||
| }; | ||
| //# sourceMappingURL=safeObjectMerge.js.map | ||
| //#endregion | ||
| export { createNullProtoObject, safeObjectMerge }; | ||
| //# sourceMappingURL=safeObjectMerge.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"safeObjectMerge.js","sources":["../../src/safeObjectMerge.ts"],"sourcesContent":["function isSafeKey(key: string): boolean {\n return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'\n}\n\n/**\n * Merge target and source into a new null-proto object, filtering dangerous keys.\n */\nexport function safeObjectMerge<T extends Record<string, unknown>>(\n target: T | undefined,\n source: Record<string, unknown> | null | undefined,\n): T {\n const result = Object.create(null) as T\n if (target) {\n for (const key of Object.keys(target)) {\n if (isSafeKey(key)) result[key as keyof T] = target[key] as T[keyof T]\n }\n }\n if (source && typeof source === 'object') {\n for (const key of Object.keys(source)) {\n if (isSafeKey(key)) result[key as keyof T] = source[key] as T[keyof T]\n }\n }\n return result\n}\n\n/**\n * Create a null-prototype object, optionally copying from source.\n */\nexport function createNullProtoObject<T extends object>(\n source?: T,\n): { [K in keyof T]: T[K] } {\n if (!source) return Object.create(null)\n const obj = Object.create(null)\n for (const key of Object.keys(source)) {\n if (isSafeKey(key)) obj[key] = (source as Record<string, unknown>)[key]\n }\n return obj\n}\n"],"names":[],"mappings":"AAAA,SAAS,UAAU,KAAsB;AACvC,SAAO,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ;AACjE;AAKO,SAAS,gBACd,QACA,QACG;AACH,QAAM,SAAS,uBAAO,OAAO,IAAI;AACjC,MAAI,QAAQ;AACV,eAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAI,UAAU,GAAG,UAAU,GAAc,IAAI,OAAO,GAAG;AAAA,IACzD;AAAA,EACF;AACA,MAAI,UAAU,OAAO,WAAW,UAAU;AACxC,eAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAI,UAAU,GAAG,UAAU,GAAc,IAAI,OAAO,GAAG;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,sBACd,QAC0B;AAC1B,MAAI,CAAC,OAAQ,QAAO,uBAAO,OAAO,IAAI;AACtC,QAAM,MAAM,uBAAO,OAAO,IAAI;AAC9B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,QAAI,UAAU,GAAG,OAAO,GAAG,IAAK,OAAmC,GAAG;AAAA,EACxE;AACA,SAAO;AACT;"} | ||
| {"version":3,"file":"safeObjectMerge.js","names":[],"sources":["../../src/safeObjectMerge.ts"],"sourcesContent":["function isSafeKey(key: string): boolean {\n return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'\n}\n\n/**\n * Merge target and source into a new null-proto object, filtering dangerous keys.\n */\nexport function safeObjectMerge<T extends Record<string, unknown>>(\n target: T | undefined,\n source: Record<string, unknown> | null | undefined,\n): T {\n const result = Object.create(null) as T\n if (target) {\n for (const key of Object.keys(target)) {\n if (isSafeKey(key)) result[key as keyof T] = target[key] as T[keyof T]\n }\n }\n if (source && typeof source === 'object') {\n for (const key of Object.keys(source)) {\n if (isSafeKey(key)) result[key as keyof T] = source[key] as T[keyof T]\n }\n }\n return result\n}\n\n/**\n * Create a null-prototype object, optionally copying from source.\n */\nexport function createNullProtoObject<T extends object>(\n source?: T,\n): { [K in keyof T]: T[K] } {\n if (!source) return Object.create(null)\n const obj = Object.create(null)\n for (const key of Object.keys(source)) {\n if (isSafeKey(key)) obj[key] = (source as Record<string, unknown>)[key]\n }\n return obj\n}\n"],"mappings":";AAAA,SAAS,UAAU,KAAsB;AACvC,QAAO,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ;;;;;AAMjE,SAAgB,gBACd,QACA,QACG;CACH,MAAM,SAAS,OAAO,OAAO,KAAK;AAClC,KAAI;OACG,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,UAAU,IAAI,CAAE,QAAO,OAAkB,OAAO;;AAGxD,KAAI,UAAU,OAAO,WAAW;OACzB,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,UAAU,IAAI,CAAE,QAAO,OAAkB,OAAO;;AAGxD,QAAO;;;;;AAMT,SAAgB,sBACd,QAC0B;AAC1B,KAAI,CAAC,OAAQ,QAAO,OAAO,OAAO,KAAK;CACvC,MAAM,MAAM,OAAO,OAAO,KAAK;AAC/B,MAAK,MAAM,OAAO,OAAO,KAAK,OAAO,CACnC,KAAI,UAAU,IAAI,CAAE,KAAI,OAAQ,OAAmC;AAErE,QAAO"} |
+4
-4
| { | ||
| "name": "@tanstack/start-client-core", | ||
| "version": "1.166.9", | ||
| "version": "1.166.10", | ||
| "description": "Modern and scalable routing for React applications", | ||
@@ -69,5 +69,5 @@ "author": "Tanner Linsley", | ||
| "tiny-warning": "^1.0.3", | ||
| "@tanstack/router-core": "1.167.1", | ||
| "@tanstack/start-fn-stubs": "1.161.5", | ||
| "@tanstack/start-storage-context": "1.166.9" | ||
| "@tanstack/router-core": "1.167.2", | ||
| "@tanstack/start-fn-stubs": "1.161.6", | ||
| "@tanstack/start-storage-context": "1.166.10" | ||
| }, | ||
@@ -74,0 +74,0 @@ "devDependencies": { |
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"} |
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"} |
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"} |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
327539
-2.04%87
-3.33%6163
-3.63%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed