From c85520427dabf779274d28059fe4151e3f19bb58 Mon Sep 17 00:00:00 2001 From: Dor Alagem Date: Wed, 29 Apr 2026 09:24:55 +0300 Subject: [PATCH 1/6] fix(start-plugin-core): sort server fn manifest entries for deterministic build output --- .../src/start-compiler/server-fn-resolver-module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts index 2635c38e07..5c7ccb2cd6 100644 --- a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts +++ b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts @@ -16,7 +16,7 @@ interface GenerateServerFnResolverModuleOptions { function getResolverManifestEntries( serverFnsById: Record, ): Array { - return Object.entries(serverFnsById).map(([id, fn]) => ({ + return Object.entries(serverFnsById).sort(([a], [b]) => a.localeCompare(b)).map(([id, fn]) => ({ id, functionName: fn.functionName, extractedFilename: fn.extractedFilename, From a3e5005ddd9dec79a76310d41317234255b5cb5e Mon Sep 17 00:00:00 2001 From: Dor Alagem Date: Wed, 29 Apr 2026 14:18:51 +0300 Subject: [PATCH 2/6] Use plain lexical sort instead of localeCompare for determinism --- .../src/start-compiler/server-fn-resolver-module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts index 5c7ccb2cd6..6a5cee4cc6 100644 --- a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts +++ b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts @@ -16,7 +16,7 @@ interface GenerateServerFnResolverModuleOptions { function getResolverManifestEntries( serverFnsById: Record, ): Array { - return Object.entries(serverFnsById).sort(([a], [b]) => a.localeCompare(b)).map(([id, fn]) => ({ + return Object.entries(serverFnsById).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([id, fn]) => ({ id, functionName: fn.functionName, extractedFilename: fn.extractedFilename, From 9d9144a881db2ed13a0430918833412097e8eee5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 20:18:58 +0000 Subject: [PATCH 3/6] ci: apply automated fixes --- .../start-compiler/server-fn-resolver-module.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts index 6a5cee4cc6..e0ab9bd32c 100644 --- a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts +++ b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts @@ -16,12 +16,14 @@ interface GenerateServerFnResolverModuleOptions { function getResolverManifestEntries( serverFnsById: Record, ): Array { - return Object.entries(serverFnsById).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([id, fn]) => ({ - id, - functionName: fn.functionName, - extractedFilename: fn.extractedFilename, - isClientReferenced: fn.isClientReferenced ?? true, - })) + return Object.entries(serverFnsById) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([id, fn]) => ({ + id, + functionName: fn.functionName, + extractedFilename: fn.extractedFilename, + isClientReferenced: fn.isClientReferenced ?? true, + })) } function getClientReferencedCheck( From b6f8f3bcaf85b075785586edca614e75d9349169 Mon Sep 17 00:00:00 2001 From: Manuel Schiller Date: Wed, 29 Apr 2026 22:51:01 +0200 Subject: [PATCH 4/6] Enhance comments in getResolverManifestEntries function Add comments to clarify sorting logic for resolver manifest entries. --- .../src/start-compiler/server-fn-resolver-module.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts index e0ab9bd32c..30666910ea 100644 --- a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts +++ b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts @@ -17,6 +17,9 @@ function getResolverManifestEntries( serverFnsById: Record, ): Array { return Object.entries(serverFnsById) + // Sort entries by ID so that the generated manifest has a stable, deterministic order. + // Non-deterministic ordering causes the compiled hash of the same source file to change + // between builds, breaking content-addressed caching and reproducible deployments. .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) .map(([id, fn]) => ({ id, From c2fcdcb61c6a12f5f24d3111c555441dc8ba1c49 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 20:53:04 +0000 Subject: [PATCH 5/6] ci: apply automated fixes --- .../server-fn-resolver-module.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts index 30666910ea..8f872a48c1 100644 --- a/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts +++ b/packages/start-plugin-core/src/start-compiler/server-fn-resolver-module.ts @@ -16,17 +16,19 @@ interface GenerateServerFnResolverModuleOptions { function getResolverManifestEntries( serverFnsById: Record, ): Array { - return Object.entries(serverFnsById) - // Sort entries by ID so that the generated manifest has a stable, deterministic order. - // Non-deterministic ordering causes the compiled hash of the same source file to change - // between builds, breaking content-addressed caching and reproducible deployments. - .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) - .map(([id, fn]) => ({ - id, - functionName: fn.functionName, - extractedFilename: fn.extractedFilename, - isClientReferenced: fn.isClientReferenced ?? true, - })) + return ( + Object.entries(serverFnsById) + // Sort entries by ID so that the generated manifest has a stable, deterministic order. + // Non-deterministic ordering causes the compiled hash of the same source file to change + // between builds, breaking content-addressed caching and reproducible deployments. + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([id, fn]) => ({ + id, + functionName: fn.functionName, + extractedFilename: fn.extractedFilename, + isClientReferenced: fn.isClientReferenced ?? true, + })) + ) } function getClientReferencedCheck( From 8a2943e286d32ecae21e2b7671e10a3c09d964f4 Mon Sep 17 00:00:00 2001 From: DORI2001 Date: Thu, 30 Apr 2026 09:33:22 +0300 Subject: [PATCH 6/6] chore: add changeset for server fn manifest sort fix --- .changeset/silver-lions-sort.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/silver-lions-sort.md diff --git a/.changeset/silver-lions-sort.md b/.changeset/silver-lions-sort.md new file mode 100644 index 0000000000..a810d49090 --- /dev/null +++ b/.changeset/silver-lions-sort.md @@ -0,0 +1,5 @@ +--- +'@tanstack/start-plugin-core': patch +--- + +Sort server function manifest entries by ID before emitting the resolver module. The `serverFnsById` map is populated in source-file scan order, which varies across machines and incremental builds, producing non-deterministic key ordering in the emitted `__tanstack-start-server-fn-resolver-*.mjs` artifact. Stable alphabetic sorting ensures reproducible builds, consistent content hashes, and clean `git diff` on committed artifacts.