@tanstack/start-client-core 1.170.11 → 1.170.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/client-rpc/frame-decoder.js +8 -0
- package/dist/esm/client-rpc/frame-decoder.js.map +1 -1
- package/dist/esm/createMiddleware.d.ts +7 -1
- package/dist/esm/createMiddleware.js +8 -3
- package/dist/esm/createMiddleware.js.map +1 -1
- package/dist/esm/createServerFn.d.ts +7 -1
- package/dist/esm/createServerFn.js +13 -8
- package/dist/esm/createServerFn.js.map +1 -1
- package/package.json +3 -3
- package/skills/start-core/auth-server-primitives/SKILL.md +5 -5
- package/skills/start-core/middleware/SKILL.md +5 -5
- package/skills/start-core/server-functions/SKILL.md +7 -7
- package/src/client-rpc/frame-decoder.ts +19 -0
- package/src/createMiddleware.ts +25 -7
- package/src/createServerFn.ts +40 -20
- package/src/tests/createServerFn.test-d.ts +39 -37
- package/src/tests/createServerMiddleware.test-d.ts +14 -10
|
@@ -119,6 +119,14 @@ function createFrameDecoder(input) {
|
|
|
119
119
|
*/
|
|
120
120
|
function extractFlattened(count) {
|
|
121
121
|
if (count === 0) return EMPTY_BUFFER;
|
|
122
|
+
const first = bufferList[0];
|
|
123
|
+
if (first && first.length >= count) {
|
|
124
|
+
const result = first.subarray(0, count);
|
|
125
|
+
if (first.length === count) bufferList.shift();
|
|
126
|
+
else bufferList[0] = first.subarray(count);
|
|
127
|
+
totalLength -= count;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
122
130
|
const result = new Uint8Array(count);
|
|
123
131
|
let offset = 0;
|
|
124
132
|
let remaining = count;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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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"}
|
|
1
|
+
{"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 // Fast path: the requested bytes are fully contained in the first buffered\n // chunk (the common case — most frames arrive within a single network\n // read). Return a subarray view instead of allocating a new buffer and\n // copying `count` bytes. The view shares the chunk's backing ArrayBuffer,\n // which is safe because buffered chunks are never mutated in place after\n // being read from the network.\n const first = bufferList[0]\n if (first && first.length >= count) {\n const result = first.subarray(0, count)\n if (first.length === count) {\n bufferList.shift()\n } else {\n bufferList[0] = first.subarray(count)\n }\n totalLength -= count\n return result\n }\n\n // Slow path: the requested bytes span multiple chunks — flatten by copying.\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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"}
|
|
@@ -33,6 +33,8 @@ export interface FunctionMiddlewareTypes<in out TRegister, in out TMiddlewares,
|
|
|
33
33
|
allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares, TServerSendContext, TServerContext>;
|
|
34
34
|
clientSendContext: TClientSendContext;
|
|
35
35
|
allClientSendContext: AssignAllClientSendContext<TMiddlewares, TClientSendContext>;
|
|
36
|
+
validator: TInputValidator;
|
|
37
|
+
/** @deprecated Use `validator` instead. */
|
|
36
38
|
inputValidator: TInputValidator;
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
@@ -72,6 +74,8 @@ type __AssignAllServerFnContext<TMiddlewares, TSendContext = undefined, TServerC
|
|
|
72
74
|
export type AssignAllClientSendContext<TMiddlewares, TSendContext = undefined> = unknown extends TSendContext ? TSendContext : Assign<AssignAllMiddleware<TMiddlewares, 'allClientSendContext'>, TSendContext>;
|
|
73
75
|
export interface FunctionMiddlewareOptions<in out TRegister, in out TMiddlewares, in out TInputValidator, in out TServerContext, in out TClientContext> {
|
|
74
76
|
middleware?: TMiddlewares;
|
|
77
|
+
validator?: ConstrainValidator<TRegister, 'GET', TInputValidator>;
|
|
78
|
+
/** @deprecated Use `validator` instead. */
|
|
75
79
|
inputValidator?: ConstrainValidator<TRegister, 'GET', TInputValidator>;
|
|
76
80
|
client?: FunctionMiddlewareClientFn<TRegister, TMiddlewares, TInputValidator, TServerContext, TClientContext>;
|
|
77
81
|
server?: FunctionMiddlewareServerFn<TRegister, TMiddlewares, TInputValidator, TServerContext, unknown, unknown>;
|
|
@@ -136,7 +140,9 @@ export type FunctionClientResultWithContext<in out TMiddlewares, in out TSendCon
|
|
|
136
140
|
export interface FunctionMiddlewareAfterClient<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> extends FunctionMiddlewareWithTypes<TRegister, TMiddlewares, TInputValidator, undefined, TServerSendContext, TClientContext, undefined>, FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, TServerSendContext, TClientContext> {
|
|
137
141
|
}
|
|
138
142
|
export interface FunctionMiddlewareValidator<TRegister, TMiddlewares> {
|
|
139
|
-
|
|
143
|
+
validator: <TNewValidator>(validator: ConstrainValidator<TRegister, 'GET', TNewValidator>) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>;
|
|
144
|
+
/** @deprecated Use `validator` instead. */
|
|
145
|
+
inputValidator: <TNewValidator>(validator: ConstrainValidator<TRegister, 'GET', TNewValidator>) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>;
|
|
140
146
|
}
|
|
141
147
|
export interface FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TInputValidator> extends FunctionMiddlewareWithTypes<TRegister, TMiddlewares, TInputValidator, undefined, undefined, undefined, undefined>, FunctionMiddlewareServer<TRegister, TMiddlewares, TInputValidator, undefined, undefined>, FunctionMiddlewareClient<TRegister, TMiddlewares, TInputValidator> {
|
|
142
148
|
}
|
|
@@ -4,14 +4,19 @@ var createMiddleware = (options, __opts) => {
|
|
|
4
4
|
type: "request",
|
|
5
5
|
...__opts || options
|
|
6
6
|
};
|
|
7
|
+
const setValidator = (validator) => {
|
|
8
|
+
return createMiddleware({}, Object.assign(resolvedOptions, {
|
|
9
|
+
validator,
|
|
10
|
+
inputValidator: validator
|
|
11
|
+
}));
|
|
12
|
+
};
|
|
7
13
|
return {
|
|
8
14
|
options: resolvedOptions,
|
|
9
15
|
middleware: (middleware) => {
|
|
10
16
|
return createMiddleware({}, Object.assign(resolvedOptions, { middleware }));
|
|
11
17
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
18
|
+
validator: setValidator,
|
|
19
|
+
inputValidator: setValidator,
|
|
15
20
|
client: (client) => {
|
|
16
21
|
return createMiddleware({}, Object.assign(resolvedOptions, { client }));
|
|
17
22
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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 {},\n Object.assign(resolvedOptions, { middleware }),\n )\n },\n inputValidator: (inputValidator: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, { inputValidator }),\n )\n },\n client: (client: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { client }))\n },\n server: (server: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { server }))\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 * Type of Start handler currently processing this request.\n */\n handlerType: 'serverFn' | 'router'\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;CAChB;CAEA,OAAO;EACL,SAAS;EACT,aAAa,eAAoB;GAC/B,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,WAAW,CAAC,CAC/C;EACF;EACA,iBAAiB,mBAAwB;GACvC,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,eAAe,CAAC,CACnD;EACF;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;CACF;AACF"}
|
|
1
|
+
{"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 const setValidator = (validator: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, {\n validator,\n // TODO remove upon stable\n inputValidator: validator,\n }),\n )\n }\n\n return {\n options: resolvedOptions,\n middleware: (middleware: any) => {\n return createMiddleware(\n {},\n Object.assign(resolvedOptions, { middleware }),\n )\n },\n validator: setValidator,\n // TODO remove upon stable\n inputValidator: setValidator,\n client: (client: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { client }))\n },\n server: (server: any) => {\n return createMiddleware({}, Object.assign(resolvedOptions, { server }))\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 validator: TInputValidator\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\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 validator?: ConstrainValidator<TRegister, 'GET', TInputValidator>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\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 validator: <TNewValidator>(\n validator: ConstrainValidator<TRegister, 'GET', TNewValidator>,\n ) => FunctionMiddlewareAfterValidator<TRegister, TMiddlewares, TNewValidator>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: <TNewValidator>(\n validator: 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 * Type of Start handler currently processing this request.\n */\n handlerType: 'serverFn' | 'router'\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;CAChB;CACA,MAAM,gBAAgB,cAAmB;EACvC,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB;GAC7B;GAEA,gBAAgB;EAClB,CAAC,CACH;CACF;CAEA,OAAO;EACL,SAAS;EACT,aAAa,eAAoB;GAC/B,OAAO,iBACL,CAAC,GACD,OAAO,OAAO,iBAAiB,EAAE,WAAW,CAAC,CAC/C;EACF;EACA,WAAW;EAEX,gBAAgB;EAChB,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;EACA,SAAS,WAAgB;GACvB,OAAO,iBAAiB,CAAC,GAAG,OAAO,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAC;EACxE;CACF;AACF"}
|
|
@@ -77,6 +77,8 @@ export type ServerFnBaseOptions<TRegister, TMethod extends Method = 'GET', TResp
|
|
|
77
77
|
method: TMethod;
|
|
78
78
|
strict?: TStrict;
|
|
79
79
|
middleware?: Constrain<TMiddlewares, ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>>;
|
|
80
|
+
validator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>;
|
|
81
|
+
/** @deprecated Use `validator` instead. */
|
|
80
82
|
inputValidator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>;
|
|
81
83
|
extractedFn?: CompiledFetcherFn<TRegister, TResponse>;
|
|
82
84
|
serverFn?: ServerFn<TRegister, TMethod, TMiddlewares, TInputValidator, TResponse, TStrict>;
|
|
@@ -91,8 +93,10 @@ export interface ServerFnMiddleware<TRegister, TMethod extends Method, TMiddlewa
|
|
|
91
93
|
export interface ServerFnAfterMiddleware<TRegister, TMethod extends Method, TMiddlewares, TInputValidator, TStrict extends ServerFnStrict> extends ServerFnWithTypes<TRegister, TMethod, TMiddlewares, TInputValidator, undefined, TStrict>, ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>, ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>, ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict> {
|
|
92
94
|
<TNewMethod extends Method = TMethod, TNewStrict extends ServerFnStrict = TStrict>(options?: ServerFnOptions<TNewMethod, TNewStrict>): ServerFnAfterMiddleware<TRegister, TNewMethod, TMiddlewares, TInputValidator, TNewStrict>;
|
|
93
95
|
}
|
|
94
|
-
export type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> = <TInputValidator>(
|
|
96
|
+
export type ValidatorFn<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> = <TInputValidator>(validator: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>) => ServerFnAfterValidator<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict>;
|
|
95
97
|
export interface ServerFnValidator<TRegister, TMethod extends Method, TMiddlewares, TStrict extends ServerFnStrict> {
|
|
98
|
+
validator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>;
|
|
99
|
+
/** @deprecated Use `validator` instead. */
|
|
96
100
|
inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>;
|
|
97
101
|
}
|
|
98
102
|
export interface ServerFnAfterValidator<TRegister, TMethod extends Method, TMiddlewares, TInputValidator, TStrict extends ServerFnStrict> extends ServerFnWithTypes<TRegister, TMethod, TMiddlewares, TInputValidator, undefined, TStrict>, ServerFnMiddleware<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict>, ServerFnHandler<TRegister, TMethod, TMiddlewares, TInputValidator, TStrict> {
|
|
@@ -116,6 +120,8 @@ export interface ServerFnTypes<in out TRegister, in out TMethod extends Method,
|
|
|
116
120
|
method: TMethod;
|
|
117
121
|
strict: TStrict;
|
|
118
122
|
middlewares: TMiddlewares;
|
|
123
|
+
validator: TInputValidator;
|
|
124
|
+
/** @deprecated Use `validator` instead. */
|
|
119
125
|
inputValidator: TInputValidator;
|
|
120
126
|
response: TResponse;
|
|
121
127
|
allServerContext: AssignAllServerFnContext<TRegister, TMiddlewares>;
|
|
@@ -8,6 +8,13 @@ import { isRedirect, parseRedirect } from "@tanstack/router-core";
|
|
|
8
8
|
var createServerFn = (options, __opts) => {
|
|
9
9
|
const resolvedOptions = __opts || options || {};
|
|
10
10
|
if (typeof resolvedOptions.method === "undefined") resolvedOptions.method = "GET";
|
|
11
|
+
const setValidator = (validator) => {
|
|
12
|
+
return createServerFn(void 0, {
|
|
13
|
+
...resolvedOptions,
|
|
14
|
+
validator,
|
|
15
|
+
inputValidator: validator
|
|
16
|
+
});
|
|
17
|
+
};
|
|
11
18
|
const res = {
|
|
12
19
|
options: resolvedOptions,
|
|
13
20
|
middleware: (middleware) => {
|
|
@@ -24,12 +31,8 @@ var createServerFn = (options, __opts) => {
|
|
|
24
31
|
res[TSS_SERVER_FUNCTION_FACTORY] = true;
|
|
25
32
|
return res;
|
|
26
33
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...resolvedOptions,
|
|
30
|
-
inputValidator
|
|
31
|
-
});
|
|
32
|
-
},
|
|
34
|
+
validator: setValidator,
|
|
35
|
+
inputValidator: setValidator,
|
|
33
36
|
handler: (...args) => {
|
|
34
37
|
const [extractedFn, serverFn] = args;
|
|
35
38
|
const newOptions = {
|
|
@@ -92,7 +95,9 @@ async function executeMiddleware(middlewares, env, opts) {
|
|
|
92
95
|
const nextMiddleware = flattenedMiddlewares.shift();
|
|
93
96
|
if (!nextMiddleware) return ctx;
|
|
94
97
|
try {
|
|
95
|
-
|
|
98
|
+
let validator = "validator" in nextMiddleware.options ? nextMiddleware.options.validator : void 0;
|
|
99
|
+
if (!validator && "inputValidator" in nextMiddleware.options) validator = nextMiddleware.options.inputValidator;
|
|
100
|
+
if (validator && env === "server") ctx.data = await execValidator(validator, ctx.data);
|
|
96
101
|
let middlewareFn = void 0;
|
|
97
102
|
if (env === "client") {
|
|
98
103
|
if ("client" in nextMiddleware.options) middlewareFn = nextMiddleware.options.client;
|
|
@@ -175,7 +180,7 @@ function serverFnBaseToMiddleware(options) {
|
|
|
175
180
|
return {
|
|
176
181
|
"~types": void 0,
|
|
177
182
|
options: {
|
|
178
|
-
inputValidator: options.inputValidator,
|
|
183
|
+
inputValidator: options.validator ?? options.inputValidator,
|
|
179
184
|
client: async ({ next, sendContext, fetch, ...ctx }) => {
|
|
180
185
|
const payload = {
|
|
181
186
|
...ctx,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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 IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\nexport type ServerFnStrict = boolean | { input?: boolean; output?: boolean }\n\nexport interface ServerFnOptions<\n TMethod extends Method = Method,\n TStrict extends ServerFnStrict = true,\n> {\n method?: TMethod\n strict?: TStrict\n}\n\nexport type ServerFnStrictInput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { input: infer TInput extends boolean }\n ? TInput\n : true\n\nexport type ServerFnStrictOutput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { output: infer TOutput extends boolean }\n ? TOutput\n : true\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TStrict extends ServerFnStrict = true,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: ServerFnOptions<TMethod, TStrict>,\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n) => ServerFnBuilder<TRegister, TMethod, TStrict>\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 any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const res: ServerFnBuilder<Register, Method, ServerFnStrict> = {\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)\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,\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 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 // Merge client context first so trusted server middleware context wins.\n context: safeObjectMerge(\n opts.context,\n serverContextAfterGlobalMiddlewares,\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, ServerFnStrict>\n const fun = (options?: ServerFnOptions<Method, ServerFnStrict>) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions)\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\n// Ideally, this type should just be `export type CustomFetch = typeof globalThis.fetch`, but that conflicts with the type overrides the `bun-types` package - a dependency of unplugin.\n// Relevant bun issues:\n// - https://github.com/oven-sh/bun/issues/23500\n// - https://github.com/oven-sh/bun/issues/23741\nexport type CustomFetch = typeof fetch extends (...args: infer A) => infer R\n ? (...args: A) => R\n : never\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<\n TRegister,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictOutput<TStrict> extends false\n ? TResponse\n : TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U, TStrict>>\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 TStrict extends ServerFnStrict = true,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse, TStrict>\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 TStrict extends ServerFnStrict = true,\n> = {\n method: TMethod\n strict?: TStrict\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n inputValidator?: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictInput<TStrict> extends false\n ? ResolveValidatorInput<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 TStrict extends ServerFnStrict = true,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator, TStrict>\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 TStrict extends ServerFnStrict,\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 TStrict\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator,\n TNewStrict\n >\n}\n\nexport type ValidatorFn<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> = <TInputValidator>(\n inputValidator: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> {\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse,\n TStrict\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<\n TRegister,\n TMethod extends Method = 'GET',\n TStrict extends ServerFnStrict = true,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, undefined, TStrict>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined, TStrict> {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnBuilder<TRegister, TNewMethod, TNewStrict>\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\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 in out TStrict extends ServerFnStrict,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, 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 in out TStrict extends ServerFnStrict,\n> {\n method: TMethod\n strict: TStrict\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 }\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)\n\n return next({\n ...ctx,\n result,\n } as any)\n },\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"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 IntersectAllValidatorInputs,\n IntersectAllValidatorOutputs,\n} from './createMiddleware'\n\nexport type ServerFnStrict = boolean | { input?: boolean; output?: boolean }\n\nexport interface ServerFnOptions<\n TMethod extends Method = Method,\n TStrict extends ServerFnStrict = true,\n> {\n method?: TMethod\n strict?: TStrict\n}\n\nexport type ServerFnStrictInput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { input: infer TInput extends boolean }\n ? TInput\n : true\n\nexport type ServerFnStrictOutput<TStrict extends ServerFnStrict> =\n TStrict extends false\n ? false\n : TStrict extends { output: infer TOutput extends boolean }\n ? TOutput\n : true\n\nexport type CreateServerFn<TRegister> = <\n TMethod extends Method,\n TStrict extends ServerFnStrict = true,\n TResponse = unknown,\n TMiddlewares = undefined,\n TInputValidator = undefined,\n>(\n options?: ServerFnOptions<TMethod, TStrict>,\n __opts?: ServerFnBaseOptions<\n TRegister,\n TMethod,\n TResponse,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n) => ServerFnBuilder<TRegister, TMethod, TStrict>\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 any\n >\n\n if (typeof resolvedOptions.method === 'undefined') {\n resolvedOptions.method = 'GET' as Method\n }\n\n const setValidator = (validator: any) => {\n // TODO remove upon stable\n const newOptions = {\n ...resolvedOptions,\n validator,\n inputValidator: validator,\n }\n return createServerFn(undefined, newOptions) as any\n }\n\n const res: ServerFnBuilder<Register, Method, ServerFnStrict> = {\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)\n res[TSS_SERVER_FUNCTION_FACTORY] = true\n return res\n },\n validator: setValidator,\n // TODO remove upon stable\n inputValidator: setValidator,\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,\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 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 // Merge client context first so trusted server middleware context wins.\n context: safeObjectMerge(\n opts.context,\n serverContextAfterGlobalMiddlewares,\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, ServerFnStrict>\n const fun = (options?: ServerFnOptions<Method, ServerFnStrict>) => {\n const newOptions = {\n ...resolvedOptions,\n ...options,\n }\n return createServerFn(undefined, newOptions)\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 let validator =\n 'validator' in nextMiddleware.options\n ? nextMiddleware.options.validator\n : undefined\n\n // TODO remove upon stable\n if (!validator && 'inputValidator' in nextMiddleware.options) {\n validator = nextMiddleware.options.inputValidator\n }\n\n if (validator && env === 'server') {\n // Execute the middleware's input function\n ctx.data = await execValidator(validator as AnyValidator, ctx.data)\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\n// Ideally, this type should just be `export type CustomFetch = typeof globalThis.fetch`, but that conflicts with the type overrides the `bun-types` package - a dependency of unplugin.\n// Relevant bun issues:\n// - https://github.com/oven-sh/bun/issues/23500\n// - https://github.com/oven-sh/bun/issues/23741\nexport type CustomFetch = typeof fetch extends (...args: infer A) => infer R\n ? (...args: A) => R\n : never\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<\n TRegister,\n TResponse,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictOutput<TStrict> extends false\n ? TResponse\n : TResponse extends PromiseLike<infer U>\n ? Promise<ServerFnReturnType<TRegister, U, TStrict>>\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 TStrict extends ServerFnStrict = true,\n> = (\n ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,\n) => ServerFnReturnType<TRegister, TResponse, TStrict>\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 TStrict extends ServerFnStrict = true,\n> = {\n method: TMethod\n strict?: TStrict\n middleware?: Constrain<\n TMiddlewares,\n ReadonlyArray<AnyFunctionMiddleware | AnyRequestMiddleware>\n >\n validator?: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator?: ConstrainValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n extractedFn?: CompiledFetcherFn<TRegister, TResponse>\n serverFn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n}\n\nexport type ValidateValidatorInput<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n ServerFnStrictInput<TStrict> extends false\n ? ResolveValidatorInput<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 TStrict extends ServerFnStrict = true,\n> =\n ValidateValidatorInput<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n > extends infer TInput\n ? Validator<TInput, any>\n : never\n\nexport type ConstrainValidator<\n TRegister,\n TMethod extends Method,\n TInputValidator,\n TStrict extends ServerFnStrict = true,\n> =\n | (unknown extends TInputValidator\n ? TInputValidator\n : ResolveValidatorInput<TInputValidator> extends ValidateValidator<\n TRegister,\n TMethod,\n TInputValidator,\n TStrict\n >\n ? TInputValidator\n : never)\n | ValidateValidator<TRegister, TMethod, TInputValidator, TStrict>\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 TStrict extends ServerFnStrict,\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 TStrict\n >\n}\n\nexport interface ServerFnAfterMiddleware<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, TMiddlewares, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, TMiddlewares, TStrict>,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnAfterMiddleware<\n TRegister,\n TNewMethod,\n TMiddlewares,\n TInputValidator,\n TNewStrict\n >\n}\n\nexport type ValidatorFn<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> = <TInputValidator>(\n validator: ConstrainValidator<TRegister, TMethod, TInputValidator, TStrict>,\n) => ServerFnAfterValidator<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n>\n\nexport interface ServerFnValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TStrict extends ServerFnStrict,\n> {\n validator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\n inputValidator: ValidatorFn<TRegister, TMethod, TMiddlewares, TStrict>\n}\n\nexport interface ServerFnAfterValidator<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\nexport interface ServerFnAfterTyper<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n undefined,\n TStrict\n >,\n ServerFnHandler<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TStrict\n > {}\n\n// Handler\nexport interface ServerFnHandler<\n TRegister,\n TMethod extends Method,\n TMiddlewares,\n TInputValidator,\n TStrict extends ServerFnStrict,\n> {\n handler: <TNewResponse>(\n fn?: ServerFn<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TNewResponse,\n TStrict\n >,\n ) => Fetcher<TMiddlewares, TInputValidator, TNewResponse>\n}\n\nexport interface ServerFnBuilder<\n TRegister,\n TMethod extends Method = 'GET',\n TStrict extends ServerFnStrict = true,\n>\n extends\n ServerFnWithTypes<\n TRegister,\n TMethod,\n undefined,\n undefined,\n undefined,\n TStrict\n >,\n ServerFnMiddleware<TRegister, TMethod, undefined, undefined, TStrict>,\n ServerFnValidator<TRegister, TMethod, undefined, TStrict>,\n ServerFnHandler<TRegister, TMethod, undefined, undefined, TStrict> {\n <\n TNewMethod extends Method = TMethod,\n TNewStrict extends ServerFnStrict = TStrict,\n >(\n options?: ServerFnOptions<TNewMethod, TNewStrict>,\n ): ServerFnBuilder<TRegister, TNewMethod, TNewStrict>\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\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 in out TStrict extends ServerFnStrict,\n> {\n '~types': ServerFnTypes<\n TRegister,\n TMethod,\n TMiddlewares,\n TInputValidator,\n TResponse,\n TStrict\n >\n options: ServerFnBaseOptions<\n TRegister,\n TMethod,\n unknown,\n undefined,\n undefined,\n TStrict\n >\n [TSS_SERVER_FUNCTION_FACTORY]: true\n}\n\nexport type AnyServerFn = ServerFnWithTypes<any, 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 in out TStrict extends ServerFnStrict,\n> {\n method: TMethod\n strict: TStrict\n middlewares: TMiddlewares\n validator: TInputValidator\n // TODO remove upon stable\n /** @deprecated Use `validator` instead. */\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 // TODO remove upon stable\n const validator = options.validator ?? options.inputValidator\n\n return {\n '~types': undefined!,\n options: {\n // TODO remove upon stable\n inputValidator: validator,\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 }\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)\n\n return next({\n ...ctx,\n result,\n } as any)\n },\n },\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-client-core",
|
|
3
|
-
"version": "1.170.
|
|
3
|
+
"version": "1.170.13",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"seroval": "^1.5.4",
|
|
94
|
-
"@tanstack/router-core": "1.171.
|
|
94
|
+
"@tanstack/router-core": "1.171.14",
|
|
95
95
|
"@tanstack/start-fn-stubs": "1.162.0",
|
|
96
|
-
"@tanstack/start-storage-context": "1.167.
|
|
96
|
+
"@tanstack/start-storage-context": "1.167.16"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"vite": "*",
|
|
@@ -31,7 +31,7 @@ This skill covers the **server half** of authentication: session storage, cookie
|
|
|
31
31
|
## Production Checklist
|
|
32
32
|
|
|
33
33
|
- Enforce auth in every server function, server route, or API endpoint that reads or writes private user, tenant, or account data. Use route `beforeLoad` for page UX, not as the data boundary.
|
|
34
|
-
- Use `.
|
|
34
|
+
- Use `.validator()` on every server function that accepts input.
|
|
35
35
|
- Store sessions in `HttpOnly`, `Secure`, `SameSite` cookies. Do not store session tokens in `localStorage` or `sessionStorage`.
|
|
36
36
|
- Hash passwords with bcrypt, scrypt, or Argon2. For missing users, verify against a dummy hash and return the same login/reset message.
|
|
37
37
|
- Rate limit login, registration, and password-reset endpoints.
|
|
@@ -139,7 +139,7 @@ import { z } from 'zod'
|
|
|
139
139
|
import { setSessionCookie } from './session'
|
|
140
140
|
|
|
141
141
|
export const login = createServerFn({ method: 'POST' })
|
|
142
|
-
.
|
|
142
|
+
.validator(z.object({ email: z.string().email(), password: z.string() }))
|
|
143
143
|
.handler(async ({ data }) => {
|
|
144
144
|
const user = await db.users.findByEmail(data.email)
|
|
145
145
|
// Always run verifyPasswordHash — even when the user doesn't exist —
|
|
@@ -237,7 +237,7 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
237
237
|
import { z } from 'zod'
|
|
238
238
|
|
|
239
239
|
export const requestPasswordReset = createServerFn({ method: 'POST' })
|
|
240
|
-
.
|
|
240
|
+
.validator(z.object({ email: z.string().email() }))
|
|
241
241
|
.handler(async ({ data }) => {
|
|
242
242
|
const user = await db.users.findByEmail(data.email)
|
|
243
243
|
if (user) {
|
|
@@ -369,7 +369,7 @@ A parsed UUID is _some_ workspace, not an _authorized_ workspace.
|
|
|
369
369
|
// WRONG — UUID is well-formed but the user may not be a member
|
|
370
370
|
const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
371
371
|
.middleware([authMiddleware])
|
|
372
|
-
.
|
|
372
|
+
.validator(z.object({ workspaceId: z.string().uuid() }))
|
|
373
373
|
.handler(async ({ context, data }) => {
|
|
374
374
|
return db.workspaces.findById(data.workspaceId) // missing membership check!
|
|
375
375
|
})
|
|
@@ -377,7 +377,7 @@ const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
|
377
377
|
// CORRECT — verify the session principal has access to that workspace
|
|
378
378
|
const getWorkspaceData = createServerFn({ method: 'GET' })
|
|
379
379
|
.middleware([authMiddleware])
|
|
380
|
-
.
|
|
380
|
+
.validator(z.object({ workspaceId: z.string().uuid() }))
|
|
381
381
|
.handler(async ({ context, data }) => {
|
|
382
382
|
const member = await db.memberships.find({
|
|
383
383
|
userId: context.session.userId,
|
|
@@ -20,7 +20,7 @@ sources:
|
|
|
20
20
|
|
|
21
21
|
Middleware customizes the behavior of server functions and server routes. It is composable — middleware can depend on other middleware to form a chain.
|
|
22
22
|
|
|
23
|
-
> **CRITICAL**: TypeScript enforces method order: `middleware()` → `
|
|
23
|
+
> **CRITICAL**: TypeScript enforces method order: `middleware()` → `validator()` → `client()` → `server()`. Wrong order causes type errors.
|
|
24
24
|
> **CRITICAL**: Validating the _shape_ of `sendContext` (e.g. `z.string().uuid().parse(...)`) is NOT authorization. A parsed identifier is a well-formed identifier, not an authorized one. Always re-check access against the session principal before using a client-sent ID as a query key, filter, or path parameter.
|
|
25
25
|
|
|
26
26
|
## Two Types of Middleware
|
|
@@ -29,7 +29,7 @@ Middleware customizes the behavior of server functions and server routes. It is
|
|
|
29
29
|
| ----------------- | -------------------------------------------- | ---------------------------------------- |
|
|
30
30
|
| Scope | All server requests (SSR, routes, functions) | Server functions only |
|
|
31
31
|
| Methods | `.server()` | `.client()`, `.server()` |
|
|
32
|
-
| Input validation | No | Yes (`.
|
|
32
|
+
| Input validation | No | Yes (`.validator()`) |
|
|
33
33
|
| Client-side logic | No | Yes |
|
|
34
34
|
| Created with | `createMiddleware()` | `createMiddleware({ type: 'function' })` |
|
|
35
35
|
|
|
@@ -160,7 +160,7 @@ import { z } from 'zod'
|
|
|
160
160
|
import { zodValidator } from '@tanstack/zod-adapter'
|
|
161
161
|
|
|
162
162
|
const workspaceMiddleware = createMiddleware({ type: 'function' })
|
|
163
|
-
.
|
|
163
|
+
.validator(zodValidator(z.object({ workspaceId: z.string() })))
|
|
164
164
|
.server(async ({ next, data }) => {
|
|
165
165
|
console.log('Workspace:', data.workspaceId)
|
|
166
166
|
return next()
|
|
@@ -382,10 +382,10 @@ createMiddleware({ type: 'function' })
|
|
|
382
382
|
.server(() => { ... })
|
|
383
383
|
.client(() => { ... })
|
|
384
384
|
|
|
385
|
-
// CORRECT — middleware →
|
|
385
|
+
// CORRECT — middleware → validator → client → server
|
|
386
386
|
createMiddleware({ type: 'function' })
|
|
387
387
|
.middleware([dep])
|
|
388
|
-
.
|
|
388
|
+
.validator(schema)
|
|
389
389
|
.client(({ next }) => next())
|
|
390
390
|
.server(({ next }) => next())
|
|
391
391
|
```
|