From d7c38e705ddc5a13d74096eed86aaab0870320a3 Mon Sep 17 00:00:00 2001 From: thinkeW <863093879@qq.com> Date: Thu, 27 Mar 2025 15:27:33 +0800 Subject: [PATCH 1/5] feat:encode sfn > functionId & extractedFilename --- packages/start/config/index.js | 23 +++++++++++++++++--- packages/start/src/runtime/server-handler.ts | 7 +++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/start/config/index.js b/packages/start/config/index.js index 64f5497ee..2421b6b17 100644 --- a/packages/start/config/index.js +++ b/packages/start/config/index.js @@ -37,6 +37,23 @@ function solidStartServerFsRouter(config) { ); } +/** + * @param {string} filepath + * @returns {string} + */ +function convertToRelativePath(filepath) { + const arr = filepath.split("/src/"); + return arr[1] ? `~/${arr[1]}` : filepath; +} + +/** encode string, here to base64 + * @param {string} str + * @returns {string} + */ +function encodeString(str) { + return btoa(encodeURIComponent(str)); +} + const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ // This is the ID that will be available to look up and import // our server function manifest and resolve its module @@ -47,7 +64,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-runtime.js", import.meta.url)) )}"`, replacer: opts => - `createServerReference(${() => {}}, '${opts.functionId}', '${opts.extractedFilename}')` + `createServerReference(${() => {}}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` }, ssr: { getRuntimeCode: () => @@ -55,7 +72,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${opts.functionId}', '${opts.extractedFilename}')` + `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` }, server: { getRuntimeCode: () => @@ -63,7 +80,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${opts.functionId}', '${opts.extractedFilename}')` + `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` } }); diff --git a/packages/start/src/runtime/server-handler.ts b/packages/start/src/runtime/server-handler.ts index 46e1603c5..5d2c2eca6 100644 --- a/packages/start/src/runtime/server-handler.ts +++ b/packages/start/src/runtime/server-handler.ts @@ -78,6 +78,11 @@ function serializeToStream(id: string, value: any) { }); } +/** decode string, here to base64 */ +function decodeString(str?: string) { + return str ? decodeURIComponent(atob(str)) : str; +} + async function handleServerFunction(h3Event: HTTPEvent) { const event = getFetchEvent(h3Event); const request = event.request; @@ -100,7 +105,7 @@ async function handleServerFunction(h3Event: HTTPEvent) { : new Response(null, { status: 404 }); } } - + functionId = decodeString(functionId); const serverFnInfo = serverFnManifest[functionId]; let fnModule: undefined | { [key: string]: any }; From 0d3ca23b84b7669bf52a6c851ca8c603fe48343e Mon Sep 17 00:00:00 2001 From: thinkeW <863093879@qq.com> Date: Fri, 28 Mar 2025 15:24:02 +0800 Subject: [PATCH 2/5] feat:hash encode sfn > functionId --- packages/start/config/index.js | 11 +++--- packages/start/src/runtime/server-handler.ts | 37 +++++++++++++++++--- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/packages/start/config/index.js b/packages/start/config/index.js index 2421b6b17..c721f848f 100644 --- a/packages/start/config/index.js +++ b/packages/start/config/index.js @@ -1,5 +1,6 @@ import { createTanStackServerFnPlugin } from "@tanstack/server-functions-plugin"; import defu from "defu"; +import { createHash } from "node:crypto"; import { existsSync } from "node:fs"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -46,12 +47,12 @@ function convertToRelativePath(filepath) { return arr[1] ? `~/${arr[1]}` : filepath; } -/** encode string, here to base64 +/** encode string, here to sha256 hash * @param {string} str * @returns {string} */ function encodeString(str) { - return btoa(encodeURIComponent(str)); + return createHash("sha256").update(str).digest("hex"); } const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ @@ -64,7 +65,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-runtime.js", import.meta.url)) )}"`, replacer: opts => - `createServerReference(${() => {}}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${() => {}}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` }, ssr: { getRuntimeCode: () => @@ -72,7 +73,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` }, server: { getRuntimeCode: () => @@ -80,7 +81,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeString(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` } }); diff --git a/packages/start/src/runtime/server-handler.ts b/packages/start/src/runtime/server-handler.ts index 5d2c2eca6..14ba7a1f6 100644 --- a/packages/start/src/runtime/server-handler.ts +++ b/packages/start/src/runtime/server-handler.ts @@ -1,4 +1,5 @@ /// +import { createHash } from "node:crypto"; import { crossSerializeStream, fromJSON, getCrossReferenceHeader } from "seroval"; // @ts-ignore import { @@ -78,11 +79,38 @@ function serializeToStream(id: string, value: any) { }); } -/** decode string, here to base64 */ -function decodeString(str?: string) { - return str ? decodeURIComponent(atob(str)) : str; +/** encode string, Need to be consistent with `packages/start/config/index.js` */ +function encodeString(str: string) { + return createHash("sha256").update(str).digest("hex"); } +function hashObjectKey(objectValue: Record) { + return Object.fromEntries( + Object.entries(objectValue).flatMap(([key, value]) => [ + [key, value], + [encodeString(key), value] + ]) + ); +} + +/** + * Creates a hashed version of server function manifest with different behavior based on environment + * + * In development: Uses a Proxy to dynamically access both original and hashed keys + * In production: Directly returns an object with both original and hashed keys + */ +const hashServerFnManifest = process.env.NODE_ENV === "development" + ? new Proxy(serverFnManifest, { // Development environment uses Proxy + get(target, key) { + // If key not found in original manifest and key is string, try hashed version + if (!target[key] && typeof key === 'string') { + return hashObjectKey(target)[key]; + } + return target[key]; + }, + }) + : hashObjectKey(serverFnManifest); + async function handleServerFunction(h3Event: HTTPEvent) { const event = getFetchEvent(h3Event); const request = event.request; @@ -105,8 +133,7 @@ async function handleServerFunction(h3Event: HTTPEvent) { : new Response(null, { status: 404 }); } } - functionId = decodeString(functionId); - const serverFnInfo = serverFnManifest[functionId]; + const serverFnInfo = hashServerFnManifest[functionId]; let fnModule: undefined | { [key: string]: any }; if (!serverFnInfo) { From 73b7c1bf01f93283c919b1e6c5df8c9e6477a91c Mon Sep 17 00:00:00 2001 From: thinkeW <863093879@qq.com> Date: Wed, 2 Apr 2025 10:09:22 +0800 Subject: [PATCH 3/5] feat:only encode sfn > extractedFilename --- packages/start/config/index.js | 18 +++------- packages/start/src/runtime/server-handler.ts | 35 +------------------- 2 files changed, 5 insertions(+), 48 deletions(-) diff --git a/packages/start/config/index.js b/packages/start/config/index.js index c721f848f..b8dbb8b00 100644 --- a/packages/start/config/index.js +++ b/packages/start/config/index.js @@ -1,6 +1,5 @@ import { createTanStackServerFnPlugin } from "@tanstack/server-functions-plugin"; import defu from "defu"; -import { createHash } from "node:crypto"; import { existsSync } from "node:fs"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -43,16 +42,7 @@ function solidStartServerFsRouter(config) { * @returns {string} */ function convertToRelativePath(filepath) { - const arr = filepath.split("/src/"); - return arr[1] ? `~/${arr[1]}` : filepath; -} - -/** encode string, here to sha256 hash - * @param {string} str - * @returns {string} - */ -function encodeString(str) { - return createHash("sha256").update(str).digest("hex"); + return filepath.replace(process.cwd(), "~"); } const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ @@ -65,7 +55,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-runtime.js", import.meta.url)) )}"`, replacer: opts => - `createServerReference(${() => {}}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${() => {}}, '${opts.functionId}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` }, ssr: { getRuntimeCode: () => @@ -73,7 +63,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${opts.fn}, '${opts.functionId}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` }, server: { getRuntimeCode: () => @@ -81,7 +71,7 @@ const SolidStartServerFnsPlugin = createTanStackServerFnPlugin({ fileURLToPath(new URL("../dist/runtime/server-fns-runtime.js", import.meta.url)) )}'`, replacer: opts => - `createServerReference(${opts.fn}, '${encodeString(opts.functionId)}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` + `createServerReference(${opts.fn}, '${opts.functionId}', '${encodeURIComponent(convertToRelativePath(opts.extractedFilename))}')` } }); diff --git a/packages/start/src/runtime/server-handler.ts b/packages/start/src/runtime/server-handler.ts index 14ba7a1f6..ffa620af4 100644 --- a/packages/start/src/runtime/server-handler.ts +++ b/packages/start/src/runtime/server-handler.ts @@ -1,5 +1,4 @@ /// -import { createHash } from "node:crypto"; import { crossSerializeStream, fromJSON, getCrossReferenceHeader } from "seroval"; // @ts-ignore import { @@ -79,38 +78,6 @@ function serializeToStream(id: string, value: any) { }); } -/** encode string, Need to be consistent with `packages/start/config/index.js` */ -function encodeString(str: string) { - return createHash("sha256").update(str).digest("hex"); -} - -function hashObjectKey(objectValue: Record) { - return Object.fromEntries( - Object.entries(objectValue).flatMap(([key, value]) => [ - [key, value], - [encodeString(key), value] - ]) - ); -} - -/** - * Creates a hashed version of server function manifest with different behavior based on environment - * - * In development: Uses a Proxy to dynamically access both original and hashed keys - * In production: Directly returns an object with both original and hashed keys - */ -const hashServerFnManifest = process.env.NODE_ENV === "development" - ? new Proxy(serverFnManifest, { // Development environment uses Proxy - get(target, key) { - // If key not found in original manifest and key is string, try hashed version - if (!target[key] && typeof key === 'string') { - return hashObjectKey(target)[key]; - } - return target[key]; - }, - }) - : hashObjectKey(serverFnManifest); - async function handleServerFunction(h3Event: HTTPEvent) { const event = getFetchEvent(h3Event); const request = event.request; @@ -133,7 +100,7 @@ async function handleServerFunction(h3Event: HTTPEvent) { : new Response(null, { status: 404 }); } } - const serverFnInfo = hashServerFnManifest[functionId]; + const serverFnInfo = serverFnManifest[functionId]; let fnModule: undefined | { [key: string]: any }; if (!serverFnInfo) { From 4042f70d77c887119aeab218e503989713a28500 Mon Sep 17 00:00:00 2001 From: thinkeW <863093879@qq.com> Date: Wed, 2 Apr 2025 10:11:05 +0800 Subject: [PATCH 4/5] fix:not change server-handler.ts --- packages/start/src/runtime/server-handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/start/src/runtime/server-handler.ts b/packages/start/src/runtime/server-handler.ts index ffa620af4..cbae38bdb 100644 --- a/packages/start/src/runtime/server-handler.ts +++ b/packages/start/src/runtime/server-handler.ts @@ -100,6 +100,7 @@ async function handleServerFunction(h3Event: HTTPEvent) { : new Response(null, { status: 404 }); } } + const serverFnInfo = serverFnManifest[functionId]; let fnModule: undefined | { [key: string]: any }; From b640817896d7821920bf09eb08c6fa0b0aa1a9d1 Mon Sep 17 00:00:00 2001 From: thinkeW <863093879@qq.com> Date: Wed, 2 Apr 2025 10:11:32 +0800 Subject: [PATCH 5/5] fix:not change server-handler.ts --- packages/start/src/runtime/server-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/start/src/runtime/server-handler.ts b/packages/start/src/runtime/server-handler.ts index cbae38bdb..46e1603c5 100644 --- a/packages/start/src/runtime/server-handler.ts +++ b/packages/start/src/runtime/server-handler.ts @@ -100,7 +100,7 @@ async function handleServerFunction(h3Event: HTTPEvent) { : new Response(null, { status: 404 }); } } - + const serverFnInfo = serverFnManifest[functionId]; let fnModule: undefined | { [key: string]: any };