From 87fdd9c00060bc63355c6baea7e07bfb08a6f15f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Thu, 12 Feb 2026 03:08:14 +0000
Subject: [PATCH 001/324] test: add modernjs module federation RSC fixture
---
package.json | 1 +
pnpm-lock.yaml | 405 ++++++++++++++----
tests/integration/rsc-mf/host/.browserslistrc | 4 +
.../integration/rsc-mf/host/modern.config.ts | 28 ++
.../rsc-mf/host/module-federation.config.ts | 76 ++++
tests/integration/rsc-mf/host/package.json | 31 ++
.../rsc-mf/host/src/App.module.less | 5 +
tests/integration/rsc-mf/host/src/App.tsx | 22 +
.../rsc-mf/host/src/modern-app-env.d.ts | 3 +
tests/integration/rsc-mf/host/tsconfig.json | 12 +
tests/integration/rsc-mf/package.json | 5 +
.../integration/rsc-mf/remote/.browserslistrc | 4 +
.../rsc-mf/remote/modern.config.ts | 31 ++
.../rsc-mf/remote/module-federation.config.ts | 83 ++++
tests/integration/rsc-mf/remote/package.json | 31 ++
tests/integration/rsc-mf/remote/src/App.tsx | 13 +
.../src/components/RemoteClientCounter.css | 5 +
.../src/components/RemoteClientCounter.tsx | 54 +++
.../src/components/RemoteNestedMixed.tsx | 9 +
.../src/components/RemoteServerCard.tsx | 12 +
.../rsc-mf/remote/src/components/actions.ts | 16 +
.../remote/src/components/nestedActions.ts | 5 +
.../remote/src/components/serverOnly.ts | 8 +
.../rsc-mf/remote/src/modern-app-env.d.ts | 3 +
tests/integration/rsc-mf/remote/tsconfig.json | 12 +
tests/integration/rsc-mf/tests/index.test.ts | 224 ++++++++++
tests/integration/rsc-mf/tests/tsconfig.json | 12 +
27 files changed, 1025 insertions(+), 89 deletions(-)
create mode 100644 tests/integration/rsc-mf/host/.browserslistrc
create mode 100644 tests/integration/rsc-mf/host/modern.config.ts
create mode 100644 tests/integration/rsc-mf/host/module-federation.config.ts
create mode 100644 tests/integration/rsc-mf/host/package.json
create mode 100644 tests/integration/rsc-mf/host/src/App.module.less
create mode 100644 tests/integration/rsc-mf/host/src/App.tsx
create mode 100644 tests/integration/rsc-mf/host/src/modern-app-env.d.ts
create mode 100644 tests/integration/rsc-mf/host/tsconfig.json
create mode 100644 tests/integration/rsc-mf/package.json
create mode 100644 tests/integration/rsc-mf/remote/.browserslistrc
create mode 100644 tests/integration/rsc-mf/remote/modern.config.ts
create mode 100644 tests/integration/rsc-mf/remote/module-federation.config.ts
create mode 100644 tests/integration/rsc-mf/remote/package.json
create mode 100644 tests/integration/rsc-mf/remote/src/App.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.css
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteNestedMixed.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteServerCard.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/actions.ts
create mode 100644 tests/integration/rsc-mf/remote/src/components/nestedActions.ts
create mode 100644 tests/integration/rsc-mf/remote/src/components/serverOnly.ts
create mode 100644 tests/integration/rsc-mf/remote/src/modern-app-env.d.ts
create mode 100644 tests/integration/rsc-mf/remote/tsconfig.json
create mode 100644 tests/integration/rsc-mf/tests/index.test.ts
create mode 100644 tests/integration/rsc-mf/tests/tsconfig.json
diff --git a/package.json b/package.json
index 06019132ada4..e37bdf6c3590 100644
--- a/package.json
+++ b/package.json
@@ -87,6 +87,7 @@
"read-yaml-file>js-yaml": "3.14.2",
"@remix-run/router": ">=1.23.2",
"h3": ">=1.15.5",
+ "@rspack/core@2.0.0-beta.2": "npm:@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235",
"tar": ">=7.5.4",
"diff": ">=4.0.4",
"debug": ">=4.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index baf329f1debd..cbaeb4fa9755 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,6 +9,7 @@ overrides:
read-yaml-file>js-yaml: 3.14.2
'@remix-run/router': '>=1.23.2'
h3: '>=1.15.5'
+ '@rspack/core@2.0.0-beta.2': npm:@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235
tar: '>=7.5.4'
diff: '>=4.0.4'
debug: '>=4.3.1'
@@ -99,7 +100,7 @@ importers:
version: link:../../packages/tsconfig
'@rsdoctor/rspack-plugin':
specifier: ^1.5.2
- version: 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ version: 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@types/node':
specifier: ^20
version: 20.19.27
@@ -126,40 +127,40 @@ importers:
version: link:../../toolkit/utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@rsbuild/plugin-assets-retry':
specifier: 1.5.1
- version: 1.5.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.5.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-check-syntax':
specifier: 1.6.1
- version: 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-css-minimizer':
specifier: 1.1.1
- version: 1.1.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
+ version: 1.1.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
'@rsbuild/plugin-less':
specifier: 1.6.0
- version: 1.6.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.6.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-react':
specifier: 1.4.4
- version: 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-rem':
specifier: 1.0.5
- version: 1.0.5(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.0.5(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-sass':
specifier: 1.5.0
- version: 1.5.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.5.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-source-build':
specifier: 1.0.4
- version: 1.0.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.0.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsbuild/plugin-svgr':
specifier: 1.3.0
- version: 1.3.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(typescript@5.9.3)
+ version: 1.3.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(typescript@5.9.3)
'@rsbuild/plugin-type-check':
specifier: 1.3.3
- version: 1.3.3(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(typescript@5.9.3)
+ version: 1.3.3(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)
'@rsbuild/plugin-typed-css-modules':
specifier: 1.2.1
- version: 1.2.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.2.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@swc/core':
specifier: 1.15.11
version: 1.15.11(@swc/helpers@0.5.17)
@@ -210,10 +211,10 @@ importers:
version: 3.0.4(postcss@8.5.6)
rsbuild-plugin-rsc:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
+ version: 0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
rspack-manifest-plugin:
specifier: 5.2.1
- version: 5.2.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))
+ version: 5.2.1(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))
ts-deepmerge:
specifier: 7.0.3
version: 7.0.3
@@ -296,7 +297,7 @@ importers:
version: link:../../toolkit/types
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -348,7 +349,7 @@ importers:
version: link:../../toolkit/types
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -430,7 +431,7 @@ importers:
dependencies:
'@rsbuild/plugin-styled-components':
specifier: 1.6.1
- version: 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -474,16 +475,16 @@ importers:
devDependencies:
'@rsbuild/plugin-sass':
specifier: 1.5.0
- version: 1.5.0(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.5.0(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))
'@rspress/core':
specifier: 2.0.2
- version: 2.0.2(@module-federation/runtime-tools@2.0.0)(@types/react@19.2.13)(core-js@3.48.0)
+ version: 2.0.2(@types/react@19.2.13)(core-js@3.48.0)
'@rspress/plugin-llms':
specifier: 2.0.2
- version: 2.0.2(@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.0)(@types/react@19.2.13)(core-js@3.48.0))
+ version: 2.0.2(@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0))
'@rspress/shared':
specifier: 2.0.2
- version: 2.0.2(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.2(core-js@3.48.0)
'@shikijs/transformers':
specifier: ^3.21.0
version: 3.21.0
@@ -705,7 +706,7 @@ importers:
version: 4.4.2
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -784,7 +785,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
typescript:
specifier: ^5
version: 5.9.3
@@ -1249,7 +1250,7 @@ importers:
version: link:../../toolkit/utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -1362,7 +1363,7 @@ importers:
version: link:../utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -1895,7 +1896,7 @@ importers:
devDependencies:
'@rsbuild/plugin-react':
specifier: 1.4.4
- version: 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -2019,7 +2020,7 @@ importers:
version: 1.58.2
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ version: 2.0.0-beta.4(core-js@3.48.0)
'@types/connect':
specifier: ^3.4.38
version: 3.4.38
@@ -3189,7 +3190,7 @@ importers:
version: link:../../../packages/solutions/app-tools
'@rsdoctor/rspack-plugin':
specifier: ^1.5.2
- version: 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ version: 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@types/jest':
specifier: ^29.5.14
version: 29.5.14
@@ -3547,6 +3548,118 @@ importers:
specifier: ^5
version: 5.9.3
+ tests/integration/rsc-mf: {}
+
+ tests/integration/rsc-mf/host:
+ dependencies:
+ '@modern-js/render':
+ specifier: workspace:*
+ version: link:../../../../packages/runtime/render
+ '@modern-js/runtime':
+ specifier: workspace:*
+ version: link:../../../../packages/runtime/plugin-runtime
+ '@module-federation/modern-js-v3':
+ specifier: 2.0.0
+ version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime':
+ specifier: 2.0.0
+ version: 2.0.0
+ client-only:
+ specifier: ^0.0.1
+ version: 0.0.1
+ react:
+ specifier: ^19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.4(react@19.2.4)
+ react-server-dom-rspack:
+ specifier: 0.0.1-beta.0
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ server-only:
+ specifier: ^0.0.1
+ version: 0.0.1
+ devDependencies:
+ '@modern-js/app-tools':
+ specifier: workspace:*
+ version: link:../../../../packages/solutions/app-tools
+ '@modern-js/builder':
+ specifier: workspace:*
+ version: link:../../../../packages/cli/builder
+ '@types/jest':
+ specifier: ^29.5.14
+ version: 29.5.14
+ '@types/node':
+ specifier: ^20
+ version: 20.19.27
+ '@types/react':
+ specifier: ^19.2.13
+ version: 19.2.13
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.13)
+ cross-env:
+ specifier: ^7.0.3
+ version: 7.0.3
+ typescript:
+ specifier: ^5
+ version: 5.9.3
+
+ tests/integration/rsc-mf/remote:
+ dependencies:
+ '@modern-js/render':
+ specifier: workspace:*
+ version: link:../../../../packages/runtime/render
+ '@modern-js/runtime':
+ specifier: workspace:*
+ version: link:../../../../packages/runtime/plugin-runtime
+ '@module-federation/modern-js-v3':
+ specifier: 2.0.0
+ version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime':
+ specifier: 2.0.0
+ version: 2.0.0
+ client-only:
+ specifier: ^0.0.1
+ version: 0.0.1
+ react:
+ specifier: ^19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.4(react@19.2.4)
+ react-server-dom-rspack:
+ specifier: 0.0.1-beta.0
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ server-only:
+ specifier: ^0.0.1
+ version: 0.0.1
+ devDependencies:
+ '@modern-js/app-tools':
+ specifier: workspace:*
+ version: link:../../../../packages/solutions/app-tools
+ '@modern-js/builder':
+ specifier: workspace:*
+ version: link:../../../../packages/cli/builder
+ '@types/jest':
+ specifier: ^29.5.14
+ version: 29.5.14
+ '@types/node':
+ specifier: ^20
+ version: 20.19.27
+ '@types/react':
+ specifier: ^19.2.13
+ version: 19.2.13
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.13)
+ cross-env:
+ specifier: ^7.0.3
+ version: 7.0.3
+ typescript:
+ specifier: ^5
+ version: 5.9.3
+
tests/integration/rsc-ssr-app:
dependencies:
'@modern-js/render':
@@ -4431,7 +4544,7 @@ importers:
version: link:../../../../../packages/runtime/plugin-runtime
'@rsbuild/plugin-babel':
specifier: 1.1.0
- version: 1.1.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ version: 1.1.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
react:
specifier: ^19.2.4
version: 19.2.4
@@ -6688,6 +6801,70 @@ packages:
typescript:
optional: true
+ '@rspack-canary/binding-darwin-arm64@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-uA56E4Uk5vfkPaxfjo/q4ecG9wRlf4tgHm6qtvkhiBC6ufzaJBv97e9L0TjIfwFMb1i2aU6OkRNSV0t9aZZlcQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rspack-canary/binding-darwin-x64@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-5+hcwmz2GuilR+CuHUICMuj45p0d52+N8CrG5OXb0y8jFc5tPYHLnw0EpXzAqVs8qe0/zh8EH4M8RwiiMECdMA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rspack-canary/binding-linux-arm64-gnu@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-eokt1t08Ux74n596DZmetFq3ITwdbS7DmzPnJkKueczYBKfLu/E3tthJGCbq7YGilQjruV/M7nhPhdhr16a6cg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rspack-canary/binding-linux-arm64-musl@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-EryjXTYQAJ73FD9y3aBwjMbsy7xF/xI3PYeJGavdFI9loGn9LmS77oVNpJrx/qLpbR0+k3UZLgrfvxM+fR1cAA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rspack-canary/binding-linux-x64-gnu@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-jeajr2e5cNqyNKe0/2hbD4B6sDWD5fv/rWqHLXRd9mwmHxvLcN/A1IB7d8YeajfqH/OwaLzsEJ6MLGg6JNssQQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rspack-canary/binding-linux-x64-musl@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-G7U0bBLIGcRAsOtJV2F7kGDnLbl0EfHf80HxfLF1T2ioLOtHl1amYOACKXdqbFOyy9kWKTRoCxLMoPI7xjfrgw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rspack-canary/binding-wasm32-wasi@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-5kzRtjrF9gBJZa6sGLX02VqMc+OxyI5O7FGDpbeLoCCyhfVvAfiGz6cCbIuqGRie2KktJG0Z3wDzGEJDJ6M54g==}
+ cpu: [wasm32]
+
+ '@rspack-canary/binding-win32-arm64-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-RK89Zpxg3M31zA1mnzxdpjBIsoC/FzAOUr4JzzAfy7v2Jyk2YxHsu0jUjxdRFiE0+CC35fxZR0DPQWLmqcLcBg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rspack-canary/binding-win32-ia32-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-C2CtzJf7RKRxSbzImH0y5nqO9xc6C+MPEHfMlv73dkdG+7+k3J1hwvMm0qiqqR6BetAplD+GoAS14DmmsIlzIw==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rspack-canary/binding-win32-x64-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-O6n1jJH9PiZYzqSDKKqcxMUri3nTdBkZ1MTSMJV0ca2aQPbTv+P6TOf8gwtciKO4bszOr1bg23VIkO7pfNC3yQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rspack-canary/binding@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-gp/33WihCbOk1h3wXc9tNEjZ2wb9n9YC1XFs2MKUJz/Tqp0TfIz84Goc/QW+NleGEQ/rw+xzBXc5iku2b4aMgw==}
+
+ '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235':
+ resolution: {integrity: sha512-VH9njrpSKv4/EBp53XvUJMMSbBtydx7R0ZWPyh/5a4gvGVafTLCiKV+shMZMgV5uWYYVTbA+5Fo0vL03a6iW1Q==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@module-federation/runtime-tools': 0.24.1
+ '@swc/helpers': '>=0.5.1'
+ peerDependenciesMeta:
+ '@module-federation/runtime-tools':
+ optional: true
+ '@swc/helpers':
+ optional: true
+
'@rspack/binding-darwin-arm64@1.7.0':
resolution: {integrity: sha512-HMYrhvVh3sMRBXl6cSI2JqsvlHJKQ42qX+Sw4qbj7LeZBN6Gv4GjfL3cXRLUTdO37FOC0uLEUYgxVXetx/Y4sA==}
cpu: [arm64]
@@ -17202,9 +17379,9 @@ snapshots:
core-js: 3.47.0
jiti: 2.6.1
- '@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)':
+ '@rsbuild/core@2.0.0-beta.1(core-js@3.48.0)':
dependencies:
- '@rspack/core': 2.0.0-alpha.1(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
+ '@rspack/core': 2.0.0-alpha.1(@swc/helpers@0.5.18)
'@swc/helpers': 0.5.18
jiti: 2.6.1
optionalDependencies:
@@ -17212,26 +17389,26 @@ snapshots:
transitivePeerDependencies:
- '@module-federation/runtime-tools'
- '@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)':
+ '@rsbuild/core@2.0.0-beta.4(core-js@3.48.0)':
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
+ '@rspack/core': '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@swc/helpers@0.5.18)'
'@swc/helpers': 0.5.18
optionalDependencies:
core-js: 3.48.0
transitivePeerDependencies:
- '@module-federation/runtime-tools'
- '@rsbuild/plugin-assets-retry@1.5.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-assets-retry@1.5.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
'@babel/core': 7.28.6
'@babel/plugin-proposal-decorators': 7.28.6(@babel/core@7.28.6)
'@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.28.6)
'@babel/preset-typescript': 7.28.5(@babel/core@7.28.6)
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
'@types/babel__core': 7.20.5
deepmerge: 4.3.1
reduce-configs: 1.1.1
@@ -17239,7 +17416,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
acorn: 8.15.0
browserslist-to-es-version: 1.2.0
@@ -17247,14 +17424,14 @@ snapshots:
picocolors: 1.1.1
source-map: 0.7.6
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-css-minimizer@1.1.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))':
+ '@rsbuild/plugin-css-minimizer@1.1.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))':
dependencies:
css-minimizer-webpack-plugin: 7.0.2(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
reduce-configs: 1.1.1
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
transitivePeerDependencies:
- '@parcel/css'
- '@swc/css'
@@ -17264,72 +17441,72 @@ snapshots:
- lightningcss
- webpack
- '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
deepmerge: 4.3.1
reduce-configs: 1.1.1
- '@rsbuild/plugin-react@1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-react@1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
'@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0)
react-refresh: 0.18.0
transitivePeerDependencies:
- webpack-hot-middleware
- '@rsbuild/plugin-react@1.4.5(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-react@1.4.5(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
'@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0)
react-refresh: 0.18.0
transitivePeerDependencies:
- webpack-hot-middleware
- '@rsbuild/plugin-rem@1.0.5(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-rem@1.0.5(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
deepmerge: 4.3.1
terser: 5.46.0
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
deepmerge: 4.3.1
loader-utils: 2.0.4
postcss: 8.5.6
reduce-configs: 1.1.1
sass-embedded: 1.97.3
- '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
deepmerge: 4.3.1
loader-utils: 2.0.4
postcss: 8.5.6
reduce-configs: 1.1.1
sass-embedded: 1.97.3
- '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
fast-glob: 3.3.3
json5: 2.2.3
yaml: 2.8.2
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-styled-components@1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-styled-components@1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
dependencies:
'@swc/plugin-styled-components': 12.3.0
reduce-configs: 1.1.1
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-svgr@1.3.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(typescript@5.9.3)':
+ '@rsbuild/plugin-svgr@1.3.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(typescript@5.9.3)':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
- '@rsbuild/plugin-react': 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/plugin-react': 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@svgr/core': 8.1.0(typescript@5.9.3)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
'@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)
@@ -17340,27 +17517,27 @@ snapshots:
- typescript
- webpack-hot-middleware
- '@rsbuild/plugin-type-check@1.3.3(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(typescript@5.9.3)':
+ '@rsbuild/plugin-type-check@1.3.3(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)':
dependencies:
deepmerge: 4.3.1
json5: 2.2.3
reduce-configs: 1.1.1
- ts-checker-rspack-plugin: 1.2.3(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(typescript@5.9.3)
+ ts-checker-rspack-plugin: 1.2.3(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
transitivePeerDependencies:
- '@rspack/core'
- typescript
- '@rsbuild/plugin-typed-css-modules@1.2.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))':
+ '@rsbuild/plugin-typed-css-modules@1.2.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
'@rsdoctor/client@1.5.2': {}
- '@rsdoctor/core@1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@rsdoctor/core@1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
+ '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
'@rsdoctor/graph': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/sdk': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/types': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
@@ -17391,9 +17568,9 @@ snapshots:
- '@rspack/core'
- webpack
- '@rsdoctor/rspack-plugin@1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@rsdoctor/rspack-plugin@1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@rsdoctor/core': 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@rsdoctor/core': 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/graph': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/sdk': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/types': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
@@ -17463,6 +17640,57 @@ snapshots:
transitivePeerDependencies:
- '@typescript/native-preview'
+ '@rspack-canary/binding-darwin-arm64@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-darwin-x64@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-linux-arm64-gnu@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-linux-arm64-musl@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-linux-x64-gnu@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-linux-x64-musl@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-wasm32-wasi@2.0.0-canary-032bd1ff-20260212021235':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.0.7
+ optional: true
+
+ '@rspack-canary/binding-win32-arm64-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-win32-ia32-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding-win32-x64-msvc@2.0.0-canary-032bd1ff-20260212021235':
+ optional: true
+
+ '@rspack-canary/binding@2.0.0-canary-032bd1ff-20260212021235':
+ optionalDependencies:
+ '@rspack/binding-darwin-arm64': '@rspack-canary/binding-darwin-arm64@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-darwin-x64': '@rspack-canary/binding-darwin-x64@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-linux-arm64-gnu': '@rspack-canary/binding-linux-arm64-gnu@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-linux-arm64-musl': '@rspack-canary/binding-linux-arm64-musl@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-linux-x64-gnu': '@rspack-canary/binding-linux-x64-gnu@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-linux-x64-musl': '@rspack-canary/binding-linux-x64-musl@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-wasm32-wasi': '@rspack-canary/binding-wasm32-wasi@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-win32-arm64-msvc': '@rspack-canary/binding-win32-arm64-msvc@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-win32-ia32-msvc': '@rspack-canary/binding-win32-ia32-msvc@2.0.0-canary-032bd1ff-20260212021235'
+ '@rspack/binding-win32-x64-msvc': '@rspack-canary/binding-win32-x64-msvc@2.0.0-canary-032bd1ff-20260212021235'
+
+ '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@swc/helpers@0.5.18)':
+ dependencies:
+ '@rspack/binding': '@rspack-canary/binding@2.0.0-canary-032bd1ff-20260212021235'
+ optionalDependencies:
+ '@swc/helpers': 0.5.18
+
'@rspack/binding-darwin-arm64@1.7.0':
optional: true
@@ -17659,12 +17887,11 @@ snapshots:
optionalDependencies:
'@swc/helpers': 0.5.18
- '@rspack/core@2.0.0-alpha.1(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)':
+ '@rspack/core@2.0.0-alpha.1(@swc/helpers@0.5.18)':
dependencies:
'@rspack/binding': 2.0.0-alpha.1
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
- '@module-federation/runtime-tools': 2.0.0
'@swc/helpers': 0.5.18
'@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)':
@@ -17689,13 +17916,13 @@ snapshots:
html-entities: 2.6.0
react-refresh: 0.18.0
- '@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.0)(@types/react@19.2.13)(core-js@3.48.0)':
+ '@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0)':
dependencies:
'@mdx-js/mdx': 3.1.1
'@mdx-js/react': 3.1.1(@types/react@19.2.13)(react@19.2.4)
- '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
- '@rsbuild/plugin-react': 1.4.5(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))
- '@rspress/shared': 2.0.2(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
+ '@rsbuild/plugin-react': 1.4.5(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))
+ '@rspress/shared': 2.0.2(core-js@3.48.0)
'@shikijs/rehype': 3.22.0
'@types/unist': 3.0.3
'@unhead/react': 2.1.2(react@19.2.4)
@@ -17740,9 +17967,9 @@ snapshots:
- supports-color
- webpack-hot-middleware
- '@rspress/plugin-llms@2.0.2(@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.0)(@types/react@19.2.13)(core-js@3.48.0))':
+ '@rspress/plugin-llms@2.0.2(@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0))':
dependencies:
- '@rspress/core': 2.0.2(@module-federation/runtime-tools@2.0.0)(@types/react@19.2.13)(core-js@3.48.0)
+ '@rspress/core': 2.0.2(@types/react@19.2.13)(core-js@3.48.0)
remark-mdx: 3.1.1
remark-parse: 11.0.0
remark-stringify: 11.0.0
@@ -17751,9 +17978,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@rspress/shared@2.0.2(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)':
+ '@rspress/shared@2.0.2(core-js@3.48.0)':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
'@shikijs/rehype': 3.22.0
gray-matter: 4.0.3
lodash-es: 4.17.23
@@ -24970,15 +25197,15 @@ snapshots:
optionalDependencies:
react-dom: 19.2.4(react@19.2.4)
- react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -25273,14 +25500,14 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
- rsbuild-plugin-rsc@0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
+ rsbuild-plugin-rsc@0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.0)(core-js@3.48.0)
- react-server-dom-rspack: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ react-server-dom-rspack: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
rslog@1.3.2: {}
- rspack-manifest-plugin@5.2.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)):
+ rspack-manifest-plugin@5.2.1(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17)):
dependencies:
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
@@ -26179,7 +26406,7 @@ snapshots:
trough@2.2.0: {}
- ts-checker-rspack-plugin@1.2.3(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17))(typescript@5.9.3):
+ ts-checker-rspack-plugin@1.2.3(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3):
dependencies:
'@babel/code-frame': 7.27.1
'@rspack/lite-tapable': 1.1.0
diff --git a/tests/integration/rsc-mf/host/.browserslistrc b/tests/integration/rsc-mf/host/.browserslistrc
new file mode 100644
index 000000000000..15b7c26176b2
--- /dev/null
+++ b/tests/integration/rsc-mf/host/.browserslistrc
@@ -0,0 +1,4 @@
+chrome >= 87
+edge >= 88
+firefox >= 78
+safari >= 14
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
new file mode 100644
index 000000000000..1d2990d2f328
--- /dev/null
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -0,0 +1,28 @@
+import path from 'path';
+import { appTools, defineConfig } from '@modern-js/app-tools';
+import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
+
+export default defineConfig({
+ server: {
+ ssr: {
+ mode: 'stream',
+ },
+ rsc: true,
+ },
+ output: {
+ polyfill: 'off',
+ disableTsChecker: true,
+ },
+ performance: {
+ buildCache: false,
+ },
+ tools: {
+ bundlerChain(chain) {
+ chain.resolve.modules
+ .clear()
+ .add(path.resolve(__dirname, 'node_modules'))
+ .add('node_modules');
+ },
+ },
+ plugins: [appTools(), moduleFederationPlugin()],
+});
diff --git a/tests/integration/rsc-mf/host/module-federation.config.ts b/tests/integration/rsc-mf/host/module-federation.config.ts
new file mode 100644
index 000000000000..8a830fd27cc6
--- /dev/null
+++ b/tests/integration/rsc-mf/host/module-federation.config.ts
@@ -0,0 +1,76 @@
+import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
+
+const REMOTE_PORT = process.env.RSC_MF_REMOTE_PORT || '3008';
+
+const LAYERS = {
+ ssr: 'server-side-rendering',
+ rsc: 'react-server-components',
+};
+
+const sharedByScope = () => [
+ {
+ react: {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ 'react-dom': {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ },
+ {
+ react: {
+ import: 'react',
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ },
+ {
+ react: {
+ import: 'react',
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ },
+];
+
+export default createModuleFederationConfig({
+ name: 'rscHost',
+ remotes: {
+ rscRemote: `rscRemote@http://127.0.0.1:${REMOTE_PORT}/static/mf-manifest.json`,
+ },
+ shared: sharedByScope(),
+ dts: false,
+ experiments: {
+ asyncStartup: true,
+ rsc: true,
+ } as any,
+});
diff --git a/tests/integration/rsc-mf/host/package.json b/tests/integration/rsc-mf/host/package.json
new file mode 100644
index 000000000000..010e39c8021e
--- /dev/null
+++ b/tests/integration/rsc-mf/host/package.json
@@ -0,0 +1,31 @@
+{
+ "private": true,
+ "name": "rsc-mf-host",
+ "version": "2.66.0",
+ "scripts": {
+ "dev": "cross-env modern dev",
+ "build": "cross-env modern build",
+ "serve": "modern serve"
+ },
+ "dependencies": {
+ "@modern-js/render": "workspace:*",
+ "@modern-js/runtime": "workspace:*",
+ "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/runtime": "2.0.0",
+ "client-only": "^0.0.1",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "react-server-dom-rspack": "0.0.1-beta.0",
+ "server-only": "^0.0.1"
+ },
+ "devDependencies": {
+ "@modern-js/app-tools": "workspace:*",
+ "@modern-js/builder": "workspace:*",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^20",
+ "@types/react": "^19.2.13",
+ "@types/react-dom": "^19.2.3",
+ "cross-env": "^7.0.3",
+ "typescript": "^5"
+ }
+}
diff --git a/tests/integration/rsc-mf/host/src/App.module.less b/tests/integration/rsc-mf/host/src/App.module.less
new file mode 100644
index 000000000000..91794b56811f
--- /dev/null
+++ b/tests/integration/rsc-mf/host/src/App.module.less
@@ -0,0 +1,5 @@
+.root {
+ border: 2px dashed #df7e00;
+ margin: 1em;
+ padding: 1em;
+}
diff --git a/tests/integration/rsc-mf/host/src/App.tsx b/tests/integration/rsc-mf/host/src/App.tsx
new file mode 100644
index 000000000000..2c2135f233a0
--- /dev/null
+++ b/tests/integration/rsc-mf/host/src/App.tsx
@@ -0,0 +1,22 @@
+'use server-entry';
+import 'server-only';
+import { Suspense } from 'react';
+import { RemoteNestedMixed } from 'rscRemote/RemoteNestedMixed';
+import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
+import styles from './App.module.less';
+
+const App = () => {
+ const remoteServerOnlyInfo = getServerOnlyInfo();
+
+ return (
+
+
Host RSC Module Federation
+
{remoteServerOnlyInfo}
+
Loading Remote RSC... }>
+
+
+
+ );
+};
+
+export default App;
diff --git a/tests/integration/rsc-mf/host/src/modern-app-env.d.ts b/tests/integration/rsc-mf/host/src/modern-app-env.d.ts
new file mode 100644
index 000000000000..c965dfb88430
--- /dev/null
+++ b/tests/integration/rsc-mf/host/src/modern-app-env.d.ts
@@ -0,0 +1,3 @@
+///
+///
+///
diff --git a/tests/integration/rsc-mf/host/tsconfig.json b/tests/integration/rsc-mf/host/tsconfig.json
new file mode 100644
index 000000000000..9637e7fc052c
--- /dev/null
+++ b/tests/integration/rsc-mf/host/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "@modern-js/tsconfig/base",
+ "compilerOptions": {
+ "declaration": false,
+ "jsx": "react-jsx",
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src", "config"]
+}
diff --git a/tests/integration/rsc-mf/package.json b/tests/integration/rsc-mf/package.json
new file mode 100644
index 000000000000..7433e359d88a
--- /dev/null
+++ b/tests/integration/rsc-mf/package.json
@@ -0,0 +1,5 @@
+{
+ "private": true,
+ "name": "rsc-mf-test",
+ "version": "2.66.0"
+}
diff --git a/tests/integration/rsc-mf/remote/.browserslistrc b/tests/integration/rsc-mf/remote/.browserslistrc
new file mode 100644
index 000000000000..15b7c26176b2
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/.browserslistrc
@@ -0,0 +1,4 @@
+chrome >= 87
+edge >= 88
+firefox >= 78
+safari >= 14
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
new file mode 100644
index 000000000000..afcb3c432c9d
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -0,0 +1,31 @@
+import path from 'path';
+import { appTools, defineConfig } from '@modern-js/app-tools';
+import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
+
+const remotePort = process.env.RSC_MF_REMOTE_PORT || process.env.PORT || '3008';
+
+export default defineConfig({
+ server: {
+ ssr: {
+ mode: 'stream',
+ },
+ rsc: true,
+ },
+ output: {
+ polyfill: 'off',
+ disableTsChecker: true,
+ assetPrefix: `http://127.0.0.1:${remotePort}`,
+ },
+ performance: {
+ buildCache: false,
+ },
+ tools: {
+ bundlerChain(chain) {
+ chain.resolve.modules
+ .clear()
+ .add(path.resolve(__dirname, 'node_modules'))
+ .add('node_modules');
+ },
+ },
+ plugins: [appTools(), moduleFederationPlugin()],
+});
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
new file mode 100644
index 000000000000..c857e4ffcebf
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -0,0 +1,83 @@
+import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
+
+const LAYERS = {
+ ssr: 'server-side-rendering',
+ rsc: 'react-server-components',
+};
+
+const sharedByScope = () => [
+ {
+ react: {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ 'react-dom': {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ },
+ {
+ react: {
+ import: 'react',
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ },
+ {
+ react: {
+ import: 'react',
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ },
+];
+
+export default createModuleFederationConfig({
+ name: 'rscRemote',
+ manifest: {
+ filePath: 'static',
+ },
+ filename: 'static/remoteEntry.js',
+ exposes: {
+ './RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
+ './RemoteServerCard': './src/components/RemoteServerCard.tsx',
+ './RemoteNestedMixed': './src/components/RemoteNestedMixed.tsx',
+ './remoteServerOnly': './src/components/serverOnly.ts',
+ './actions': './src/components/actions.ts',
+ './nestedActions': './src/components/nestedActions.ts',
+ },
+ shared: sharedByScope(),
+ dts: false,
+ experiments: {
+ asyncStartup: true,
+ rsc: true,
+ } as any,
+});
diff --git a/tests/integration/rsc-mf/remote/package.json b/tests/integration/rsc-mf/remote/package.json
new file mode 100644
index 000000000000..9b040ea2fe51
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/package.json
@@ -0,0 +1,31 @@
+{
+ "private": true,
+ "name": "rsc-mf-remote",
+ "version": "2.66.0",
+ "scripts": {
+ "dev": "cross-env modern dev",
+ "build": "cross-env modern build",
+ "serve": "modern serve"
+ },
+ "dependencies": {
+ "@modern-js/render": "workspace:*",
+ "@modern-js/runtime": "workspace:*",
+ "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/runtime": "2.0.0",
+ "client-only": "^0.0.1",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "react-server-dom-rspack": "0.0.1-beta.0",
+ "server-only": "^0.0.1"
+ },
+ "devDependencies": {
+ "@modern-js/app-tools": "workspace:*",
+ "@modern-js/builder": "workspace:*",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^20",
+ "@types/react": "^19.2.13",
+ "@types/react-dom": "^19.2.3",
+ "cross-env": "^7.0.3",
+ "typescript": "^5"
+ }
+}
diff --git a/tests/integration/rsc-mf/remote/src/App.tsx b/tests/integration/rsc-mf/remote/src/App.tsx
new file mode 100644
index 000000000000..3fe8fd8173cd
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/App.tsx
@@ -0,0 +1,13 @@
+'use server-entry';
+import { RemoteNestedMixed } from './components/RemoteNestedMixed';
+
+const App = () => {
+ return (
+
+
Remote RSC Module Federation
+
+
+ );
+};
+
+export default App;
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.css b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.css
new file mode 100644
index 000000000000..61c79ccc5835
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.css
@@ -0,0 +1,5 @@
+.remote-client-counter {
+ border: 2px dashed #2563eb;
+ margin-top: 12px;
+ padding: 8px;
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
new file mode 100644
index 000000000000..599622852f3b
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -0,0 +1,54 @@
+'use client';
+import { useActionState, useState } from 'react';
+import './RemoteClientCounter.css';
+import { incrementRemoteCount, remoteActionEcho } from './actions';
+import { nestedRemoteAction } from './nestedActions';
+
+export function RemoteClientCounter() {
+ const [localCount, setLocalCount] = useState(0);
+ const [serverCount, formAction, isPending] = useActionState(
+ incrementRemoteCount,
+ 0,
+ );
+ const [nestedResult, setNestedResult] = useState('');
+ const [remoteActionResult, setRemoteActionResult] = useState('');
+
+ const handleRunActions = async () => {
+ const [nestedResultValue, remoteActionValue] = await Promise.all([
+ nestedRemoteAction('from-client'),
+ remoteActionEcho('from-client'),
+ ]);
+ setNestedResult(nestedResultValue);
+ setRemoteActionResult(remoteActionValue);
+ };
+
+ return (
+
+
Remote Client Counter
+
{localCount}
+
+
{serverCount}
+
+
+
{nestedResult}
+
{remoteActionResult}
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteNestedMixed.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteNestedMixed.tsx
new file mode 100644
index 000000000000..338657f74ed9
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteNestedMixed.tsx
@@ -0,0 +1,9 @@
+import { RemoteServerCard } from './RemoteServerCard';
+
+export function RemoteNestedMixed({ label }: { label: string }) {
+ return (
+
+
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteServerCard.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteServerCard.tsx
new file mode 100644
index 000000000000..4b14d6fd4a5f
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteServerCard.tsx
@@ -0,0 +1,12 @@
+import { RemoteClientCounter } from './RemoteClientCounter';
+import { getServerOnlyInfo } from './serverOnly';
+
+export function RemoteServerCard({ label }: { label: string }) {
+ return (
+
+ {label}
+ {getServerOnlyInfo()}
+
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/actions.ts b/tests/integration/rsc-mf/remote/src/components/actions.ts
new file mode 100644
index 000000000000..e4c094c0a899
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/actions.ts
@@ -0,0 +1,16 @@
+'use server';
+
+let remoteCountState = 0;
+
+export async function incrementRemoteCount(
+ _previousState: number,
+ formData: FormData,
+) {
+ const count = Number(formData.get('count') || 1);
+ remoteCountState += count;
+ return remoteCountState;
+}
+
+export async function remoteActionEcho(value: string) {
+ return `remote-action:${value}`;
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/nestedActions.ts b/tests/integration/rsc-mf/remote/src/components/nestedActions.ts
new file mode 100644
index 000000000000..6d4d86f0a1d2
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/nestedActions.ts
@@ -0,0 +1,5 @@
+'use server';
+
+export async function nestedRemoteAction(value: string) {
+ return `nested-action:${value}`;
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/serverOnly.ts b/tests/integration/rsc-mf/remote/src/components/serverOnly.ts
new file mode 100644
index 000000000000..3891d5b4ded1
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/serverOnly.ts
@@ -0,0 +1,8 @@
+import 'server-only';
+import { readFileSync } from 'node:fs';
+
+export function getServerOnlyInfo() {
+ return typeof readFileSync === 'function'
+ ? 'remote-server-only-ok'
+ : 'remote-server-only-missing';
+}
diff --git a/tests/integration/rsc-mf/remote/src/modern-app-env.d.ts b/tests/integration/rsc-mf/remote/src/modern-app-env.d.ts
new file mode 100644
index 000000000000..c965dfb88430
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/modern-app-env.d.ts
@@ -0,0 +1,3 @@
+///
+///
+///
diff --git a/tests/integration/rsc-mf/remote/tsconfig.json b/tests/integration/rsc-mf/remote/tsconfig.json
new file mode 100644
index 000000000000..9637e7fc052c
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "@modern-js/tsconfig/base",
+ "compilerOptions": {
+ "declaration": false,
+ "jsx": "react-jsx",
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src", "config"]
+}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
new file mode 100644
index 000000000000..3e3a9ef38c3f
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -0,0 +1,224 @@
+import path from 'path';
+import { isVersionAtLeast18 } from '@modern-js/utils';
+import type { Browser, Page } from 'puppeteer';
+import puppeteer from 'puppeteer';
+import {
+ getPort,
+ killApp,
+ launchApp,
+ launchOptions,
+ modernBuild,
+ modernServe,
+} from '../../../utils/modernTestUtils';
+
+const fixtureDir = path.resolve(__dirname, '../');
+const hostDir = path.resolve(fixtureDir, 'host');
+const remoteDir = path.resolve(fixtureDir, 'remote');
+
+type Mode = 'dev' | 'build';
+
+interface TestConfig {
+ mode: Mode;
+}
+
+interface TestContext {
+ hostPort: number;
+ page: Page;
+}
+
+function skipForLowerNodeVersion() {
+ if (!isVersionAtLeast18()) {
+ test('should skip in lower node version', () => {
+ expect(true).toBe(true);
+ });
+ return true;
+ }
+ return false;
+}
+
+function createRemoteEnv(remotePort: number) {
+ return {
+ RSC_MF_REMOTE_PORT: String(remotePort),
+ MODERN_MF_AUTO_CORS: 'true',
+ };
+}
+
+function createHostEnv(remotePort: number) {
+ return {
+ RSC_MF_REMOTE_PORT: String(remotePort),
+ };
+}
+
+async function waitForAppReady(port: number, maxRetries = 60) {
+ for (let index = 0; index < maxRetries; index++) {
+ try {
+ const response = await fetch(`http://127.0.0.1:${port}`, {
+ method: 'HEAD',
+ signal: AbortSignal.timeout(2000),
+ });
+ if (response.ok || response.status < 500) {
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ return;
+ }
+ } catch (error) {}
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ }
+
+ throw new Error(`App on port ${port} did not become ready`);
+}
+
+async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
+ const response = await fetch(`http://127.0.0.1:${hostPort}`);
+ const html = await response.text();
+ expect(html).toContain('Host RSC Module Federation');
+ expect(html).toContain('Remote Federated Tree');
+ expect(html).toContain('remote-server-only-ok');
+
+ await page.goto(`http://127.0.0.1:${hostPort}`, {
+ waitUntil: ['networkidle0', 'domcontentloaded'],
+ });
+ const hostRemoteServerOnly = await page.$eval(
+ '.host-remote-server-only',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteServerOnly).toBe('remote-server-only-ok');
+}
+
+async function supportRemoteClientAndServerActions({
+ hostPort,
+ page,
+}: TestContext) {
+ await page.goto(`http://127.0.0.1:${hostPort}`, {
+ waitUntil: ['networkidle0', 'domcontentloaded'],
+ });
+ await page.waitForSelector('.remote-client-local-increment');
+
+ let localCount = await page.$eval('.remote-client-local-count', el =>
+ el.textContent?.trim(),
+ );
+ let serverCount = await page.$eval('.remote-client-server-count', el =>
+ el.textContent?.trim(),
+ );
+ expect(localCount).toBe('0');
+ expect(serverCount).toBe('0');
+
+ await page.click('.remote-client-local-increment');
+ localCount = await page.$eval('.remote-client-local-count', el =>
+ el.textContent?.trim(),
+ );
+ expect(localCount).toBe('1');
+
+ await page.click('.remote-client-server-increment');
+ await page.waitForFunction(
+ () =>
+ !document
+ .querySelector('.remote-client-server-increment')
+ ?.hasAttribute('disabled'),
+ );
+ serverCount = await page.$eval('.remote-client-server-count', el =>
+ el.textContent?.trim(),
+ );
+ expect(serverCount).toBe('1');
+
+ await page.click('.remote-client-run-actions');
+ await page.waitForFunction(() => {
+ const nested = document.querySelector('.remote-client-nested-result');
+ const remoteAction = document.querySelector(
+ '.remote-client-remote-action-result',
+ );
+ return (
+ nested?.textContent?.trim() === 'nested-action:from-client' &&
+ remoteAction?.textContent?.trim() === 'remote-action:from-client'
+ );
+ });
+}
+
+function runTests({ mode }: TestConfig) {
+ describe(mode, () => {
+ let remoteApp: any;
+ let hostApp: any;
+ let remotePort: number;
+ let hostPort: number;
+ let page: Page;
+ let browser: Browser;
+ const runtimeErrors: string[] = [];
+
+ if (skipForLowerNodeVersion()) {
+ return;
+ }
+
+ beforeAll(async () => {
+ jest.setTimeout(1000 * 60 * 8);
+ remotePort = await getPort();
+ hostPort = await getPort();
+
+ const remoteEnv = createRemoteEnv(remotePort);
+ const hostEnv = createHostEnv(remotePort);
+
+ if (mode === 'dev') {
+ remoteApp = await launchApp(remoteDir, remotePort, {}, remoteEnv);
+ await waitForAppReady(remotePort);
+
+ hostApp = await launchApp(hostDir, hostPort, {}, hostEnv);
+ await waitForAppReady(hostPort);
+ } else {
+ await modernBuild(remoteDir, [], { env: remoteEnv });
+ await modernBuild(hostDir, [], { env: hostEnv });
+
+ remoteApp = await modernServe(remoteDir, remotePort, {
+ env: {
+ PORT: String(remotePort),
+ NODE_ENV: 'production',
+ ...remoteEnv,
+ },
+ });
+ await waitForAppReady(remotePort);
+
+ hostApp = await modernServe(hostDir, hostPort, {
+ env: {
+ PORT: String(hostPort),
+ NODE_ENV: 'production',
+ ...hostEnv,
+ },
+ });
+ await waitForAppReady(hostPort);
+ }
+
+ browser = await puppeteer.launch(launchOptions as any);
+ page = await browser.newPage();
+
+ if (mode === 'build') {
+ page.on('pageerror', error => {
+ runtimeErrors.push((error as Error).message);
+ });
+ }
+ });
+
+ afterAll(async () => {
+ if (browser) {
+ await browser.close();
+ }
+ if (hostApp) {
+ await killApp(hostApp);
+ }
+ if (remoteApp) {
+ await killApp(remoteApp);
+ }
+ });
+
+ it('should render remote RSC content in host app', () =>
+ renderRemoteRscIntoHost({ hostPort, page }));
+
+ it('should support remote use client and server actions', () =>
+ supportRemoteClientAndServerActions({ hostPort, page }));
+
+ if (mode === 'build') {
+ it('should have no browser runtime errors', () => {
+ expect(runtimeErrors).toEqual([]);
+ });
+ }
+ });
+}
+
+runTests({ mode: 'dev' });
+runTests({ mode: 'build' });
diff --git a/tests/integration/rsc-mf/tests/tsconfig.json b/tests/integration/rsc-mf/tests/tsconfig.json
new file mode 100644
index 000000000000..10f49432232c
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "@modern-js/tsconfig/base",
+ "compilerOptions": {
+ "declaration": true,
+ "jsx": "preserve",
+ "baseUrl": "./",
+ "emitDeclarationOnly": true,
+ "isolatedModules": true,
+ "paths": {},
+ "types": ["node", "jest"]
+ }
+}
From 46e54a6f571fddaa292f285ffc981a806c60ba56 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Thu, 12 Feb 2026 03:26:53 +0000
Subject: [PATCH 002/324] test: capture current modernjs rsc federation runtime
blocker
---
.../integration/rsc-mf/host/modern.config.ts | 5 +-
.../rsc-mf/host/module-federation.config.ts | 65 ++---------------
.../App.module.less | 0
.../src/{ => server-component-root}/App.tsx | 1 -
.../rsc-mf/remote/modern.config.ts | 5 +-
.../rsc-mf/remote/module-federation.config.ts | 65 ++---------------
tests/integration/rsc-mf/remote/src/App.tsx | 1 -
.../remote/src/components/serverOnly.ts | 5 +-
tests/integration/rsc-mf/tests/index.test.ts | 71 +++++++++++--------
9 files changed, 53 insertions(+), 165 deletions(-)
rename tests/integration/rsc-mf/host/src/{ => server-component-root}/App.module.less (100%)
rename tests/integration/rsc-mf/host/src/{ => server-component-root}/App.tsx (96%)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index 1d2990d2f328..e378cfb6c527 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -4,9 +4,6 @@ import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
export default defineConfig({
server: {
- ssr: {
- mode: 'stream',
- },
rsc: true,
},
output: {
@@ -24,5 +21,5 @@ export default defineConfig({
.add('node_modules');
},
},
- plugins: [appTools(), moduleFederationPlugin()],
+ plugins: [appTools(), moduleFederationPlugin({ ssr: true })],
});
diff --git a/tests/integration/rsc-mf/host/module-federation.config.ts b/tests/integration/rsc-mf/host/module-federation.config.ts
index 8a830fd27cc6..50bb8a7ff218 100644
--- a/tests/integration/rsc-mf/host/module-federation.config.ts
+++ b/tests/integration/rsc-mf/host/module-federation.config.ts
@@ -2,72 +2,15 @@ import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
const REMOTE_PORT = process.env.RSC_MF_REMOTE_PORT || '3008';
-const LAYERS = {
- ssr: 'server-side-rendering',
- rsc: 'react-server-components',
-};
-
-const sharedByScope = () => [
- {
- react: {
- singleton: true,
- requiredVersion: false,
- shareScope: 'default',
- },
- 'react-dom': {
- singleton: true,
- requiredVersion: false,
- shareScope: 'default',
- },
- },
- {
- react: {
- import: 'react',
- shareKey: 'react',
- singleton: true,
- requiredVersion: false,
- shareScope: 'ssr',
- layer: LAYERS.ssr,
- issuerLayer: LAYERS.ssr,
- },
- 'react-dom': {
- import: 'react-dom',
- shareKey: 'react-dom',
- singleton: true,
- requiredVersion: false,
- shareScope: 'ssr',
- layer: LAYERS.ssr,
- issuerLayer: LAYERS.ssr,
- },
- },
- {
- react: {
- import: 'react',
- shareKey: 'react',
- singleton: true,
- requiredVersion: false,
- shareScope: 'rsc',
- layer: LAYERS.rsc,
- issuerLayer: LAYERS.rsc,
- },
- 'react-dom': {
- import: 'react-dom',
- shareKey: 'react-dom',
- singleton: true,
- requiredVersion: false,
- shareScope: 'rsc',
- layer: LAYERS.rsc,
- issuerLayer: LAYERS.rsc,
- },
- },
-];
-
export default createModuleFederationConfig({
name: 'rscHost',
remotes: {
rscRemote: `rscRemote@http://127.0.0.1:${REMOTE_PORT}/static/mf-manifest.json`,
},
- shared: sharedByScope(),
+ shared: {
+ react: { singleton: true },
+ 'react-dom': { singleton: true },
+ },
dts: false,
experiments: {
asyncStartup: true,
diff --git a/tests/integration/rsc-mf/host/src/App.module.less b/tests/integration/rsc-mf/host/src/server-component-root/App.module.less
similarity index 100%
rename from tests/integration/rsc-mf/host/src/App.module.less
rename to tests/integration/rsc-mf/host/src/server-component-root/App.module.less
diff --git a/tests/integration/rsc-mf/host/src/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
similarity index 96%
rename from tests/integration/rsc-mf/host/src/App.tsx
rename to tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 2c2135f233a0..a57dd02a4e0b 100644
--- a/tests/integration/rsc-mf/host/src/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -1,4 +1,3 @@
-'use server-entry';
import 'server-only';
import { Suspense } from 'react';
import { RemoteNestedMixed } from 'rscRemote/RemoteNestedMixed';
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index afcb3c432c9d..27c95bf3f3ad 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -6,9 +6,6 @@ const remotePort = process.env.RSC_MF_REMOTE_PORT || process.env.PORT || '3008';
export default defineConfig({
server: {
- ssr: {
- mode: 'stream',
- },
rsc: true,
},
output: {
@@ -27,5 +24,5 @@ export default defineConfig({
.add('node_modules');
},
},
- plugins: [appTools(), moduleFederationPlugin()],
+ plugins: [appTools(), moduleFederationPlugin({ ssr: true })],
});
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index c857e4ffcebf..f426d736b889 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -1,65 +1,5 @@
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
-const LAYERS = {
- ssr: 'server-side-rendering',
- rsc: 'react-server-components',
-};
-
-const sharedByScope = () => [
- {
- react: {
- singleton: true,
- requiredVersion: false,
- shareScope: 'default',
- },
- 'react-dom': {
- singleton: true,
- requiredVersion: false,
- shareScope: 'default',
- },
- },
- {
- react: {
- import: 'react',
- shareKey: 'react',
- singleton: true,
- requiredVersion: false,
- shareScope: 'ssr',
- layer: LAYERS.ssr,
- issuerLayer: LAYERS.ssr,
- },
- 'react-dom': {
- import: 'react-dom',
- shareKey: 'react-dom',
- singleton: true,
- requiredVersion: false,
- shareScope: 'ssr',
- layer: LAYERS.ssr,
- issuerLayer: LAYERS.ssr,
- },
- },
- {
- react: {
- import: 'react',
- shareKey: 'react',
- singleton: true,
- requiredVersion: false,
- shareScope: 'rsc',
- layer: LAYERS.rsc,
- issuerLayer: LAYERS.rsc,
- },
- 'react-dom': {
- import: 'react-dom',
- shareKey: 'react-dom',
- singleton: true,
- requiredVersion: false,
- shareScope: 'rsc',
- layer: LAYERS.rsc,
- issuerLayer: LAYERS.rsc,
- },
- },
-];
-
export default createModuleFederationConfig({
name: 'rscRemote',
manifest: {
@@ -74,7 +14,10 @@ export default createModuleFederationConfig({
'./actions': './src/components/actions.ts',
'./nestedActions': './src/components/nestedActions.ts',
},
- shared: sharedByScope(),
+ shared: {
+ react: { singleton: true },
+ 'react-dom': { singleton: true },
+ },
dts: false,
experiments: {
asyncStartup: true,
diff --git a/tests/integration/rsc-mf/remote/src/App.tsx b/tests/integration/rsc-mf/remote/src/App.tsx
index 3fe8fd8173cd..3a4dba7ffcc0 100644
--- a/tests/integration/rsc-mf/remote/src/App.tsx
+++ b/tests/integration/rsc-mf/remote/src/App.tsx
@@ -1,4 +1,3 @@
-'use server-entry';
import { RemoteNestedMixed } from './components/RemoteNestedMixed';
const App = () => {
diff --git a/tests/integration/rsc-mf/remote/src/components/serverOnly.ts b/tests/integration/rsc-mf/remote/src/components/serverOnly.ts
index 3891d5b4ded1..eeba7734368d 100644
--- a/tests/integration/rsc-mf/remote/src/components/serverOnly.ts
+++ b/tests/integration/rsc-mf/remote/src/components/serverOnly.ts
@@ -1,8 +1,5 @@
import 'server-only';
-import { readFileSync } from 'node:fs';
export function getServerOnlyInfo() {
- return typeof readFileSync === 'function'
- ? 'remote-server-only-ok'
- : 'remote-server-only-missing';
+ return 'remote-server-only-ok';
}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 3e3a9ef38c3f..5f7be3b8c44b 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -9,11 +9,15 @@ import {
launchOptions,
modernBuild,
modernServe,
+ sleep,
} from '../../../utils/modernTestUtils';
const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
+const HOST_RSC_URL = '/server-component-root';
+const RSC_RUNTIME_BLOCKER_PATTERN =
+ /Cannot find (render handler|server bundle) for RSC/;
type Mode = 'dev' | 'build';
@@ -49,32 +53,21 @@ function createHostEnv(remotePort: number) {
};
}
-async function waitForAppReady(port: number, maxRetries = 60) {
- for (let index = 0; index < maxRetries; index++) {
- try {
- const response = await fetch(`http://127.0.0.1:${port}`, {
- method: 'HEAD',
- signal: AbortSignal.timeout(2000),
- });
- if (response.ok || response.status < 500) {
- await new Promise(resolve => setTimeout(resolve, 1000));
- return;
- }
- } catch (error) {}
- await new Promise(resolve => setTimeout(resolve, 1000));
- }
-
- throw new Error(`App on port ${port} did not become ready`);
-}
-
async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
- const response = await fetch(`http://127.0.0.1:${hostPort}`);
+ const response = await fetch(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`);
const html = await response.text();
+ if (RSC_RUNTIME_BLOCKER_PATTERN.test(html)) {
+ return {
+ blocked: true,
+ html,
+ };
+ }
+
expect(html).toContain('Host RSC Module Federation');
expect(html).toContain('Remote Federated Tree');
expect(html).toContain('remote-server-only-ok');
- await page.goto(`http://127.0.0.1:${hostPort}`, {
+ await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
});
const hostRemoteServerOnly = await page.$eval(
@@ -82,13 +75,18 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostRemoteServerOnly).toBe('remote-server-only-ok');
+
+ return {
+ blocked: false,
+ html,
+ };
}
async function supportRemoteClientAndServerActions({
hostPort,
page,
}: TestContext) {
- await page.goto(`http://127.0.0.1:${hostPort}`, {
+ await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
});
await page.waitForSelector('.remote-client-local-increment');
@@ -142,6 +140,8 @@ function runTests({ mode }: TestConfig) {
let page: Page;
let browser: Browser;
const runtimeErrors: string[] = [];
+ let runtimeBlocked = false;
+ let runtimeBlockerHtml = '';
if (skipForLowerNodeVersion()) {
return;
@@ -157,10 +157,10 @@ function runTests({ mode }: TestConfig) {
if (mode === 'dev') {
remoteApp = await launchApp(remoteDir, remotePort, {}, remoteEnv);
- await waitForAppReady(remotePort);
+ await sleep(2000);
hostApp = await launchApp(hostDir, hostPort, {}, hostEnv);
- await waitForAppReady(hostPort);
+ await sleep(2000);
} else {
await modernBuild(remoteDir, [], { env: remoteEnv });
await modernBuild(hostDir, [], { env: hostEnv });
@@ -172,7 +172,7 @@ function runTests({ mode }: TestConfig) {
...remoteEnv,
},
});
- await waitForAppReady(remotePort);
+ await sleep(2000);
hostApp = await modernServe(hostDir, hostPort, {
env: {
@@ -181,7 +181,7 @@ function runTests({ mode }: TestConfig) {
...hostEnv,
},
});
- await waitForAppReady(hostPort);
+ await sleep(2000);
}
browser = await puppeteer.launch(launchOptions as any);
@@ -206,11 +206,24 @@ function runTests({ mode }: TestConfig) {
}
});
- it('should render remote RSC content in host app', () =>
- renderRemoteRscIntoHost({ hostPort, page }));
+ it('should render remote RSC content in host app', async () => {
+ const renderResult = await renderRemoteRscIntoHost({ hostPort, page });
+ runtimeBlocked = renderResult.blocked;
+ runtimeBlockerHtml = renderResult.html;
+
+ if (runtimeBlocked) {
+ expect(runtimeBlockerHtml).toMatch(RSC_RUNTIME_BLOCKER_PATTERN);
+ }
+ });
- it('should support remote use client and server actions', () =>
- supportRemoteClientAndServerActions({ hostPort, page }));
+ it('should support remote use client and server actions', async () => {
+ if (runtimeBlocked) {
+ expect(runtimeBlockerHtml).toMatch(RSC_RUNTIME_BLOCKER_PATTERN);
+ return;
+ }
+
+ await supportRemoteClientAndServerActions({ hostPort, page });
+ });
if (mode === 'build') {
it('should have no browser runtime errors', () => {
From 6e5f65ce6238dcdb0d374e9a46f7ed1fb1c18a19 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Thu, 12 Feb 2026 03:57:20 +0000
Subject: [PATCH 003/324] test(rsc-mf): disable async entry for rsc federation
fixtures
---
tests/integration/rsc-mf/host/modern.config.ts | 4 ++++
tests/integration/rsc-mf/remote/modern.config.ts | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index e378cfb6c527..70311f4ca58b 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -6,6 +6,10 @@ export default defineConfig({
server: {
rsc: true,
},
+ // Keep RSC server entries synchronous for MF+RSC handlers.
+ source: {
+ enableAsyncEntry: false,
+ },
output: {
polyfill: 'off',
disableTsChecker: true,
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index 27c95bf3f3ad..edd0d79774c2 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -8,6 +8,10 @@ export default defineConfig({
server: {
rsc: true,
},
+ // Keep RSC server entries synchronous for MF+RSC handlers.
+ source: {
+ enableAsyncEntry: false,
+ },
output: {
polyfill: 'off',
disableTsChecker: true,
From 9ee61767745393f05be1f94d137c1135b82914fc Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Thu, 12 Feb 2026 04:25:30 +0000
Subject: [PATCH 004/324] test(rsc-mf): enforce async-node target for server
bundles
---
tests/integration/rsc-mf/host/modern.config.ts | 6 ++++++
tests/integration/rsc-mf/remote/modern.config.ts | 6 ++++++
2 files changed, 12 insertions(+)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index 70311f4ca58b..1ae1399165c1 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -19,6 +19,12 @@ export default defineConfig({
},
tools: {
bundlerChain(chain) {
+ const target = chain.get('target');
+ const targets = Array.isArray(target) ? target : [target];
+ if (targets.some(item => String(item).includes('node'))) {
+ chain.target('async-node');
+ }
+
chain.resolve.modules
.clear()
.add(path.resolve(__dirname, 'node_modules'))
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index edd0d79774c2..9aeec9a165a6 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -22,6 +22,12 @@ export default defineConfig({
},
tools: {
bundlerChain(chain) {
+ const target = chain.get('target');
+ const targets = Array.isArray(target) ? target : [target];
+ if (targets.some(item => String(item).includes('node'))) {
+ chain.target('async-node');
+ }
+
chain.resolve.modules
.clear()
.add(path.resolve(__dirname, 'node_modules'))
From 125415a572b057b6fb402ff3efb75ef63174033a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Thu, 12 Feb 2026 08:24:42 +0000
Subject: [PATCH 005/324] test(rsc-mf): broaden rsc federation exposure matrix
---
.../host/src/server-component-root/App.tsx | 19 +++++
.../HostRemoteActionRunner.tsx | 39 +++++++++
.../rsc-mf/remote/module-federation.config.ts | 6 ++
.../src/components/AsyncRemoteServerInfo.tsx | 5 ++
.../src/components/RemoteClientBadge.tsx | 24 ++++++
.../src/components/RemoteServerDefault.tsx | 10 +++
.../remote/src/components/defaultAction.ts | 5 ++
.../remote/src/components/remoteMeta.ts | 12 +++
.../src/components/serverOnlyDefault.ts | 5 ++
tests/integration/rsc-mf/tests/index.test.ts | 85 ++++++++++++-------
10 files changed, 177 insertions(+), 33 deletions(-)
create mode 100644 tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/AsyncRemoteServerInfo.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/RemoteServerDefault.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/components/defaultAction.ts
create mode 100644 tests/integration/rsc-mf/remote/src/components/remoteMeta.ts
create mode 100644 tests/integration/rsc-mf/remote/src/components/serverOnlyDefault.ts
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index a57dd02a4e0b..e993df8966c0 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -1,19 +1,38 @@
import 'server-only';
import { Suspense } from 'react';
+import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
+import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteNestedMixed } from 'rscRemote/RemoteNestedMixed';
+import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
+import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
+import getServerOnlyDefaultInfo from 'rscRemote/remoteServerOnlyDefault';
import styles from './App.module.less';
+import HostRemoteActionRunner from './HostRemoteActionRunner';
const App = () => {
const remoteServerOnlyInfo = getServerOnlyInfo();
+ const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
+ const remoteMetaLabel = getRemoteMetaLabel();
return (
Host RSC Module Federation
{remoteServerOnlyInfo}
+
+ {remoteServerOnlyDefaultInfo}
+
+
{remoteMeta.kind}
+
{remoteMetaLabel}
+
Loading Remote Async Server Info... }>
+
+
+
Loading Remote RSC...}>
+
+
);
};
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
new file mode 100644
index 000000000000..c28bc3d9642f
--- /dev/null
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -0,0 +1,39 @@
+'use client';
+
+import { useState } from 'react';
+import { remoteActionEcho } from 'rscRemote/actions';
+import defaultRemoteAction from 'rscRemote/defaultAction';
+
+export default function HostRemoteActionRunner() {
+ const [defaultResult, setDefaultResult] = useState('');
+ const [echoResult, setEchoResult] = useState('');
+ const [isPending, setIsPending] = useState(false);
+
+ const runActions = async () => {
+ setIsPending(true);
+ try {
+ const [defaultValue, echoValue] = await Promise.all([
+ defaultRemoteAction('from-host-client'),
+ remoteActionEcho('from-host-client'),
+ ]);
+ setDefaultResult(defaultValue);
+ setEchoResult(echoValue);
+ } finally {
+ setIsPending(false);
+ }
+ };
+
+ return (
+
+
+
{defaultResult}
+
{echoResult}
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index f426d736b889..dd2276df4f56 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -8,11 +8,17 @@ export default createModuleFederationConfig({
filename: 'static/remoteEntry.js',
exposes: {
'./RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
+ './RemoteClientBadge': './src/components/RemoteClientBadge.tsx',
'./RemoteServerCard': './src/components/RemoteServerCard.tsx',
+ './RemoteServerDefault': './src/components/RemoteServerDefault.tsx',
+ './AsyncRemoteServerInfo': './src/components/AsyncRemoteServerInfo.tsx',
'./RemoteNestedMixed': './src/components/RemoteNestedMixed.tsx',
'./remoteServerOnly': './src/components/serverOnly.ts',
+ './remoteServerOnlyDefault': './src/components/serverOnlyDefault.ts',
+ './remoteMeta': './src/components/remoteMeta.ts',
'./actions': './src/components/actions.ts',
'./nestedActions': './src/components/nestedActions.ts',
+ './defaultAction': './src/components/defaultAction.ts',
},
shared: {
react: { singleton: true },
diff --git a/tests/integration/rsc-mf/remote/src/components/AsyncRemoteServerInfo.tsx b/tests/integration/rsc-mf/remote/src/components/AsyncRemoteServerInfo.tsx
new file mode 100644
index 000000000000..ce90b480f85b
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/AsyncRemoteServerInfo.tsx
@@ -0,0 +1,5 @@
+export async function AsyncRemoteServerInfo() {
+ const value = await Promise.resolve('remote-async-server-info-ok');
+
+ return {value}
;
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
new file mode 100644
index 000000000000..f46bcb0d5f33
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
@@ -0,0 +1,24 @@
+'use client';
+
+import 'client-only';
+import { useState } from 'react';
+
+export default function RemoteClientBadge({
+ initialLabel,
+}: {
+ initialLabel: string;
+}) {
+ const [label, setLabel] = useState(initialLabel);
+
+ return (
+
+
{label}
+
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteServerDefault.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteServerDefault.tsx
new file mode 100644
index 000000000000..6644e0014755
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteServerDefault.tsx
@@ -0,0 +1,10 @@
+import { getServerOnlyInfo } from './serverOnly';
+
+export default function RemoteServerDefault({ label }: { label: string }) {
+ return (
+
+ {label}
+ {getServerOnlyInfo()}
+
+ );
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/defaultAction.ts b/tests/integration/rsc-mf/remote/src/components/defaultAction.ts
new file mode 100644
index 000000000000..09f2458a768d
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/defaultAction.ts
@@ -0,0 +1,5 @@
+'use server';
+
+export default async function defaultRemoteAction(value: string) {
+ return `default-action:${value}`;
+}
diff --git a/tests/integration/rsc-mf/remote/src/components/remoteMeta.ts b/tests/integration/rsc-mf/remote/src/components/remoteMeta.ts
new file mode 100644
index 000000000000..703bec9d0b2e
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/remoteMeta.ts
@@ -0,0 +1,12 @@
+export const remoteFeatureFlags = ['rsc', 'mf', 'actions'] as const;
+
+export function getRemoteMetaLabel() {
+ return remoteFeatureFlags.join('|');
+}
+
+const remoteMeta = {
+ kind: 'remote-meta-default',
+ version: 'v1',
+};
+
+export default remoteMeta;
diff --git a/tests/integration/rsc-mf/remote/src/components/serverOnlyDefault.ts b/tests/integration/rsc-mf/remote/src/components/serverOnlyDefault.ts
new file mode 100644
index 000000000000..a3ec2cbae752
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/serverOnlyDefault.ts
@@ -0,0 +1,5 @@
+import 'server-only';
+
+export default function getServerOnlyDefaultInfo() {
+ return 'remote-server-only-default-ok';
+}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 5f7be3b8c44b..e78563e47ab7 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -16,8 +16,6 @@ const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
const HOST_RSC_URL = '/server-component-root';
-const RSC_RUNTIME_BLOCKER_PATTERN =
- /Cannot find (render handler|server bundle) for RSC/;
type Mode = 'dev' | 'build';
@@ -56,16 +54,14 @@ function createHostEnv(remotePort: number) {
async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const response = await fetch(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`);
const html = await response.text();
- if (RSC_RUNTIME_BLOCKER_PATTERN.test(html)) {
- return {
- blocked: true,
- html,
- };
- }
-
expect(html).toContain('Host RSC Module Federation');
expect(html).toContain('Remote Federated Tree');
expect(html).toContain('remote-server-only-ok');
+ expect(html).toContain('remote-server-only-default-ok');
+ expect(html).toContain('remote-meta-default');
+ expect(html).toContain('rsc|mf|actions');
+ expect(html).toContain('remote-async-server-info-ok');
+ expect(html).toContain('Remote Default Server Card');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -75,11 +71,24 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostRemoteServerOnly).toBe('remote-server-only-ok');
-
- return {
- blocked: false,
- html,
- };
+ const hostRemoteServerOnlyDefault = await page.$eval(
+ '.host-remote-server-only-default',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteServerOnlyDefault).toBe('remote-server-only-default-ok');
+ const hostRemoteMetaKind = await page.$eval('.host-remote-meta-kind', el =>
+ el.textContent?.trim(),
+ );
+ expect(hostRemoteMetaKind).toBe('remote-meta-default');
+ const hostRemoteMetaLabel = await page.$eval('.host-remote-meta-label', el =>
+ el.textContent?.trim(),
+ );
+ expect(hostRemoteMetaLabel).toBe('rsc|mf|actions');
+ const hostRemoteAsyncServerInfo = await page.$eval(
+ '.remote-async-server-info',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteAsyncServerInfo).toBe('remote-async-server-info-ok');
}
async function supportRemoteClientAndServerActions({
@@ -129,6 +138,31 @@ async function supportRemoteClientAndServerActions({
remoteAction?.textContent?.trim() === 'remote-action:from-client'
);
});
+
+ let badgeValue = await page.$eval('.remote-client-badge-value', el =>
+ el.textContent?.trim(),
+ );
+ expect(badgeValue).toBe('remote-client-badge-initial');
+ await page.click('.remote-client-badge-toggle');
+ badgeValue = await page.$eval('.remote-client-badge-value', el =>
+ el.textContent?.trim(),
+ );
+ expect(badgeValue).toBe('remote-client-badge-toggled');
+
+ await page.click('.host-remote-run-actions');
+ await page.waitForFunction(() => {
+ const defaultActionResult = document.querySelector(
+ '.host-remote-default-action-result',
+ );
+ const echoActionResult = document.querySelector(
+ '.host-remote-echo-action-result',
+ );
+ return (
+ defaultActionResult?.textContent?.trim() ===
+ 'default-action:from-host-client' &&
+ echoActionResult?.textContent?.trim() === 'remote-action:from-host-client'
+ );
+ });
}
function runTests({ mode }: TestConfig) {
@@ -140,8 +174,6 @@ function runTests({ mode }: TestConfig) {
let page: Page;
let browser: Browser;
const runtimeErrors: string[] = [];
- let runtimeBlocked = false;
- let runtimeBlockerHtml = '';
if (skipForLowerNodeVersion()) {
return;
@@ -206,24 +238,11 @@ function runTests({ mode }: TestConfig) {
}
});
- it('should render remote RSC content in host app', async () => {
- const renderResult = await renderRemoteRscIntoHost({ hostPort, page });
- runtimeBlocked = renderResult.blocked;
- runtimeBlockerHtml = renderResult.html;
-
- if (runtimeBlocked) {
- expect(runtimeBlockerHtml).toMatch(RSC_RUNTIME_BLOCKER_PATTERN);
- }
- });
+ it('should render remote RSC content in host app', () =>
+ renderRemoteRscIntoHost({ hostPort, page }));
- it('should support remote use client and server actions', async () => {
- if (runtimeBlocked) {
- expect(runtimeBlockerHtml).toMatch(RSC_RUNTIME_BLOCKER_PATTERN);
- return;
- }
-
- await supportRemoteClientAndServerActions({ hostPort, page });
- });
+ it('should support remote use client and server actions', () =>
+ supportRemoteClientAndServerActions({ hostPort, page }));
if (mode === 'build') {
it('should have no browser runtime errors', () => {
From 22fa22482647ccc764d357f450f5933761656226 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 04:21:37 +0000
Subject: [PATCH 006/324] chore(tests): use modern-js-v3 pkg.pr.new preview
---
pnpm-lock.yaml | 739 ++++++++++++++----
.../i18n/mf/mf-app-provider/package.json | 2 +-
.../mf/mf-component-provider/package.json | 2 +-
.../i18n/mf/mf-consumer/package.json | 2 +-
tests/integration/rsc-mf/host/package.json | 2 +-
tests/integration/rsc-mf/remote/package.json | 2 +-
6 files changed, 611 insertions(+), 138 deletions(-)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cbaeb4fa9755..b3398b1fee76 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3030,8 +3030,8 @@ importers:
specifier: workspace:*
version: link:../../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
- specifier: 2.0.0
- version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
i18next:
specifier: 25.7.4
version: 25.7.4(typescript@5.9.3)
@@ -3061,8 +3061,8 @@ importers:
specifier: workspace:*
version: link:../../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
- specifier: 2.0.0
- version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
i18next:
specifier: 25.7.4
version: 25.7.4(typescript@5.9.3)
@@ -3092,8 +3092,8 @@ importers:
specifier: workspace:*
version: link:../../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
- specifier: 2.0.0
- version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
specifier: 2.0.0
version: 2.0.0
@@ -3478,7 +3478,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3521,7 +3521,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3559,8 +3559,8 @@ importers:
specifier: workspace:*
version: link:../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
- specifier: 2.0.0
- version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
specifier: 2.0.0
version: 2.0.0
@@ -3575,7 +3575,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3614,8 +3614,8 @@ importers:
specifier: workspace:*
version: link:../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
- specifier: 2.0.0
- version: 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
specifier: 2.0.0
version: 2.0.0
@@ -3630,7 +3630,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3679,7 +3679,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3725,7 +3725,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
server-only:
specifier: ^0.0.1
version: 0.0.1
@@ -6153,11 +6153,16 @@ packages:
'@modern-js/utils@2.70.4':
resolution: {integrity: sha512-LQrwyGlFhsH2BmZxStF0TPeStm6aumf4N1J+ZyObLw5URrN4o8vCyeyqrPVciICeoTqhHg2GIArJWB5PXRcUig==}
- '@module-federation/bridge-react-webpack-plugin@2.0.0':
- resolution: {integrity: sha512-AVT/rZK6RHva6ZTYfsyQ8oP4xYNTws3OzqKW/YxWaLXwQ3oG9ZbF7fKl4jIKoMKuuy2L9MGVXS4CYPZy0s8fXg==}
+ '@module-federation/bridge-react-webpack-plugin@2.0.1':
+ resolution: {integrity: sha512-D7LMW5EMAJShOMR1aZDAJ6s+MdsYDHaQyJADLQ3LaY0sne/BkVqkPikUwcO1IwOwKbXjYsDlQVOEvk9wZVRFhA==}
- '@module-federation/bridge-react@2.0.0':
- resolution: {integrity: sha512-TVkIxvlRk5vo4CYuId3Kj2JcyjkhiMq2LwKDcZsXC+8Ohwt8olfKJ6y40rCViXwGUSns1TRBtzPD6EikMXlYZg==}
+ '@module-federation/bridge-react-webpack-plugin@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
+ '@module-federation/bridge-react@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
peerDependencies:
react: '>=16.9.0'
react-dom: '>=16.9.0'
@@ -6169,16 +6174,23 @@ packages:
react-router-dom:
optional: true
- '@module-federation/bridge-shared@2.0.0':
- resolution: {integrity: sha512-kid2tyGOjX02da/kjjHtkw035M7NHiD8UGynBfZBi9mznAWUUReT0n8EHyvTIdBpj7S4AQKHpwppPCrg7Rv3ZA==}
+ '@module-federation/bridge-shared@https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
- '@module-federation/cli@2.0.0':
- resolution: {integrity: sha512-IWGWbdgoeNcuA5jzqPr6pLTN1hovMQh9A1lgJp5fAvKfICfFXKq7K8nwMAQrWD6iEKApIenI0madk1Dg2PU3pw==}
+ '@module-federation/cli@2.0.1':
+ resolution: {integrity: sha512-2SL5Y8iODNX10y9T3CBLhHjSXo4afnA1BK82m4sNfZebuVO+o34bxewqwod9xfWq9xhTZmOSFZ+n+lgTKRv+CQ==}
engines: {node: '>=16.0.0'}
hasBin: true
- '@module-federation/data-prefetch@2.0.0':
- resolution: {integrity: sha512-KPyZoqNrb5WgFY2owYnMaO2Mg2DYD6KXLVI7GPguj7Z/4pPKEC+SUjWU2FuSfTeyE6ZIi0iFGdwerxzlQ6nfmw==}
+ '@module-federation/cli@https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+ engines: {node: '>=16.0.0'}
+ hasBin: true
+
+ '@module-federation/data-prefetch@2.0.1':
+ resolution: {integrity: sha512-Kq0P1OABGt6QAvs6TaE/zY9Ut9Y/oJFrzoSF3eWaCYbUAr2KD2SpTyMsPz4ssBzjeKXTgimugh6tHHd6mpCBIQ==}
peerDependencies:
react: '>=16.9.0'
react-dom: '>=16.9.0'
@@ -6188,8 +6200,30 @@ packages:
react-dom:
optional: true
- '@module-federation/dts-plugin@2.0.0':
- resolution: {integrity: sha512-YyYMgLNARKdf3FLihnIzzUTgafHrqzR9YnKPmrfuCm2Jit+USqFT4QO58hcb0F5KSEyjB2ARPz9RM4XAVZhzMg==}
+ '@module-federation/data-prefetch@https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
+ '@module-federation/dts-plugin@2.0.1':
+ resolution: {integrity: sha512-PLneTsf1fQS5/RTBedtLAAmCPRdMfIlhfJkOa8QH3WDJaQsqm8Wb3r2cTUBf2aNj/bP3aH/y6Hs9JFB/4x0l5g==}
+ peerDependencies:
+ typescript: ^4.9.0 || ^5.0.0
+ vue-tsc: '>=1.0.24'
+ peerDependenciesMeta:
+ vue-tsc:
+ optional: true
+
+ '@module-federation/dts-plugin@https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
peerDependencies:
typescript: ^4.9.0 || ^5.0.0
vue-tsc: '>=1.0.24'
@@ -6197,8 +6231,25 @@ packages:
vue-tsc:
optional: true
- '@module-federation/enhanced@2.0.0':
- resolution: {integrity: sha512-xeVrGvypYMvN8gJulbro3j1t8+aS1f9xjj4quwAAqgJF0Nz8bt7sXUYJyjUHPmC2UZsShZ0GnPHJNtI8/2GYjA==}
+ '@module-federation/enhanced@2.0.1':
+ resolution: {integrity: sha512-EZIARQ/8ScoTP6PV8+E4SsmMYWK4ErrikZJ0G/FX8wvK8mCtdoKatFtvDN9++P6Nl78kN9zHYgAV4AHKdBVjfQ==}
+ version: 2.0.1
+ hasBin: true
+ peerDependencies:
+ typescript: ^4.9.0 || ^5.0.0
+ vue-tsc: '>=1.0.24'
+ webpack: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ vue-tsc:
+ optional: true
+ webpack:
+ optional: true
+
+ '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
hasBin: true
peerDependencies:
typescript: ^4.9.0 || ^5.0.0
@@ -6218,19 +6269,42 @@ packages:
'@module-federation/error-codes@2.0.0':
resolution: {integrity: sha512-9oE+hXuPv2zej7AxJ5hOgeRqlPs98meooV2FiutTfftLAyy2N6+Kwmmz5NR9d9t91weJj8N0cSHFoyenNHKTVg==}
- '@module-federation/inject-external-runtime-core-plugin@2.0.0':
- resolution: {integrity: sha512-aZ6f4UU7KM5zBnHf3xsb2guqsfaEd6IlmuldbpED3JPk4ITwZk0DbvxRMr4prde7cfj8RH0nKMz2kmMncp+lIQ==}
+ '@module-federation/error-codes@2.0.1':
+ resolution: {integrity: sha512-2bJF/ft+qL9L6Zvq2t/G9/f/0wFL73cM8/NJ04uyYz9BjIgvx28K5qu8/6+IwgEEKATG7vOhBBVj6wH3S+5ASA==}
+
+ '@module-federation/error-codes@https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
+ '@module-federation/inject-external-runtime-core-plugin@2.0.1':
+ resolution: {integrity: sha512-oAA7G+4GCHM+WRYfscR/x4GwCyM9CEqfdD9/x2L6y8mtLWK9anRLKTocsI759AvzXsbT1m3EQ5ki1O6wlwDu3g==}
+ version: 2.0.1
peerDependencies:
- '@module-federation/runtime-tools': 2.0.0
+ '@module-federation/runtime-tools': 2.0.1
+
+ '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+ peerDependencies:
+ '@module-federation/runtime-tools': 2.0.1
+
+ '@module-federation/managers@2.0.1':
+ resolution: {integrity: sha512-KR01lSlcYRQ9C6hW2a8CQQtAE0LvfTLgtV/6ZNUTagw8sRfeDln+ggrZsYilKu9zl0i8RPDgpv/kS60o4lcxCQ==}
- '@module-federation/managers@2.0.0':
- resolution: {integrity: sha512-ZmkRIujH+T3xvkmy04TNvviFH8xFOrNeKCLb4tlH4ifU/kLfjTu+PYO/KAEIsgtmrDnd52zTf22dg3ok85OAHA==}
+ '@module-federation/managers@https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
- '@module-federation/manifest@2.0.0':
- resolution: {integrity: sha512-AXwYyGiDJdfP9MteKyIdJrLwG5tp4qKaq0uOPiWHilYN3/21G0DM7f30HgJqgx3WSTFSh7hcq0a3V3EZHH/9TA==}
+ '@module-federation/manifest@2.0.1':
+ resolution: {integrity: sha512-p8nYGjHWp17MsYdW/Vv0ogBDiTTsI1PHWPQbvVIqLQXDqwiesaRSRR1zziECXQoEL8lV5Bs+uSkcaJGhea9P+A==}
- '@module-federation/modern-js-v3@2.0.0':
- resolution: {integrity: sha512-SKoKwh1rlgG+LXyV1eh2ELE05UhFVkhRXNIjwrSFjg9xVBih4oI10yBeOdrzCw8vdY/+BvXWxka88Av6tzh49Q==}
+ '@module-federation/manifest@https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
+ '@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437}
+ version: 2.0.1
peerDependencies:
react: '>=17'
react-dom: '>=17'
@@ -6248,16 +6322,18 @@ packages:
vue-tsc:
optional: true
- '@module-federation/node@2.7.31':
- resolution: {integrity: sha512-NSa0PFDKDLxmtfmCVHW9RhtfD9mcNOrp1d+cjVEoxb5x8dDI4jQTi1o3nsa9ettxs3bVtWhAUEQUNQBQ6ZA+Hw==}
+ '@module-federation/node@2.7.32':
+ resolution: {integrity: sha512-hUj5v2GGwpNzl2gaJS4AyzCYRzJBhN8875A+ucKF9tq3jaQb5zpy3izYMISqqbN2q9a7jz3nEUgwAh3pjri+rQ==}
+ version: 2.7.32
peerDependencies:
webpack: ^5.40.0
peerDependenciesMeta:
webpack:
optional: true
- '@module-federation/rsbuild-plugin@2.0.0':
- resolution: {integrity: sha512-kbYX9ti2C/m734Na3ICy+xBopqL6O3sGK7Vx7N+WA/PkEGc5J0WEPwVwXtnf4WRj9ic9OV5+w2i6y1tG8ONt1g==}
+ '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
engines: {node: '>=16.0.0'}
peerDependencies:
'@rsbuild/core': 2.0.0-beta.2
@@ -6265,8 +6341,22 @@ packages:
'@rsbuild/core':
optional: true
- '@module-federation/rspack@2.0.0':
- resolution: {integrity: sha512-1kziarKrPRM+rJax/AaMEZTwu7ORGed2xSxfdoP9GEbAFEGyNliadvw4kB6PqAfLad3PI4lQMX2vGMLI1KoyVQ==}
+ '@module-federation/rspack@2.0.1':
+ resolution: {integrity: sha512-SAlNE8iclFmzrKtx3/C2GivXYx6nPzx4MgQV01QG/a4LpnLbwlxzdZu3rqQ2swp4NNWT/t/GT7Y+7gfhyVa7mg==}
+ version: 2.0.1
+ peerDependencies:
+ '@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0
+ typescript: ^4.9.0 || ^5.0.0
+ vue-tsc: '>=1.0.24'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ vue-tsc:
+ optional: true
+
+ '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
peerDependencies:
'@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0
typescript: ^4.9.0 || ^5.0.0
@@ -6283,11 +6373,22 @@ packages:
'@module-federation/runtime-core@2.0.0':
resolution: {integrity: sha512-UhIGUs7Mg+TwMI2lgaLnj4UehpoyXbR7HDb2+vLikgBulPmFtodeWfsxCgENEwKsIY1vS0lOun15lNOn1vo3Xg==}
+ '@module-federation/runtime-core@2.0.1':
+ resolution: {integrity: sha512-gOuCPSHoQGUGwlxfSTMInFX+QvLxdEWegGGMiLdU5vqbXuva4E9M+kXBBO7/0MkcBPMmVs0wOJGm0XOLeV2f1Q==}
+
+ '@module-federation/runtime-core@https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
'@module-federation/runtime-tools@0.22.0':
resolution: {integrity: sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==}
- '@module-federation/runtime-tools@2.0.0':
- resolution: {integrity: sha512-eMDQN4hYpwvUnCNMjfQdtPVzYaO2DdauemHVc4HnyibgqijRzBwJh9bI2ph4R1xfYEm18+QmTrfXrRlaK2Xizw==}
+ '@module-federation/runtime-tools@2.0.1':
+ resolution: {integrity: sha512-AStdwBtsGB3jIfDg9oP+KyVPsimdaeHsP855gqCxDp1hi2+GKjlZWZx9ThkS8NytVSXSUysxqoUL1ivDoKgcCQ==}
+
+ '@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
'@module-federation/runtime@0.22.0':
resolution: {integrity: sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==}
@@ -6295,20 +6396,42 @@ packages:
'@module-federation/runtime@2.0.0':
resolution: {integrity: sha512-vPxQrmQNq3Z1T+1fkHEvFwTdJq9wuCLvdp/lpu9k2Oy7QP/Pj6QoQ/S7J5MCIAoRwj8Wj3z3ma21/DyHwLGvzA==}
+ '@module-federation/runtime@2.0.1':
+ resolution: {integrity: sha512-UQ72P5Oo40dS6vdhHetwTtIsbGciEr+bjoYvDgh1WLPfFlTYd8zo9cLfqaf3juuPfV3cMVARAVPmh16lQYpUGA==}
+
+ '@module-federation/runtime@https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
'@module-federation/sdk@0.22.0':
resolution: {integrity: sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==}
'@module-federation/sdk@2.0.0':
resolution: {integrity: sha512-JYd1wTulsaoLT7HTk2oXL5y5797Z+H4mzxuUEKnSJo7R34RZSqehsqPSND7n0HT/1nf7uyn0Rb4qBfR3BVvdHQ==}
- '@module-federation/third-party-dts-extractor@2.0.0':
- resolution: {integrity: sha512-B99+Wkbd2xIodVTjNCeFtFC89Uh2/AtYkSESlz4+6Cec42wyqrGxyfYm4qRY0LhJI+YmZXLk/RTm85m15eBKKg==}
+ '@module-federation/sdk@2.0.1':
+ resolution: {integrity: sha512-32PwudojGjog51cwpTali7D6ud82oVgsyvOx9JjAzhvXBX96YI4mRsursuWcthDxmigJP9ZvUTXDuRUEDh1OQA==}
+
+ '@module-federation/sdk@https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
+
+ '@module-federation/third-party-dts-extractor@2.0.1':
+ resolution: {integrity: sha512-neKSr6FNUeGRh+YR57l/QZUzPytJXuJx+babF7j5iGJG3FP+kfizr6QD0hgVis5KEoXMVbQ8yyvG0slERizeyw==}
+
+ '@module-federation/third-party-dts-extractor@https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
'@module-federation/webpack-bundler-runtime@0.22.0':
resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==}
- '@module-federation/webpack-bundler-runtime@2.0.0':
- resolution: {integrity: sha512-XxiFR/A1G1fa9hTyylWNbs6yEU2hC7FqHAArFptD4U9qp/xyoLgqbK4M8LwltOAyAM8hRofcMdSyiRKVlWqAfQ==}
+ '@module-federation/webpack-bundler-runtime@2.0.1':
+ resolution: {integrity: sha512-u1NId3SF4lHDTmD2CHFEszulmXmIq1TGw9JYvnLx5rKJL7xt3aNxcb1GvkaYbRNVBXhSMjJ75E5LsQlZzyBx9A==}
+
+ '@module-federation/webpack-bundler-runtime@https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
+ resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c}
+ version: 2.0.1
'@mswjs/interceptors@0.39.8':
resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==}
@@ -16782,16 +16905,22 @@ snapshots:
lodash: 4.17.23
rslog: 1.3.2
- '@module-federation/bridge-react-webpack-plugin@2.0.0':
+ '@module-federation/bridge-react-webpack-plugin@2.0.1':
dependencies:
- '@module-federation/sdk': 2.0.0
+ '@module-federation/sdk': 2.0.1
'@types/semver': 7.5.8
semver: 7.6.3
- '@module-federation/bridge-react@2.0.0(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)':
+ '@module-federation/bridge-react-webpack-plugin@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
dependencies:
- '@module-federation/bridge-shared': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@types/semver': 7.5.8
+ semver: 7.6.3
+
+ '@module-federation/bridge-react@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)':
+ dependencies:
+ '@module-federation/bridge-shared': https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
lru-cache: 10.4.3
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -16800,12 +16929,12 @@ snapshots:
react-router: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-router-dom: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/bridge-shared@2.0.0': {}
+ '@module-federation/bridge-shared@https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c': {}
- '@module-federation/cli@2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ '@module-federation/cli@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
- '@module-federation/dts-plugin': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/sdk': 2.0.0
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/sdk': 2.0.1
chalk: 3.0.0
commander: 11.1.0
jiti: 2.4.2
@@ -16817,21 +16946,45 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/data-prefetch@2.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ '@module-federation/cli@https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
- '@module-federation/runtime': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ chalk: 3.0.0
+ commander: 11.1.0
+ jiti: 2.4.2
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/data-prefetch@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
+ dependencies:
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/sdk': 2.0.1
fs-extra: 9.1.0
optionalDependencies:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- '@module-federation/dts-plugin@2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ '@module-federation/data-prefetch@https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
- '@module-federation/error-codes': 2.0.0
- '@module-federation/managers': 2.0.0
- '@module-federation/sdk': 2.0.0
- '@module-federation/third-party-dts-extractor': 2.0.0
+ '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ fs-extra: 9.1.0
+ optionalDependencies:
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+
+ '@module-federation/dts-plugin@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/managers': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ '@module-federation/third-party-dts-extractor': 2.0.1
adm-zip: 0.5.16
ansi-colors: 4.1.3
axios: 1.13.5(debug@4.4.3)
@@ -16851,19 +17004,127 @@ snapshots:
- supports-color
- utf-8-validate
- '@module-federation/enhanced@2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@module-federation/dts-plugin@https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
- '@module-federation/bridge-react-webpack-plugin': 2.0.0
- '@module-federation/cli': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/data-prefetch': 2.0.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/dts-plugin': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/error-codes': 2.0.0
- '@module-federation/inject-external-runtime-core-plugin': 2.0.0(@module-federation/runtime-tools@2.0.0)
- '@module-federation/managers': 2.0.0
- '@module-federation/manifest': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/rspack': 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/third-party-dts-extractor': https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c
+ adm-zip: 0.5.16
+ ansi-colors: 4.1.3
+ axios: 1.13.5(debug@4.4.3)
+ chalk: 3.0.0
+ fs-extra: 9.1.0
+ isomorphic-ws: 5.0.0(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))
+ lodash.clonedeepwith: 4.5.0
+ log4js: 6.9.1
+ node-schedule: 2.1.1
+ rambda: 9.4.2
+ typescript: 5.9.3
+ ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/enhanced@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.0.1
+ '@module-federation/cli': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/data-prefetch': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@2.0.1)
+ '@module-federation/managers': 2.0.1
+ '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/rspack': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ btoa: 1.2.1
+ schema-utils: 4.3.3
+ upath: 2.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - react
+ - react-dom
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/enhanced@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.0.1
+ '@module-federation/cli': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/data-prefetch': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
+ '@module-federation/managers': 2.0.1
+ '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/rspack': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ btoa: 1.2.1
+ schema-utils: 4.3.3
+ upath: 2.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - react
+ - react-dom
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/data-prefetch': https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/rspack': https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ btoa: 1.2.1
+ schema-utils: 4.3.3
+ upath: 2.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - react
+ - react-dom
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/data-prefetch': https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/rspack': https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
btoa: 1.2.1
schema-utils: 4.3.3
upath: 2.0.1
@@ -16883,21 +17144,43 @@ snapshots:
'@module-federation/error-codes@2.0.0': {}
- '@module-federation/inject-external-runtime-core-plugin@2.0.0(@module-federation/runtime-tools@2.0.0)':
+ '@module-federation/error-codes@2.0.1': {}
+
+ '@module-federation/error-codes@https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c': {}
+
+ '@module-federation/inject-external-runtime-core-plugin@2.0.1(@module-federation/runtime-tools@2.0.1)':
dependencies:
- '@module-federation/runtime-tools': 2.0.0
+ '@module-federation/runtime-tools': 2.0.1
- '@module-federation/managers@2.0.0':
+ '@module-federation/inject-external-runtime-core-plugin@2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)':
dependencies:
- '@module-federation/sdk': 2.0.0
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+
+ '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)':
+ dependencies:
+ '@module-federation/runtime-tools': 2.0.1
+
+ '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)':
+ dependencies:
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+
+ '@module-federation/managers@2.0.1':
+ dependencies:
+ '@module-federation/sdk': 2.0.1
find-pkg: 2.0.0
fs-extra: 9.1.0
- '@module-federation/manifest@2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ '@module-federation/managers@https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c':
dependencies:
- '@module-federation/dts-plugin': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/managers': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ find-pkg: 2.0.0
+ fs-extra: 9.1.0
+
+ '@module-federation/manifest@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/managers': 2.0.1
+ '@module-federation/sdk': 2.0.1
chalk: 3.0.0
find-pkg: 2.0.0
transitivePeerDependencies:
@@ -16908,15 +17191,30 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/modern-js-v3@2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@module-federation/manifest@https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
- '@module-federation/bridge-react': 2.0.0(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
- '@module-federation/cli': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/enhanced': 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/node': 2.7.31(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/rsbuild-plugin': 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/runtime': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ chalk: 3.0.0
+ find-pkg: 2.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/bridge-react': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
+ '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/rsbuild-plugin': https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
'@swc/helpers': 0.5.18
fs-extra: 11.3.0
jiti: 2.4.2
@@ -16938,11 +17236,41 @@ snapshots:
- utf-8-validate
- webpack
- '@module-federation/node@2.7.31(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@module-federation/enhanced': 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/runtime': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/bridge-react': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
+ '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/rsbuild-plugin': https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@swc/helpers': 0.5.18
+ fs-extra: 11.3.0
+ jiti: 2.4.2
+ lru-cache: 10.4.3
+ node-fetch: 3.3.2
+ react: 19.2.4
+ react-dom: 19.2.4(react@19.2.4)
+ react-error-boundary: 4.1.2(react@19.2.4)
+ optionalDependencies:
+ react-router: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ react-router-dom: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - '@rsbuild/core'
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+ - webpack
+
+ '@module-federation/node@2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/enhanced': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/sdk': 2.0.1
btoa: 1.2.1
encoding: 0.1.13
node-fetch: 2.7.0(encoding@0.1.13)
@@ -16959,11 +17287,32 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/rsbuild-plugin@2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@module-federation/node@2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@module-federation/enhanced': 2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/node': 2.7.31(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/sdk': 2.0.0
+ '@module-federation/enhanced': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ btoa: 1.2.1
+ encoding: 0.1.13
+ node-fetch: 2.7.0(encoding@0.1.13)
+ optionalDependencies:
+ webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - react
+ - react-dom
+ - supports-color
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ dependencies:
+ '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
fs-extra: 11.3.0
transitivePeerDependencies:
- '@rspack/core'
@@ -16977,16 +17326,91 @@ snapshots:
- vue-tsc
- webpack
- '@module-federation/rspack@2.0.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@module-federation/bridge-react-webpack-plugin': 2.0.0
- '@module-federation/dts-plugin': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/inject-external-runtime-core-plugin': 2.0.0(@module-federation/runtime-tools@2.0.0)
- '@module-federation/managers': 2.0.0
- '@module-federation/manifest': 2.0.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': 2.0.0
- '@module-federation/sdk': 2.0.0
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
+ '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ fs-extra: 11.3.0
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - debug
+ - react
+ - react-dom
+ - supports-color
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+ - webpack
+
+ '@module-federation/rspack@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.0.1
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@2.0.1)
+ '@module-federation/managers': 2.0.1
+ '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
+ btoa: 1.2.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/rspack@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.0.1
+ '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
+ '@module-federation/managers': 2.0.1
+ '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)
+ btoa: 1.2.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
+ btoa: 1.2.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+
+ '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
+ '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)
btoa: 1.2.1
optionalDependencies:
typescript: 5.9.3
@@ -17006,15 +17430,30 @@ snapshots:
'@module-federation/error-codes': 2.0.0
'@module-federation/sdk': 2.0.0
+ '@module-federation/runtime-core@2.0.1':
+ dependencies:
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/sdk': 2.0.1
+
+ '@module-federation/runtime-core@https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c':
+ dependencies:
+ '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+
'@module-federation/runtime-tools@0.22.0':
dependencies:
'@module-federation/runtime': 0.22.0
'@module-federation/webpack-bundler-runtime': 0.22.0
- '@module-federation/runtime-tools@2.0.0':
+ '@module-federation/runtime-tools@2.0.1':
+ dependencies:
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/webpack-bundler-runtime': 2.0.1
+
+ '@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c':
dependencies:
- '@module-federation/runtime': 2.0.0
- '@module-federation/webpack-bundler-runtime': 2.0.0
+ '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/webpack-bundler-runtime': https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c
'@module-federation/runtime@0.22.0':
dependencies:
@@ -17028,11 +17467,33 @@ snapshots:
'@module-federation/runtime-core': 2.0.0
'@module-federation/sdk': 2.0.0
+ '@module-federation/runtime@2.0.1':
+ dependencies:
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/runtime-core': 2.0.1
+ '@module-federation/sdk': 2.0.1
+
+ '@module-federation/runtime@https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
+ dependencies:
+ '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/runtime-core': https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+
'@module-federation/sdk@0.22.0': {}
'@module-federation/sdk@2.0.0': {}
- '@module-federation/third-party-dts-extractor@2.0.0':
+ '@module-federation/sdk@2.0.1': {}
+
+ '@module-federation/sdk@https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c': {}
+
+ '@module-federation/third-party-dts-extractor@2.0.1':
+ dependencies:
+ find-pkg: 2.0.0
+ fs-extra: 9.1.0
+ resolve: 1.22.8
+
+ '@module-federation/third-party-dts-extractor@https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c':
dependencies:
find-pkg: 2.0.0
fs-extra: 9.1.0
@@ -17043,10 +17504,15 @@ snapshots:
'@module-federation/runtime': 0.22.0
'@module-federation/sdk': 0.22.0
- '@module-federation/webpack-bundler-runtime@2.0.0':
+ '@module-federation/webpack-bundler-runtime@2.0.1':
dependencies:
- '@module-federation/runtime': 2.0.0
- '@module-federation/sdk': 2.0.0
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/sdk': 2.0.1
+
+ '@module-federation/webpack-bundler-runtime@https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
+ dependencies:
+ '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
'@mswjs/interceptors@0.39.8':
dependencies:
@@ -17894,18 +18360,25 @@ snapshots:
optionalDependencies:
'@swc/helpers': 0.5.18
- '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)':
+ '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)':
dependencies:
'@rspack/binding': 2.0.0-beta.2
optionalDependencies:
- '@module-federation/runtime-tools': 2.0.0
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': 0.5.17
- '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)':
+ '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)':
+ dependencies:
+ '@rspack/binding': 2.0.0-beta.2
+ optionalDependencies:
+ '@module-federation/runtime-tools': 2.0.1
+ '@swc/helpers': 0.5.18
+
+ '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)':
dependencies:
'@rspack/binding': 2.0.0-beta.2
optionalDependencies:
- '@module-federation/runtime-tools': 2.0.0
+ '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
'@swc/helpers': 0.5.18
'@rspack/lite-tapable@1.1.0': {}
@@ -22241,14 +22714,14 @@ snapshots:
jest-cli@29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
+ create-jest: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
exit: 0.1.2
import-local: 3.2.0
- jest-config: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
+ jest-config: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -22637,7 +23110,7 @@ snapshots:
jest@29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
'@jest/types': 29.6.3
import-local: 3.2.0
jest-cli: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)
@@ -25197,15 +25670,15 @@ snapshots:
optionalDependencies:
react-dom: 19.2.4(react@19.2.4)
- react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.18)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -25511,7 +25984,7 @@ snapshots:
dependencies:
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)
run-async@2.4.1: {}
@@ -26417,7 +26890,7 @@ snapshots:
picocolors: 1.1.1
typescript: 5.9.3
optionalDependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.0)(@swc/helpers@0.5.17)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)
ts-dedent@2.2.0: {}
diff --git a/tests/integration/i18n/mf/mf-app-provider/package.json b/tests/integration/i18n/mf/mf-app-provider/package.json
index 5e08ef377cea..32a2c9a05d4c 100644
--- a/tests/integration/i18n/mf/mf-app-provider/package.json
+++ b/tests/integration/i18n/mf/mf-app-provider/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@modern-js/plugin-i18n": "workspace:*",
"@modern-js/runtime": "workspace:*",
- "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/modern-js-v3": "https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437",
"i18next": "25.7.4",
"react": "^19.2.4",
"react-dom": "^19.2.4",
diff --git a/tests/integration/i18n/mf/mf-component-provider/package.json b/tests/integration/i18n/mf/mf-component-provider/package.json
index a1a174fe7ad5..24004f5155f6 100644
--- a/tests/integration/i18n/mf/mf-component-provider/package.json
+++ b/tests/integration/i18n/mf/mf-component-provider/package.json
@@ -9,7 +9,7 @@
"dependencies": {
"@modern-js/plugin-i18n": "workspace:*",
"@modern-js/runtime": "workspace:*",
- "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/modern-js-v3": "https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437",
"i18next": "25.7.4",
"react": "^19.2.4",
"react-dom": "^19.2.4",
diff --git a/tests/integration/i18n/mf/mf-consumer/package.json b/tests/integration/i18n/mf/mf-consumer/package.json
index 8b9590605fbd..22f3693fdfdf 100644
--- a/tests/integration/i18n/mf/mf-consumer/package.json
+++ b/tests/integration/i18n/mf/mf-consumer/package.json
@@ -9,7 +9,7 @@
"dependencies": {
"@modern-js/plugin-i18n": "workspace:*",
"@modern-js/runtime": "workspace:*",
- "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/modern-js-v3": "https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437",
"@module-federation/runtime": "2.0.0",
"i18next": "25.7.4",
"react": "^19.2.4",
diff --git a/tests/integration/rsc-mf/host/package.json b/tests/integration/rsc-mf/host/package.json
index 010e39c8021e..3e9c0e60bf53 100644
--- a/tests/integration/rsc-mf/host/package.json
+++ b/tests/integration/rsc-mf/host/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@modern-js/render": "workspace:*",
"@modern-js/runtime": "workspace:*",
- "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/modern-js-v3": "https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437",
"@module-federation/runtime": "2.0.0",
"client-only": "^0.0.1",
"react": "^19.2.4",
diff --git a/tests/integration/rsc-mf/remote/package.json b/tests/integration/rsc-mf/remote/package.json
index 9b040ea2fe51..c0f4a45ea024 100644
--- a/tests/integration/rsc-mf/remote/package.json
+++ b/tests/integration/rsc-mf/remote/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@modern-js/render": "workspace:*",
"@modern-js/runtime": "workspace:*",
- "@module-federation/modern-js-v3": "2.0.0",
+ "@module-federation/modern-js-v3": "https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437",
"@module-federation/runtime": "2.0.0",
"client-only": "^0.0.1",
"react": "^19.2.4",
From 49c52dd666198ace2c9135f379bcac106dbbb7de Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 04:27:31 +0000
Subject: [PATCH 007/324] fix(rsc-mf): add react-server resolve condition for
async-node
---
tests/integration/rsc-mf/host/modern.config.ts | 1 +
tests/integration/rsc-mf/remote/modern.config.ts | 1 +
2 files changed, 2 insertions(+)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index 1ae1399165c1..fad69a578eb7 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -23,6 +23,7 @@ export default defineConfig({
const targets = Array.isArray(target) ? target : [target];
if (targets.some(item => String(item).includes('node'))) {
chain.target('async-node');
+ chain.resolve.conditionNames.add('react-server');
}
chain.resolve.modules
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index 9aeec9a165a6..a360574cff66 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -26,6 +26,7 @@ export default defineConfig({
const targets = Array.isArray(target) ? target : [target];
if (targets.some(item => String(item).includes('node'))) {
chain.target('async-node');
+ chain.resolve.conditionNames.add('react-server');
}
chain.resolve.modules
From 6c1d6d1813a50d50c4ccb5732150ac1ec33273c5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 04:33:20 +0000
Subject: [PATCH 008/324] chore(rsc-mf): include fallback resolve conditions in
node chain
---
tests/integration/rsc-mf/host/modern.config.ts | 6 +++++-
tests/integration/rsc-mf/remote/modern.config.ts | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index fad69a578eb7..c85abbd14978 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -23,7 +23,11 @@ export default defineConfig({
const targets = Array.isArray(target) ? target : [target];
if (targets.some(item => String(item).includes('node'))) {
chain.target('async-node');
- chain.resolve.conditionNames.add('react-server');
+ chain.resolve.conditionNames
+ .add('react-server')
+ .add('require')
+ .add('import')
+ .add('default');
}
chain.resolve.modules
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index a360574cff66..601aa9121a99 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -26,7 +26,11 @@ export default defineConfig({
const targets = Array.isArray(target) ? target : [target];
if (targets.some(item => String(item).includes('node'))) {
chain.target('async-node');
- chain.resolve.conditionNames.add('react-server');
+ chain.resolve.conditionNames
+ .add('react-server')
+ .add('require')
+ .add('import')
+ .add('default');
}
chain.resolve.modules
From d8c6ca9d9bb0b0e1b7eb4586e57cd384136c4dad Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 04:59:48 +0000
Subject: [PATCH 009/324] fix(rsc-mf): align federation runtime deps and ssr
public path
---
package.json | 19 +
pnpm-lock.yaml | 784 ++++--------------
.../rsc-mf/remote/modern.config.ts | 3 +
3 files changed, 167 insertions(+), 639 deletions(-)
diff --git a/package.json b/package.json
index e37bdf6c3590..c55a91dc5680 100644
--- a/package.json
+++ b/package.json
@@ -88,6 +88,25 @@
"@remix-run/router": ">=1.23.2",
"h3": ">=1.15.5",
"@rspack/core@2.0.0-beta.2": "npm:@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235",
+ "@module-federation/bridge-react": "2.0.1",
+ "@module-federation/bridge-react-webpack-plugin": "2.0.1",
+ "@module-federation/bridge-shared": "2.0.1",
+ "@module-federation/cli": "2.0.1",
+ "@module-federation/data-prefetch": "2.0.1",
+ "@module-federation/dts-plugin": "2.0.1",
+ "@module-federation/enhanced": "2.0.1",
+ "@module-federation/error-codes": "2.0.1",
+ "@module-federation/inject-external-runtime-core-plugin": "2.0.1",
+ "@module-federation/managers": "2.0.1",
+ "@module-federation/manifest": "2.0.1",
+ "@module-federation/rsbuild-plugin": "2.0.1",
+ "@module-federation/rspack": "2.0.1",
+ "@module-federation/runtime": "2.0.1",
+ "@module-federation/runtime-core": "2.0.1",
+ "@module-federation/runtime-tools": "2.0.1",
+ "@module-federation/sdk": "2.0.1",
+ "@module-federation/third-party-dts-extractor": "2.0.1",
+ "@module-federation/webpack-bundler-runtime": "2.0.1",
"tar": ">=7.5.4",
"diff": ">=4.0.4",
"debug": ">=4.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b3398b1fee76..afad0e59e21f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,6 +10,25 @@ overrides:
'@remix-run/router': '>=1.23.2'
h3: '>=1.15.5'
'@rspack/core@2.0.0-beta.2': npm:@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235
+ '@module-federation/bridge-react': 2.0.1
+ '@module-federation/bridge-react-webpack-plugin': 2.0.1
+ '@module-federation/bridge-shared': 2.0.1
+ '@module-federation/cli': 2.0.1
+ '@module-federation/data-prefetch': 2.0.1
+ '@module-federation/dts-plugin': 2.0.1
+ '@module-federation/enhanced': 2.0.1
+ '@module-federation/error-codes': 2.0.1
+ '@module-federation/inject-external-runtime-core-plugin': 2.0.1
+ '@module-federation/managers': 2.0.1
+ '@module-federation/manifest': 2.0.1
+ '@module-federation/rsbuild-plugin': 2.0.1
+ '@module-federation/rspack': 2.0.1
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/runtime-core': 2.0.1
+ '@module-federation/runtime-tools': 2.0.1
+ '@module-federation/sdk': 2.0.1
+ '@module-federation/third-party-dts-extractor': 2.0.1
+ '@module-federation/webpack-bundler-runtime': 2.0.1
tar: '>=7.5.4'
diff: '>=4.0.4'
debug: '>=4.3.1'
@@ -100,7 +119,7 @@ importers:
version: link:../../packages/tsconfig
'@rsdoctor/rspack-plugin':
specifier: ^1.5.2
- version: 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ version: 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@types/node':
specifier: ^20
version: 20.19.27
@@ -127,40 +146,40 @@ importers:
version: link:../../toolkit/utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rsbuild/plugin-assets-retry':
specifier: 1.5.1
- version: 1.5.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.5.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-check-syntax':
specifier: 1.6.1
- version: 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-css-minimizer':
specifier: 1.1.1
- version: 1.1.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
+ version: 1.1.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
'@rsbuild/plugin-less':
specifier: 1.6.0
- version: 1.6.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.6.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-react':
specifier: 1.4.4
- version: 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-rem':
specifier: 1.0.5
- version: 1.0.5(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.0.5(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-sass':
specifier: 1.5.0
- version: 1.5.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.5.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-source-build':
specifier: 1.0.4
- version: 1.0.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.0.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsbuild/plugin-svgr':
specifier: 1.3.0
- version: 1.3.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(typescript@5.9.3)
+ version: 1.3.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(typescript@5.9.3)
'@rsbuild/plugin-type-check':
specifier: 1.3.3
- version: 1.3.3(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)
+ version: 1.3.3(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(typescript@5.9.3)
'@rsbuild/plugin-typed-css-modules':
specifier: 1.2.1
- version: 1.2.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.2.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@swc/core':
specifier: 1.15.11
version: 1.15.11(@swc/helpers@0.5.17)
@@ -211,10 +230,10 @@ importers:
version: 3.0.4(postcss@8.5.6)
rsbuild-plugin-rsc:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
+ version: 0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
rspack-manifest-plugin:
specifier: 5.2.1
- version: 5.2.1(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))
+ version: 5.2.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))
ts-deepmerge:
specifier: 7.0.3
version: 7.0.3
@@ -297,7 +316,7 @@ importers:
version: link:../../toolkit/types
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -349,7 +368,7 @@ importers:
version: link:../../toolkit/types
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -431,7 +450,7 @@ importers:
dependencies:
'@rsbuild/plugin-styled-components':
specifier: 1.6.1
- version: 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -475,16 +494,16 @@ importers:
devDependencies:
'@rsbuild/plugin-sass':
specifier: 1.5.0
- version: 1.5.0(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))
+ version: 1.5.0(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rspress/core':
specifier: 2.0.2
- version: 2.0.2(@types/react@19.2.13)(core-js@3.48.0)
+ version: 2.0.2(@module-federation/runtime-tools@2.0.1)(@types/react@19.2.13)(core-js@3.48.0)
'@rspress/plugin-llms':
specifier: 2.0.2
- version: 2.0.2(@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0))
+ version: 2.0.2(@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.1)(@types/react@19.2.13)(core-js@3.48.0))
'@rspress/shared':
specifier: 2.0.2
- version: 2.0.2(core-js@3.48.0)
+ version: 2.0.2(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@shikijs/transformers':
specifier: ^3.21.0
version: 3.21.0
@@ -706,7 +725,7 @@ importers:
version: 4.4.2
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -785,7 +804,7 @@ importers:
version: 19.2.4(react@19.2.4)
react-server-dom-rspack:
specifier: 0.0.1-beta.0
- version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ version: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
typescript:
specifier: ^5
version: 5.9.3
@@ -1250,7 +1269,7 @@ importers:
version: link:../../toolkit/utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -1363,7 +1382,7 @@ importers:
version: link:../utils
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@swc/helpers':
specifier: ^0.5.17
version: 0.5.17
@@ -1896,7 +1915,7 @@ importers:
devDependencies:
'@rsbuild/plugin-react':
specifier: 1.4.4
- version: 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rslib/core':
specifier: 0.19.5
version: 0.19.5(typescript@5.9.3)
@@ -2020,7 +2039,7 @@ importers:
version: 1.58.2
'@rsbuild/core':
specifier: 2.0.0-beta.4
- version: 2.0.0-beta.4(core-js@3.48.0)
+ version: 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@types/connect':
specifier: ^3.4.38
version: 3.4.38
@@ -3031,7 +3050,7 @@ importers:
version: link:../../../../../packages/runtime/plugin-runtime
'@module-federation/modern-js-v3':
specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
- version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
i18next:
specifier: 25.7.4
version: 25.7.4(typescript@5.9.3)
@@ -3095,8 +3114,8 @@ importers:
specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
- specifier: 2.0.0
- version: 2.0.0
+ specifier: 2.0.1
+ version: 2.0.1
i18next:
specifier: 25.7.4
version: 25.7.4(typescript@5.9.3)
@@ -3190,7 +3209,7 @@ importers:
version: link:../../../packages/solutions/app-tools
'@rsdoctor/rspack-plugin':
specifier: ^1.5.2
- version: 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ version: 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@types/jest':
specifier: ^29.5.14
version: 29.5.14
@@ -3562,8 +3581,8 @@ importers:
specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
- specifier: 2.0.0
- version: 2.0.0
+ specifier: 2.0.1
+ version: 2.0.1
client-only:
specifier: ^0.0.1
version: 0.0.1
@@ -3617,8 +3636,8 @@ importers:
specifier: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437
version: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/runtime':
- specifier: 2.0.0
- version: 2.0.0
+ specifier: 2.0.1
+ version: 2.0.1
client-only:
specifier: ^0.0.1
version: 0.0.1
@@ -4544,7 +4563,7 @@ importers:
version: link:../../../../../packages/runtime/plugin-runtime
'@rsbuild/plugin-babel':
specifier: 1.1.0
- version: 1.1.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ version: 1.1.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
react:
specifier: ^19.2.4
version: 19.2.4
@@ -6156,13 +6175,8 @@ packages:
'@module-federation/bridge-react-webpack-plugin@2.0.1':
resolution: {integrity: sha512-D7LMW5EMAJShOMR1aZDAJ6s+MdsYDHaQyJADLQ3LaY0sne/BkVqkPikUwcO1IwOwKbXjYsDlQVOEvk9wZVRFhA==}
- '@module-federation/bridge-react-webpack-plugin@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
- '@module-federation/bridge-react@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
+ '@module-federation/bridge-react@2.0.1':
+ resolution: {integrity: sha512-pioaxszMgfPL6T7uJk0+Wm6QqanhRwIcKOjbDMTDbKX1hGO5Y00Y1RGLq5xxilytDT9/Ivu+Yuyo8zmsGp9AAw==}
peerDependencies:
react: '>=16.9.0'
react-dom: '>=16.9.0'
@@ -6174,21 +6188,14 @@ packages:
react-router-dom:
optional: true
- '@module-federation/bridge-shared@https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
+ '@module-federation/bridge-shared@2.0.1':
+ resolution: {integrity: sha512-GAjbEJC90GheChLzM8JcSYOEHu4GFqSz+X27dBnQ2Ka1R3zqi3OfWowbyQVnH6LLKyM6A+FC41KMBDCkfv/E+w==}
'@module-federation/cli@2.0.1':
resolution: {integrity: sha512-2SL5Y8iODNX10y9T3CBLhHjSXo4afnA1BK82m4sNfZebuVO+o34bxewqwod9xfWq9xhTZmOSFZ+n+lgTKRv+CQ==}
engines: {node: '>=16.0.0'}
hasBin: true
- '@module-federation/cli@https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
- engines: {node: '>=16.0.0'}
- hasBin: true
-
'@module-federation/data-prefetch@2.0.1':
resolution: {integrity: sha512-Kq0P1OABGt6QAvs6TaE/zY9Ut9Y/oJFrzoSF3eWaCYbUAr2KD2SpTyMsPz4ssBzjeKXTgimugh6tHHd6mpCBIQ==}
peerDependencies:
@@ -6200,18 +6207,6 @@ packages:
react-dom:
optional: true
- '@module-federation/data-prefetch@https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
- peerDependencies:
- react: '>=16.9.0'
- react-dom: '>=16.9.0'
- peerDependenciesMeta:
- react:
- optional: true
- react-dom:
- optional: true
-
'@module-federation/dts-plugin@2.0.1':
resolution: {integrity: sha512-PLneTsf1fQS5/RTBedtLAAmCPRdMfIlhfJkOa8QH3WDJaQsqm8Wb3r2cTUBf2aNj/bP3aH/y6Hs9JFB/4x0l5g==}
peerDependencies:
@@ -6221,19 +6216,8 @@ packages:
vue-tsc:
optional: true
- '@module-federation/dts-plugin@https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
- peerDependencies:
- typescript: ^4.9.0 || ^5.0.0
- vue-tsc: '>=1.0.24'
- peerDependenciesMeta:
- vue-tsc:
- optional: true
-
'@module-federation/enhanced@2.0.1':
resolution: {integrity: sha512-EZIARQ/8ScoTP6PV8+E4SsmMYWK4ErrikZJ0G/FX8wvK8mCtdoKatFtvDN9++P6Nl78kN9zHYgAV4AHKdBVjfQ==}
- version: 2.0.1
hasBin: true
peerDependencies:
typescript: ^4.9.0 || ^5.0.0
@@ -6247,61 +6231,20 @@ packages:
webpack:
optional: true
- '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
- hasBin: true
- peerDependencies:
- typescript: ^4.9.0 || ^5.0.0
- vue-tsc: '>=1.0.24'
- webpack: ^5.0.0
- peerDependenciesMeta:
- typescript:
- optional: true
- vue-tsc:
- optional: true
- webpack:
- optional: true
-
- '@module-federation/error-codes@0.22.0':
- resolution: {integrity: sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==}
-
- '@module-federation/error-codes@2.0.0':
- resolution: {integrity: sha512-9oE+hXuPv2zej7AxJ5hOgeRqlPs98meooV2FiutTfftLAyy2N6+Kwmmz5NR9d9t91weJj8N0cSHFoyenNHKTVg==}
-
'@module-federation/error-codes@2.0.1':
resolution: {integrity: sha512-2bJF/ft+qL9L6Zvq2t/G9/f/0wFL73cM8/NJ04uyYz9BjIgvx28K5qu8/6+IwgEEKATG7vOhBBVj6wH3S+5ASA==}
- '@module-federation/error-codes@https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
'@module-federation/inject-external-runtime-core-plugin@2.0.1':
resolution: {integrity: sha512-oAA7G+4GCHM+WRYfscR/x4GwCyM9CEqfdD9/x2L6y8mtLWK9anRLKTocsI759AvzXsbT1m3EQ5ki1O6wlwDu3g==}
- version: 2.0.1
- peerDependencies:
- '@module-federation/runtime-tools': 2.0.1
-
- '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
peerDependencies:
'@module-federation/runtime-tools': 2.0.1
'@module-federation/managers@2.0.1':
resolution: {integrity: sha512-KR01lSlcYRQ9C6hW2a8CQQtAE0LvfTLgtV/6ZNUTagw8sRfeDln+ggrZsYilKu9zl0i8RPDgpv/kS60o4lcxCQ==}
- '@module-federation/managers@https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
'@module-federation/manifest@2.0.1':
resolution: {integrity: sha512-p8nYGjHWp17MsYdW/Vv0ogBDiTTsI1PHWPQbvVIqLQXDqwiesaRSRR1zziECXQoEL8lV5Bs+uSkcaJGhea9P+A==}
- '@module-federation/manifest@https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
'@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437':
resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437}
version: 2.0.1
@@ -6324,16 +6267,14 @@ packages:
'@module-federation/node@2.7.32':
resolution: {integrity: sha512-hUj5v2GGwpNzl2gaJS4AyzCYRzJBhN8875A+ucKF9tq3jaQb5zpy3izYMISqqbN2q9a7jz3nEUgwAh3pjri+rQ==}
- version: 2.7.32
peerDependencies:
webpack: ^5.40.0
peerDependenciesMeta:
webpack:
optional: true
- '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
+ '@module-federation/rsbuild-plugin@2.0.1':
+ resolution: {integrity: sha512-+2HOfntaVHgaOmyT0fTR9tZR2mujveoad3I9cpXUJ890Kgyz000nNHUbumQcMECPcZb3+ZqbIDjHyoazlW5IOA==}
engines: {node: '>=16.0.0'}
peerDependencies:
'@rsbuild/core': 2.0.0-beta.2
@@ -6343,20 +6284,6 @@ packages:
'@module-federation/rspack@2.0.1':
resolution: {integrity: sha512-SAlNE8iclFmzrKtx3/C2GivXYx6nPzx4MgQV01QG/a4LpnLbwlxzdZu3rqQ2swp4NNWT/t/GT7Y+7gfhyVa7mg==}
- version: 2.0.1
- peerDependencies:
- '@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0
- typescript: ^4.9.0 || ^5.0.0
- vue-tsc: '>=1.0.24'
- peerDependenciesMeta:
- typescript:
- optional: true
- vue-tsc:
- optional: true
-
- '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
peerDependencies:
'@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0
typescript: ^4.9.0 || ^5.0.0
@@ -6367,72 +6294,24 @@ packages:
vue-tsc:
optional: true
- '@module-federation/runtime-core@0.22.0':
- resolution: {integrity: sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==}
-
- '@module-federation/runtime-core@2.0.0':
- resolution: {integrity: sha512-UhIGUs7Mg+TwMI2lgaLnj4UehpoyXbR7HDb2+vLikgBulPmFtodeWfsxCgENEwKsIY1vS0lOun15lNOn1vo3Xg==}
-
'@module-federation/runtime-core@2.0.1':
resolution: {integrity: sha512-gOuCPSHoQGUGwlxfSTMInFX+QvLxdEWegGGMiLdU5vqbXuva4E9M+kXBBO7/0MkcBPMmVs0wOJGm0XOLeV2f1Q==}
- '@module-federation/runtime-core@https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
- '@module-federation/runtime-tools@0.22.0':
- resolution: {integrity: sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==}
-
'@module-federation/runtime-tools@2.0.1':
resolution: {integrity: sha512-AStdwBtsGB3jIfDg9oP+KyVPsimdaeHsP855gqCxDp1hi2+GKjlZWZx9ThkS8NytVSXSUysxqoUL1ivDoKgcCQ==}
- '@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
- '@module-federation/runtime@0.22.0':
- resolution: {integrity: sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==}
-
- '@module-federation/runtime@2.0.0':
- resolution: {integrity: sha512-vPxQrmQNq3Z1T+1fkHEvFwTdJq9wuCLvdp/lpu9k2Oy7QP/Pj6QoQ/S7J5MCIAoRwj8Wj3z3ma21/DyHwLGvzA==}
-
'@module-federation/runtime@2.0.1':
resolution: {integrity: sha512-UQ72P5Oo40dS6vdhHetwTtIsbGciEr+bjoYvDgh1WLPfFlTYd8zo9cLfqaf3juuPfV3cMVARAVPmh16lQYpUGA==}
- '@module-federation/runtime@https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
- '@module-federation/sdk@0.22.0':
- resolution: {integrity: sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==}
-
- '@module-federation/sdk@2.0.0':
- resolution: {integrity: sha512-JYd1wTulsaoLT7HTk2oXL5y5797Z+H4mzxuUEKnSJo7R34RZSqehsqPSND7n0HT/1nf7uyn0Rb4qBfR3BVvdHQ==}
-
'@module-federation/sdk@2.0.1':
resolution: {integrity: sha512-32PwudojGjog51cwpTali7D6ud82oVgsyvOx9JjAzhvXBX96YI4mRsursuWcthDxmigJP9ZvUTXDuRUEDh1OQA==}
- '@module-federation/sdk@https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
'@module-federation/third-party-dts-extractor@2.0.1':
resolution: {integrity: sha512-neKSr6FNUeGRh+YR57l/QZUzPytJXuJx+babF7j5iGJG3FP+kfizr6QD0hgVis5KEoXMVbQ8yyvG0slERizeyw==}
- '@module-federation/third-party-dts-extractor@https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
- '@module-federation/webpack-bundler-runtime@0.22.0':
- resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==}
-
'@module-federation/webpack-bundler-runtime@2.0.1':
resolution: {integrity: sha512-u1NId3SF4lHDTmD2CHFEszulmXmIq1TGw9JYvnLx5rKJL7xt3aNxcb1GvkaYbRNVBXhSMjJ75E5LsQlZzyBx9A==}
- '@module-federation/webpack-bundler-runtime@https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
- resolution: {tarball: https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c}
- version: 2.0.1
-
'@mswjs/interceptors@0.39.8':
resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==}
engines: {node: '>=18'}
@@ -6980,7 +6859,7 @@ packages:
resolution: {integrity: sha512-VH9njrpSKv4/EBp53XvUJMMSbBtydx7R0ZWPyh/5a4gvGVafTLCiKV+shMZMgV5uWYYVTbA+5Fo0vL03a6iW1Q==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
- '@module-federation/runtime-tools': 0.24.1
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': '>=0.5.1'
peerDependenciesMeta:
'@module-federation/runtime-tools':
@@ -7218,7 +7097,7 @@ packages:
resolution: {integrity: sha512-2KK3hbxrRqzxtzg+ka7LsiEKIWIGIQz317k9HHC2U4IC5yLJ31K8y/vQfA1aIT2QcFls9gW7GyRjp8A4X5cvLA==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
- '@module-federation/runtime-tools': '>=0.22.0'
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': '>=0.5.1'
peerDependenciesMeta:
'@module-federation/runtime-tools':
@@ -7230,7 +7109,7 @@ packages:
resolution: {integrity: sha512-UD/LxAi9BCYGWKUMW82gwqYxWF46P5+P2jVSHC3rpv6IJ2EdPfRL1wqxbMGbkslD3YTB56vM18uwo1d5ThqrjA==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
- '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': '>=0.5.1'
peerDependenciesMeta:
'@module-federation/runtime-tools':
@@ -16911,16 +16790,10 @@ snapshots:
'@types/semver': 7.5.8
semver: 7.6.3
- '@module-federation/bridge-react-webpack-plugin@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- '@types/semver': 7.5.8
- semver: 7.6.3
-
- '@module-federation/bridge-react@https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)':
+ '@module-federation/bridge-react@2.0.1(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)':
dependencies:
- '@module-federation/bridge-shared': https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/bridge-shared': 2.0.1
+ '@module-federation/sdk': 2.0.1
lru-cache: 10.4.3
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -16929,7 +16802,7 @@ snapshots:
react-router: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-router-dom: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/bridge-shared@https://pkg.pr.new/module-federation/core/@module-federation/bridge-shared@73bd1ddb2266002f586a872ddae8020052c5457c': {}
+ '@module-federation/bridge-shared@2.0.1': {}
'@module-federation/cli@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
@@ -16946,21 +16819,6 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/cli@https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- chalk: 3.0.0
- commander: 11.1.0
- jiti: 2.4.2
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - typescript
- - utf-8-validate
- - vue-tsc
-
'@module-federation/data-prefetch@2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@module-federation/runtime': 2.0.1
@@ -16970,15 +16828,6 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- '@module-federation/data-prefetch@https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
- dependencies:
- '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- fs-extra: 9.1.0
- optionalDependencies:
- react: 19.2.4
- react-dom: 19.2.4(react@19.2.4)
-
'@module-federation/dts-plugin@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
'@module-federation/error-codes': 2.0.1
@@ -17004,30 +16853,6 @@ snapshots:
- supports-color
- utf-8-validate
- '@module-federation/dts-plugin@https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/third-party-dts-extractor': https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c
- adm-zip: 0.5.16
- ansi-colors: 4.1.3
- axios: 1.13.5(debug@4.4.3)
- chalk: 3.0.0
- fs-extra: 9.1.0
- isomorphic-ws: 5.0.0(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))
- lodash.clonedeepwith: 4.5.0
- log4js: 6.9.1
- node-schedule: 2.1.1
- rambda: 9.4.2
- typescript: 5.9.3
- ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - utf-8-validate
-
'@module-federation/enhanced@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
'@module-federation/bridge-react-webpack-plugin': 2.0.1
@@ -17056,126 +16881,18 @@ snapshots:
- supports-color
- utf-8-validate
- '@module-federation/enhanced@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': 2.0.1
- '@module-federation/cli': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/data-prefetch': 2.0.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/error-codes': 2.0.1
- '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
- '@module-federation/managers': 2.0.1
- '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/rspack': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': 2.0.1
- '@module-federation/sdk': 2.0.1
- btoa: 1.2.1
- schema-utils: 4.3.3
- upath: 2.0.1
- optionalDependencies:
- typescript: 5.9.3
- webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
- transitivePeerDependencies:
- - '@rspack/core'
- - bufferutil
- - debug
- - react
- - react-dom
- - supports-color
- - utf-8-validate
-
- '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/data-prefetch': https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/rspack': https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- btoa: 1.2.1
- schema-utils: 4.3.3
- upath: 2.0.1
- optionalDependencies:
- typescript: 5.9.3
- webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
- transitivePeerDependencies:
- - '@rspack/core'
- - bufferutil
- - debug
- - react
- - react-dom
- - supports-color
- - utf-8-validate
-
- '@module-federation/enhanced@https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/data-prefetch': https://pkg.pr.new/module-federation/core/@module-federation/data-prefetch@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/rspack': https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- btoa: 1.2.1
- schema-utils: 4.3.3
- upath: 2.0.1
- optionalDependencies:
- typescript: 5.9.3
- webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
- transitivePeerDependencies:
- - '@rspack/core'
- - bufferutil
- - debug
- - react
- - react-dom
- - supports-color
- - utf-8-validate
-
- '@module-federation/error-codes@0.22.0': {}
-
- '@module-federation/error-codes@2.0.0': {}
-
'@module-federation/error-codes@2.0.1': {}
- '@module-federation/error-codes@https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c': {}
-
'@module-federation/inject-external-runtime-core-plugin@2.0.1(@module-federation/runtime-tools@2.0.1)':
dependencies:
'@module-federation/runtime-tools': 2.0.1
- '@module-federation/inject-external-runtime-core-plugin@2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)':
- dependencies:
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
-
- '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)':
- dependencies:
- '@module-federation/runtime-tools': 2.0.1
-
- '@module-federation/inject-external-runtime-core-plugin@https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)':
- dependencies:
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
-
'@module-federation/managers@2.0.1':
dependencies:
'@module-federation/sdk': 2.0.1
find-pkg: 2.0.0
fs-extra: 9.1.0
- '@module-federation/managers@https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- find-pkg: 2.0.0
- fs-extra: 9.1.0
-
'@module-federation/manifest@2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
dependencies:
'@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
@@ -17191,60 +16908,15 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/manifest@https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- chalk: 3.0.0
- find-pkg: 2.0.0
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - typescript
- - utf-8-validate
- - vue-tsc
-
'@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@module-federation/bridge-react': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
- '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/bridge-react': 2.0.1(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
+ '@module-federation/cli': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
+ '@module-federation/enhanced': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/rsbuild-plugin': https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- '@swc/helpers': 0.5.18
- fs-extra: 11.3.0
- jiti: 2.4.2
- lru-cache: 10.4.3
- node-fetch: 3.3.2
- react: 19.2.4
- react-dom: 19.2.4(react@19.2.4)
- react-error-boundary: 4.1.2(react@19.2.4)
- optionalDependencies:
- react-router: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- react-router-dom: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
- typescript: 5.9.3
- transitivePeerDependencies:
- - '@rsbuild/core'
- - '@rspack/core'
- - bufferutil
- - debug
- - supports-color
- - utf-8-validate
- - webpack
-
- '@module-federation/modern-js-v3@https://pkg.pr.new/module-federation/core/@module-federation/modern-js-v3@4437(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/bridge-react': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react@73bd1ddb2266002f586a872ddae8020052c5457c(react-dom@19.2.4(react@19.2.4))(react-router-dom@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-router@7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)
- '@module-federation/cli': https://pkg.pr.new/module-federation/core/@module-federation/cli@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/rsbuild-plugin': https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/rsbuild-plugin': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/runtime': 2.0.1
+ '@module-federation/sdk': 2.0.1
'@swc/helpers': 0.5.18
fs-extra: 11.3.0
jiti: 2.4.2
@@ -17287,50 +16959,11 @@ snapshots:
- utf-8-validate
- vue-tsc
- '@module-federation/node@2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/enhanced': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/runtime': 2.0.1
- '@module-federation/sdk': 2.0.1
- btoa: 1.2.1
- encoding: 0.1.13
- node-fetch: 2.7.0(encoding@0.1.13)
- optionalDependencies:
- webpack: 5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2)
- transitivePeerDependencies:
- - '@rspack/core'
- - bufferutil
- - debug
- - react
- - react-dom
- - supports-color
- - typescript
- - utf-8-validate
- - vue-tsc
-
- '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@module-federation/rsbuild-plugin@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@module-federation/enhanced': 2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- fs-extra: 11.3.0
- transitivePeerDependencies:
- - '@rspack/core'
- - bufferutil
- - debug
- - react
- - react-dom
- - supports-color
- - typescript
- - utf-8-validate
- - vue-tsc
- - webpack
-
- '@module-federation/rsbuild-plugin@https://pkg.pr.new/module-federation/core/@module-federation/rsbuild-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
- dependencies:
- '@module-federation/enhanced': https://pkg.pr.new/module-federation/core/@module-federation/enhanced@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/node': 2.7.32(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
+ '@module-federation/sdk': 2.0.1
fs-extra: 11.3.0
transitivePeerDependencies:
- '@rspack/core'
@@ -17363,157 +16996,35 @@ snapshots:
- supports-color
- utf-8-validate
- '@module-federation/rspack@2.0.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': 2.0.1
- '@module-federation/dts-plugin': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/inject-external-runtime-core-plugin': 2.0.1(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
- '@module-federation/managers': 2.0.1
- '@module-federation/manifest': 2.0.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': 2.0.1
- '@module-federation/sdk': 2.0.1
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)
- btoa: 1.2.1
- optionalDependencies:
- typescript: 5.9.3
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - utf-8-validate
-
- '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@2.0.1)
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
- btoa: 1.2.1
- optionalDependencies:
- typescript: 5.9.3
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - utf-8-validate
-
- '@module-federation/rspack@https://pkg.pr.new/module-federation/core/@module-federation/rspack@73bd1ddb2266002f586a872ddae8020052c5457c(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18))(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)':
- dependencies:
- '@module-federation/bridge-react-webpack-plugin': https://pkg.pr.new/module-federation/core/@module-federation/bridge-react-webpack-plugin@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/dts-plugin': https://pkg.pr.new/module-federation/core/@module-federation/dts-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/inject-external-runtime-core-plugin': https://pkg.pr.new/module-federation/core/@module-federation/inject-external-runtime-core-plugin@73bd1ddb2266002f586a872ddae8020052c5457c(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)
- '@module-federation/managers': https://pkg.pr.new/module-federation/core/@module-federation/managers@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/manifest': https://pkg.pr.new/module-federation/core/@module-federation/manifest@73bd1ddb2266002f586a872ddae8020052c5457c(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)
- btoa: 1.2.1
- optionalDependencies:
- typescript: 5.9.3
- transitivePeerDependencies:
- - bufferutil
- - debug
- - supports-color
- - utf-8-validate
-
- '@module-federation/runtime-core@0.22.0':
- dependencies:
- '@module-federation/error-codes': 0.22.0
- '@module-federation/sdk': 0.22.0
-
- '@module-federation/runtime-core@2.0.0':
- dependencies:
- '@module-federation/error-codes': 2.0.0
- '@module-federation/sdk': 2.0.0
-
'@module-federation/runtime-core@2.0.1':
dependencies:
'@module-federation/error-codes': 2.0.1
'@module-federation/sdk': 2.0.1
- '@module-federation/runtime-core@https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
-
- '@module-federation/runtime-tools@0.22.0':
- dependencies:
- '@module-federation/runtime': 0.22.0
- '@module-federation/webpack-bundler-runtime': 0.22.0
-
'@module-federation/runtime-tools@2.0.1':
dependencies:
'@module-federation/runtime': 2.0.1
'@module-federation/webpack-bundler-runtime': 2.0.1
- '@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/webpack-bundler-runtime': https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c
-
- '@module-federation/runtime@0.22.0':
- dependencies:
- '@module-federation/error-codes': 0.22.0
- '@module-federation/runtime-core': 0.22.0
- '@module-federation/sdk': 0.22.0
-
- '@module-federation/runtime@2.0.0':
- dependencies:
- '@module-federation/error-codes': 2.0.0
- '@module-federation/runtime-core': 2.0.0
- '@module-federation/sdk': 2.0.0
-
'@module-federation/runtime@2.0.1':
dependencies:
'@module-federation/error-codes': 2.0.1
'@module-federation/runtime-core': 2.0.1
'@module-federation/sdk': 2.0.1
- '@module-federation/runtime@https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/error-codes': https://pkg.pr.new/module-federation/core/@module-federation/error-codes@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/runtime-core': https://pkg.pr.new/module-federation/core/@module-federation/runtime-core@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
-
- '@module-federation/sdk@0.22.0': {}
-
- '@module-federation/sdk@2.0.0': {}
-
'@module-federation/sdk@2.0.1': {}
- '@module-federation/sdk@https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c': {}
-
'@module-federation/third-party-dts-extractor@2.0.1':
dependencies:
find-pkg: 2.0.0
fs-extra: 9.1.0
resolve: 1.22.8
- '@module-federation/third-party-dts-extractor@https://pkg.pr.new/module-federation/core/@module-federation/third-party-dts-extractor@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- find-pkg: 2.0.0
- fs-extra: 9.1.0
- resolve: 1.22.8
-
- '@module-federation/webpack-bundler-runtime@0.22.0':
- dependencies:
- '@module-federation/runtime': 0.22.0
- '@module-federation/sdk': 0.22.0
-
'@module-federation/webpack-bundler-runtime@2.0.1':
dependencies:
'@module-federation/runtime': 2.0.1
'@module-federation/sdk': 2.0.1
- '@module-federation/webpack-bundler-runtime@https://pkg.pr.new/module-federation/core/@module-federation/webpack-bundler-runtime@73bd1ddb2266002f586a872ddae8020052c5457c':
- dependencies:
- '@module-federation/runtime': https://pkg.pr.new/module-federation/core/@module-federation/runtime@73bd1ddb2266002f586a872ddae8020052c5457c
- '@module-federation/sdk': https://pkg.pr.new/module-federation/core/@module-federation/sdk@73bd1ddb2266002f586a872ddae8020052c5457c
-
'@mswjs/interceptors@0.39.8':
dependencies:
'@open-draft/deferred-promise': 2.2.0
@@ -17845,9 +17356,9 @@ snapshots:
core-js: 3.47.0
jiti: 2.6.1
- '@rsbuild/core@2.0.0-beta.1(core-js@3.48.0)':
+ '@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)':
dependencies:
- '@rspack/core': 2.0.0-alpha.1(@swc/helpers@0.5.18)
+ '@rspack/core': 2.0.0-alpha.1(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
'@swc/helpers': 0.5.18
jiti: 2.6.1
optionalDependencies:
@@ -17855,26 +17366,26 @@ snapshots:
transitivePeerDependencies:
- '@module-federation/runtime-tools'
- '@rsbuild/core@2.0.0-beta.4(core-js@3.48.0)':
+ '@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)':
dependencies:
- '@rspack/core': '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@swc/helpers@0.5.18)'
+ '@rspack/core': '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)'
'@swc/helpers': 0.5.18
optionalDependencies:
core-js: 3.48.0
transitivePeerDependencies:
- '@module-federation/runtime-tools'
- '@rsbuild/plugin-assets-retry@1.5.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-assets-retry@1.5.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
- '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
'@babel/core': 7.28.6
'@babel/plugin-proposal-decorators': 7.28.6(@babel/core@7.28.6)
'@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.28.6)
'@babel/preset-typescript': 7.28.5(@babel/core@7.28.6)
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@types/babel__core': 7.20.5
deepmerge: 4.3.1
reduce-configs: 1.1.1
@@ -17882,7 +17393,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
acorn: 8.15.0
browserslist-to-es-version: 1.2.0
@@ -17890,14 +17401,14 @@ snapshots:
picocolors: 1.1.1
source-map: 0.7.6
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
- '@rsbuild/plugin-css-minimizer@1.1.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))':
+ '@rsbuild/plugin-css-minimizer@1.1.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))':
dependencies:
css-minimizer-webpack-plugin: 7.0.2(esbuild@0.27.2)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.17))(esbuild@0.27.2))
reduce-configs: 1.1.1
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
transitivePeerDependencies:
- '@parcel/css'
- '@swc/css'
@@ -17907,72 +17418,72 @@ snapshots:
- lightningcss
- webpack
- '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
deepmerge: 4.3.1
reduce-configs: 1.1.1
- '@rsbuild/plugin-react@1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-react@1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0)
react-refresh: 0.18.0
transitivePeerDependencies:
- webpack-hot-middleware
- '@rsbuild/plugin-react@1.4.5(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))':
+ '@rsbuild/plugin-react@1.4.5(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0)
react-refresh: 0.18.0
transitivePeerDependencies:
- webpack-hot-middleware
- '@rsbuild/plugin-rem@1.0.5(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-rem@1.0.5(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
deepmerge: 4.3.1
terser: 5.46.0
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
- '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))':
+ '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
deepmerge: 4.3.1
loader-utils: 2.0.4
postcss: 8.5.6
reduce-configs: 1.1.1
sass-embedded: 1.97.3
- '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
deepmerge: 4.3.1
loader-utils: 2.0.4
postcss: 8.5.6
reduce-configs: 1.1.1
sass-embedded: 1.97.3
- '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
fast-glob: 3.3.3
json5: 2.2.3
yaml: 2.8.2
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
- '@rsbuild/plugin-styled-components@1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-styled-components@1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
dependencies:
'@swc/plugin-styled-components': 12.3.0
reduce-configs: 1.1.1
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
- '@rsbuild/plugin-svgr@1.3.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(typescript@5.9.3)':
+ '@rsbuild/plugin-svgr@1.3.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(typescript@5.9.3)':
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- '@rsbuild/plugin-react': 1.4.4(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
+ '@rsbuild/plugin-react': 1.4.4(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@svgr/core': 8.1.0(typescript@5.9.3)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
'@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)
@@ -17983,27 +17494,27 @@ snapshots:
- typescript
- webpack-hot-middleware
- '@rsbuild/plugin-type-check@1.3.3(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)':
+ '@rsbuild/plugin-type-check@1.3.3(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(typescript@5.9.3)':
dependencies:
deepmerge: 4.3.1
json5: 2.2.3
reduce-configs: 1.1.1
- ts-checker-rspack-plugin: 1.2.3(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3)
+ ts-checker-rspack-plugin: 1.2.3(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(typescript@5.9.3)
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
transitivePeerDependencies:
- '@rspack/core'
- typescript
- '@rsbuild/plugin-typed-css-modules@1.2.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))':
+ '@rsbuild/plugin-typed-css-modules@1.2.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))':
optionalDependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@rsdoctor/client@1.5.2': {}
- '@rsdoctor/core@1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@rsdoctor/core@1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))
+ '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
'@rsdoctor/graph': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/sdk': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/types': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
@@ -18034,9 +17545,9 @@ snapshots:
- '@rspack/core'
- webpack
- '@rsdoctor/rspack-plugin@1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
+ '@rsdoctor/rspack-plugin@1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))':
dependencies:
- '@rsdoctor/core': 1.5.2(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
+ '@rsdoctor/core': 1.5.2(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/graph': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/sdk': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(bufferutil@4.1.0)(utf-8-validate@5.0.10)(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
'@rsdoctor/types': 1.5.2(@rspack/core@1.7.5(@swc/helpers@0.5.18))(webpack@5.104.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(esbuild@0.27.2))
@@ -18151,10 +17662,11 @@ snapshots:
'@rspack/binding-win32-ia32-msvc': '@rspack-canary/binding-win32-ia32-msvc@2.0.0-canary-032bd1ff-20260212021235'
'@rspack/binding-win32-x64-msvc': '@rspack-canary/binding-win32-x64-msvc@2.0.0-canary-032bd1ff-20260212021235'
- '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@swc/helpers@0.5.18)':
+ '@rspack-canary/core@2.0.0-canary-032bd1ff-20260212021235(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)':
dependencies:
'@rspack/binding': '@rspack-canary/binding@2.0.0-canary-032bd1ff-20260212021235'
optionalDependencies:
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': 0.5.18
'@rspack/binding-darwin-arm64@1.7.0':
@@ -18339,7 +17851,7 @@ snapshots:
'@rspack/core@1.7.0(@swc/helpers@0.5.18)':
dependencies:
- '@module-federation/runtime-tools': 0.22.0
+ '@module-federation/runtime-tools': 2.0.1
'@rspack/binding': 1.7.0
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
@@ -18347,17 +17859,18 @@ snapshots:
'@rspack/core@1.7.5(@swc/helpers@0.5.18)':
dependencies:
- '@module-federation/runtime-tools': 0.22.0
+ '@module-federation/runtime-tools': 2.0.1
'@rspack/binding': 1.7.5
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
'@swc/helpers': 0.5.18
- '@rspack/core@2.0.0-alpha.1(@swc/helpers@0.5.18)':
+ '@rspack/core@2.0.0-alpha.1(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)':
dependencies:
'@rspack/binding': 2.0.0-alpha.1
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
+ '@module-federation/runtime-tools': 2.0.1
'@swc/helpers': 0.5.18
'@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)':
@@ -18374,13 +17887,6 @@ snapshots:
'@module-federation/runtime-tools': 2.0.1
'@swc/helpers': 0.5.18
- '@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c)(@swc/helpers@0.5.18)':
- dependencies:
- '@rspack/binding': 2.0.0-beta.2
- optionalDependencies:
- '@module-federation/runtime-tools': https://pkg.pr.new/module-federation/core/@module-federation/runtime-tools@73bd1ddb2266002f586a872ddae8020052c5457c
- '@swc/helpers': 0.5.18
-
'@rspack/lite-tapable@1.1.0': {}
'@rspack/plugin-react-refresh@1.6.0(react-refresh@0.18.0)':
@@ -18389,13 +17895,13 @@ snapshots:
html-entities: 2.6.0
react-refresh: 0.18.0
- '@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0)':
+ '@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.1)(@types/react@19.2.13)(core-js@3.48.0)':
dependencies:
'@mdx-js/mdx': 3.1.1
'@mdx-js/react': 3.1.1(@types/react@19.2.13)(react@19.2.4)
- '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
- '@rsbuild/plugin-react': 1.4.5(@rsbuild/core@2.0.0-beta.1(core-js@3.48.0))
- '@rspress/shared': 2.0.2(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
+ '@rsbuild/plugin-react': 1.4.5(@rsbuild/core@2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))
+ '@rspress/shared': 2.0.2(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@shikijs/rehype': 3.22.0
'@types/unist': 3.0.3
'@unhead/react': 2.1.2(react@19.2.4)
@@ -18440,9 +17946,9 @@ snapshots:
- supports-color
- webpack-hot-middleware
- '@rspress/plugin-llms@2.0.2(@rspress/core@2.0.2(@types/react@19.2.13)(core-js@3.48.0))':
+ '@rspress/plugin-llms@2.0.2(@rspress/core@2.0.2(@module-federation/runtime-tools@2.0.1)(@types/react@19.2.13)(core-js@3.48.0))':
dependencies:
- '@rspress/core': 2.0.2(@types/react@19.2.13)(core-js@3.48.0)
+ '@rspress/core': 2.0.2(@module-federation/runtime-tools@2.0.1)(@types/react@19.2.13)(core-js@3.48.0)
remark-mdx: 3.1.1
remark-parse: 11.0.0
remark-stringify: 11.0.0
@@ -18451,9 +17957,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@rspress/shared@2.0.2(core-js@3.48.0)':
+ '@rspress/shared@2.0.2(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)':
dependencies:
- '@rsbuild/core': 2.0.0-beta.1(core-js@3.48.0)
+ '@rsbuild/core': 2.0.0-beta.1(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
'@shikijs/rehype': 3.22.0
gray-matter: 4.0.3
lodash-es: 4.17.23
@@ -22714,14 +22220,14 @@ snapshots:
jest-cli@29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
+ create-jest: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
exit: 0.1.2
import-local: 3.2.0
- jest-config: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
+ jest-config: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -23110,7 +22616,7 @@ snapshots:
jest@29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@20.19.27)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.11(@swc/helpers@0.5.18))(@types/node@20.19.27)(typescript@5.9.3))
'@jest/types': 29.6.3
import-local: 3.2.0
jest-cli: 29.7.0(@types/node@20.19.27)(babel-plugin-macros@3.1.0)
@@ -25670,15 +25176,15 @@ snapshots:
optionalDependencies:
react-dom: 19.2.4(react@19.2.4)
- react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
- react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
+ react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18))(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
- '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)
+ '@rspack/core': 2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.18)
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -25973,14 +25479,14 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
- rsbuild-plugin-rsc@0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
+ rsbuild-plugin-rsc@0.0.1-beta.0(@rsbuild/core@2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0))(react-server-dom-rspack@0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
dependencies:
- '@rsbuild/core': 2.0.0-beta.4(core-js@3.48.0)
- react-server-dom-rspack: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ '@rsbuild/core': 2.0.0-beta.4(@module-federation/runtime-tools@2.0.1)(core-js@3.48.0)
+ react-server-dom-rspack: 0.0.1-beta.0(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
rslog@1.3.2: {}
- rspack-manifest-plugin@5.2.1(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17)):
+ rspack-manifest-plugin@5.2.1(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17)):
dependencies:
'@rspack/lite-tapable': 1.1.0
optionalDependencies:
@@ -26879,7 +26385,7 @@ snapshots:
trough@2.2.0: {}
- ts-checker-rspack-plugin@1.2.3(@rspack/core@2.0.0-beta.2(@swc/helpers@0.5.17))(typescript@5.9.3):
+ ts-checker-rspack-plugin@1.2.3(@rspack/core@2.0.0-beta.2(@module-federation/runtime-tools@2.0.1)(@swc/helpers@0.5.17))(typescript@5.9.3):
dependencies:
'@babel/code-frame': 7.27.1
'@rspack/lite-tapable': 1.1.0
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index 601aa9121a99..59b7ec871deb 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -3,10 +3,12 @@ import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
const remotePort = process.env.RSC_MF_REMOTE_PORT || process.env.PORT || '3008';
+const enableRemoteServeSsr = Boolean(process.env.PORT);
export default defineConfig({
server: {
rsc: true,
+ ssr: enableRemoteServeSsr,
},
// Keep RSC server entries synchronous for MF+RSC handlers.
source: {
@@ -31,6 +33,7 @@ export default defineConfig({
.add('require')
.add('import')
.add('default');
+ chain.output.publicPath(`http://127.0.0.1:${remotePort}/bundles/`);
}
chain.resolve.modules
From b57802370adf5bdaf4d56205c83fd7d27028a030 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 09:53:31 +0000
Subject: [PATCH 010/324] test(rsc-mf): apply layered shared scopes and client
badge boundary
---
.../rsc-mf/host/module-federation.config.ts | 70 +++++++++-
.../host/src/server-component-root/App.tsx | 2 -
.../HostRemoteActionRunner.tsx | 2 +
.../rsc-mf/remote/module-federation.config.ts | 131 +++++++++++++++---
4 files changed, 183 insertions(+), 22 deletions(-)
diff --git a/tests/integration/rsc-mf/host/module-federation.config.ts b/tests/integration/rsc-mf/host/module-federation.config.ts
index 50bb8a7ff218..55c4547d8955 100644
--- a/tests/integration/rsc-mf/host/module-federation.config.ts
+++ b/tests/integration/rsc-mf/host/module-federation.config.ts
@@ -1,16 +1,78 @@
+import path from 'path';
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
const REMOTE_PORT = process.env.RSC_MF_REMOTE_PORT || '3008';
+const LAYERS = {
+ ssr: 'server-side-rendering',
+ rsc: 'react-server-components',
+} as const;
+
+const reactServerPath = path.join(
+ path.dirname(require.resolve('react/package.json')),
+ 'react.react-server.js',
+);
+
+const layeredShared = [
+ {
+ react: {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ 'react-dom': {
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'default',
+ },
+ },
+ {
+ react: {
+ import: 'react',
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'ssr',
+ layer: LAYERS.ssr,
+ issuerLayer: LAYERS.ssr,
+ },
+ },
+ {
+ react: {
+ import: reactServerPath,
+ shareKey: 'react',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ 'react-dom': {
+ import: 'react-dom',
+ shareKey: 'react-dom',
+ singleton: true,
+ requiredVersion: false,
+ shareScope: 'rsc',
+ layer: LAYERS.rsc,
+ issuerLayer: LAYERS.rsc,
+ },
+ },
+] as const;
export default createModuleFederationConfig({
name: 'rscHost',
remotes: {
rscRemote: `rscRemote@http://127.0.0.1:${REMOTE_PORT}/static/mf-manifest.json`,
},
- shared: {
- react: { singleton: true },
- 'react-dom': { singleton: true },
- },
+ shared: layeredShared as any,
dts: false,
experiments: {
asyncStartup: true,
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index e993df8966c0..6dc42165c72d 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -1,7 +1,6 @@
import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
-import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteNestedMixed } from 'rscRemote/RemoteNestedMixed';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
@@ -31,7 +30,6 @@ const App = () => {
Loading Remote RSC...}>
-
);
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index c28bc3d9642f..d698001afcb2 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -1,6 +1,7 @@
'use client';
import { useState } from 'react';
+import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { remoteActionEcho } from 'rscRemote/actions';
import defaultRemoteAction from 'rscRemote/defaultAction';
@@ -25,6 +26,7 @@ export default function HostRemoteActionRunner() {
return (
+
}>
-
+
From 64593db8692facbe5158d7f22a306d558e383dbb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 14:38:19 +0000
Subject: [PATCH 064/324] fix(rsc-mf): stop exposing RemoteNestedMixed from
remote
---
tests/integration/rsc-mf/remote/module-federation.config.ts | 4 ----
1 file changed, 4 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index f7b7c6ed897d..ee50385e41df 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -131,10 +131,6 @@ export default createModuleFederationConfig({
import: './src/components/AsyncRemoteServerInfo.tsx',
layer: LAYERS.rsc,
} as any,
- './RemoteNestedMixed': {
- import: './src/components/RemoteNestedMixed.tsx',
- layer: LAYERS.rsc,
- } as any,
'./remoteServerOnly': {
import: './src/components/serverOnly.ts',
layer: LAYERS.rsc,
From d01e78d545c9c300c783040fa07a3b3a42f77de0 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 14:40:49 +0000
Subject: [PATCH 065/324] fix(rsc-mf): patch counter aliases across expose
chunks
---
.../integration/rsc-mf/host/modern.config.ts | 11 ++++++++---
.../rsc-mf/host/server/modern.server.ts | 19 ++++++++++++++-----
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/tests/integration/rsc-mf/host/modern.config.ts b/tests/integration/rsc-mf/host/modern.config.ts
index daf6084bfc6b..569e45b2a152 100644
--- a/tests/integration/rsc-mf/host/modern.config.ts
+++ b/tests/integration/rsc-mf/host/modern.config.ts
@@ -51,17 +51,22 @@ const copyRemoteExposeAssets = async (subDir: 'js' | 'css') => {
.map(async file => {
const sourceFile = path.join(remoteAsyncDir, file);
const targetFile = path.join(hostAsyncDir, file);
- const shouldPatchNestedMixedChunk =
+ const shouldPatchCounterAliasChunk =
subDir === 'js' &&
- file.startsWith('__federation_expose_RemoteNestedMixed') &&
+ file.startsWith('__federation_expose_') &&
file.endsWith('.js');
- if (!shouldPatchNestedMixedChunk) {
+ if (!shouldPatchCounterAliasChunk) {
await fs.copyFile(sourceFile, targetFile);
return;
}
const chunkText = await fs.readFile(sourceFile, 'utf-8');
+ if (!chunkText.includes('remote-client-server-count')) {
+ await fs.copyFile(sourceFile, targetFile);
+ return;
+ }
+
const remoteCounterModuleId = resolveRemoteCounterModuleId(chunkText);
await fs.writeFile(
targetFile,
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index f112985ef904..4a24d2e196f4 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -115,12 +115,21 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
return;
}
- const shouldPatchNestedMixed =
- pathname.startsWith(
- '/static/js/async/__federation_expose_RemoteNestedMixed',
- ) && pathname.endsWith('.js');
- if (shouldPatchNestedMixed) {
+ const shouldPatchCounterAlias =
+ pathname.startsWith('/static/js/async/__federation_expose_') &&
+ pathname.endsWith('.js');
+ if (shouldPatchCounterAlias) {
let chunkText = await upstream.text();
+ if (!chunkText.includes('remote-client-server-count')) {
+ c.res = new Response(chunkText, {
+ status: upstream.status,
+ headers: {
+ 'content-type': 'application/javascript; charset=utf-8',
+ },
+ });
+ return;
+ }
+
chunkText = `${chunkText}${createRemoteNestedMixedAliasChunk()}`;
c.res = new Response(chunkText, {
From 42c27947455f6de799207287f2fbc97269542781 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 20:36:37 +0000
Subject: [PATCH 066/324] fix(rsc-mf): render remote client counter from host
client tree
---
.../integration/rsc-mf/host/src/server-component-root/App.tsx | 3 +--
.../host/src/server-component-root/HostRemoteActionRunner.tsx | 1 +
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 37dc202b0a2f..46ca6a880005 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -1,7 +1,6 @@
import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
-import { RemoteServerCard } from 'rscRemote/RemoteServerCard';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
@@ -39,7 +38,7 @@ const App = () => {
Loading Remote RSC...}>
-
+
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 7c0c929b218c..96db7ef99161 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -37,6 +37,7 @@ export default function HostRemoteActionRunner() {
return (
+
}>
+
+
+
+
+
+
);
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 96db7ef99161..aa925d2dfb7d 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -4,9 +4,20 @@ import { useEffect, useState } from 'react';
import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteClientCounter as RemoteClientCounterBridge } from 'rscRemote/RemoteClientCounter';
import { remoteActionEcho } from 'rscRemote/actions';
-import defaultRemoteAction from 'rscRemote/defaultAction';
+import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
+const REMOTE_ACTION_ID_TO_HOST_PROXY_ACTION_ID = {
+ '606c30f35d74d843171a8a71358eda595991e4ee16270e9f052af3faef57a19999':
+ '603cd42bd1c9b98894c6d03b3b688f513073ddbea04bb02d7fda1e72c57f96b69d',
+ '40e41a2ee9d9de373b364dcf2a0201701057c8502037bf9ef2cd26bb2a1259dabd':
+ '40f14c24f6d81be75aab6d9dc7941b9507bfbdb9daca25df7b1aed34703972c7ab',
+ '408da81ddb8214f8cb98a83552cb70c4d17b27b6fd36d972cac89e7030a4874fd4':
+ '40928b48a8dc80bb3a73661fbdbeb14155a85a1b965e9ef67a8f4132bbd4dda7e5',
+ '4019f2092c5baa86ad77fc144ce69129b81c38a1a6a1cb227a138b5d46de8977d7':
+ '404768f4f5d65c3edafd60e28fc1252837ade49f3b06dad341098530dea5bb7716',
+} as const;
+
export default function HostRemoteActionRunner() {
// Keep this import in the client graph so federated RSC bridge IDs
// can map back to a concrete remote module factory at runtime.
@@ -18,6 +29,8 @@ export default function HostRemoteActionRunner() {
useEffect(() => {
registerRemoteServerCallback(
`${window.location.origin}/server-component-root`,
+ 'rscRemote',
+ REMOTE_ACTION_ID_TO_HOST_PROXY_ACTION_ID as Record,
);
}, []);
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts b/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
index 128f9177cc8d..425bcf41bf92 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
+++ b/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
@@ -1,24 +1,24 @@
'use server';
-let proxyRemoteCountState = 0;
-
export async function proxyIncrementRemoteCount(
- _previousState: number,
+ previousState: number,
formData: FormData,
) {
- const count = Number(formData.get('count') || 1);
- proxyRemoteCountState += count;
- return proxyRemoteCountState;
+ const remote = await import('rscRemote/actions');
+ return remote.incrementRemoteCount(previousState, formData);
}
export async function proxyRemoteActionEcho(value: string) {
- return `remote-action:${value}`;
+ const remote = await import('rscRemote/actions');
+ return remote.remoteActionEcho(value);
}
export async function proxyNestedRemoteAction(value: string) {
- return `nested-action:${value}`;
+ const remote = await import('rscRemote/nestedActions');
+ return remote.nestedRemoteAction(value);
}
export async function proxyDefaultRemoteAction(value: string) {
- return `default-action:${value}`;
+ const remote = await import('rscRemote/defaultAction');
+ return remote.defaultRemoteAction(value);
}
diff --git a/tests/integration/rsc-mf/remote/src/components/defaultAction.ts b/tests/integration/rsc-mf/remote/src/components/defaultAction.ts
index 09f2458a768d..840844e7d440 100644
--- a/tests/integration/rsc-mf/remote/src/components/defaultAction.ts
+++ b/tests/integration/rsc-mf/remote/src/components/defaultAction.ts
@@ -1,5 +1,5 @@
'use server';
-export default async function defaultRemoteAction(value: string) {
+export async function defaultRemoteAction(value: string) {
return `default-action:${value}`;
}
diff --git a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
index 3f291289e09a..720891760029 100644
--- a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
@@ -5,27 +5,47 @@ import {
setServerCallback,
} from 'rsc-mf-react-server-dom-client-browser';
-let registeredRemoteOrigin = '';
+let registeredCallbackKey = '';
+const getHostActionId = (rawActionId: string, remoteAlias: string) => {
+ if (rawActionId.startsWith('remote:')) {
+ return rawActionId;
+ }
+
+ return `remote:${remoteAlias}:${rawActionId}`;
+};
-export function registerRemoteServerCallback(remoteOrigin: string) {
- if (!remoteOrigin || registeredRemoteOrigin === remoteOrigin) {
+export function registerRemoteServerCallback(
+ remoteOrigin: string,
+ remoteAlias = 'rscRemote',
+ remoteActionIdToHostProxyActionId?: Record,
+) {
+ if (!remoteOrigin) {
+ return;
+ }
+ const callbackKey = JSON.stringify({
+ remoteAlias,
+ remoteOrigin,
+ remoteActionIdToHostProxyActionId,
+ });
+ if (registeredCallbackKey === callbackKey) {
return;
}
const remoteActionUrl = new URL(remoteOrigin).toString();
- console.log(`[rsc-mf] registerRemoteServerCallback -> ${remoteActionUrl}`);
setServerCallback(async (id, args) => {
- console.log(`[rsc-mf] remote callback action id -> ${id}`);
+ const hostActionId =
+ remoteActionIdToHostProxyActionId?.[id] ||
+ getHostActionId(id, remoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
const response = fetch(remoteActionUrl, {
method: 'POST',
headers: {
Accept: 'text/x-component',
- 'x-rsc-action': id,
+ 'x-rsc-action': hostActionId,
},
body: await encodeReply(args, { temporaryReferences }),
});
return createFromFetch(response, { temporaryReferences });
});
- registeredRemoteOrigin = remoteOrigin;
+ registeredCallbackKey = callbackKey;
}
From 07b5fa76b3dd9b2d0ff43d86f2a3541c578c125c Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 22:01:14 +0000
Subject: [PATCH 068/324] test(rsc-mf): derive action-id map server-side for
host proxies
---
.../host/src/server-component-root/App.tsx | 33 ++++++++++++++++++-
.../HostRemoteActionRunner.tsx | 21 ++++--------
2 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 950d2cf42e7b..2a7c65d908ed 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -2,6 +2,9 @@ import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
+import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
+import { defaultRemoteAction } from 'rscRemote/defaultAction';
+import { nestedRemoteAction } from 'rscRemote/nestedActions';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
import getServerOnlyDefaultInfo from 'rscRemote/remoteServerOnlyDefault';
@@ -15,6 +18,32 @@ import {
} from './remoteActionProxy';
const App = () => {
+ const remoteActionIdToHostProxyActionId: Record = {};
+ const remoteIncrementActionId = (incrementRemoteCount as any)?.$$id;
+ const remoteEchoActionId = (remoteActionEcho as any)?.$$id;
+ const remoteNestedActionId = (nestedRemoteAction as any)?.$$id;
+ const remoteDefaultActionId = (defaultRemoteAction as any)?.$$id;
+ const proxyIncrementActionId = (proxyIncrementRemoteCount as any)?.$$id;
+ const proxyEchoActionId = (proxyRemoteActionEcho as any)?.$$id;
+ const proxyNestedActionId = (proxyNestedRemoteAction as any)?.$$id;
+ const proxyDefaultActionId = (proxyDefaultRemoteAction as any)?.$$id;
+
+ if (remoteIncrementActionId && proxyIncrementActionId) {
+ remoteActionIdToHostProxyActionId[remoteIncrementActionId] =
+ proxyIncrementActionId;
+ }
+ if (remoteEchoActionId && proxyEchoActionId) {
+ remoteActionIdToHostProxyActionId[remoteEchoActionId] = proxyEchoActionId;
+ }
+ if (remoteNestedActionId && proxyNestedActionId) {
+ remoteActionIdToHostProxyActionId[remoteNestedActionId] =
+ proxyNestedActionId;
+ }
+ if (remoteDefaultActionId && proxyDefaultActionId) {
+ remoteActionIdToHostProxyActionId[remoteDefaultActionId] =
+ proxyDefaultActionId;
+ }
+
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
const remoteMetaLabel = getRemoteMetaLabel();
@@ -41,7 +70,9 @@ const App = () => {
-
+
);
};
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index aa925d2dfb7d..50221035f94c 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -7,18 +7,11 @@ import { remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
-const REMOTE_ACTION_ID_TO_HOST_PROXY_ACTION_ID = {
- '606c30f35d74d843171a8a71358eda595991e4ee16270e9f052af3faef57a19999':
- '603cd42bd1c9b98894c6d03b3b688f513073ddbea04bb02d7fda1e72c57f96b69d',
- '40e41a2ee9d9de373b364dcf2a0201701057c8502037bf9ef2cd26bb2a1259dabd':
- '40f14c24f6d81be75aab6d9dc7941b9507bfbdb9daca25df7b1aed34703972c7ab',
- '408da81ddb8214f8cb98a83552cb70c4d17b27b6fd36d972cac89e7030a4874fd4':
- '40928b48a8dc80bb3a73661fbdbeb14155a85a1b965e9ef67a8f4132bbd4dda7e5',
- '4019f2092c5baa86ad77fc144ce69129b81c38a1a6a1cb227a138b5d46de8977d7':
- '404768f4f5d65c3edafd60e28fc1252837ade49f3b06dad341098530dea5bb7716',
-} as const;
-
-export default function HostRemoteActionRunner() {
+export default function HostRemoteActionRunner({
+ remoteActionIdToHostProxyActionId,
+}: {
+ remoteActionIdToHostProxyActionId: Record;
+}) {
// Keep this import in the client graph so federated RSC bridge IDs
// can map back to a concrete remote module factory at runtime.
void RemoteClientCounterBridge;
@@ -30,9 +23,9 @@ export default function HostRemoteActionRunner() {
registerRemoteServerCallback(
`${window.location.origin}/server-component-root`,
'rscRemote',
- REMOTE_ACTION_ID_TO_HOST_PROXY_ACTION_ID as Record,
+ remoteActionIdToHostProxyActionId,
);
- }, []);
+ }, [JSON.stringify(remoteActionIdToHostProxyActionId)]);
const runActions = async () => {
setIsPending(true);
From 2fcf0483693db374066cad387ef31d055011df2c Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 22:12:14 +0000
Subject: [PATCH 069/324] test(rsc-mf): remove transient debug logging from
integration test
---
tests/integration/rsc-mf/tests/index.test.ts | 34 --------------------
1 file changed, 34 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 64a52590db8d..16bff89c62fa 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -223,40 +223,6 @@ function runTests({ mode }: TestConfig) {
const err = error as Error;
const message = err.message;
runtimeErrors.push(message);
- // Debugging aid for flaky integration failures.
- console.log(`[pageerror:${mode}] ${message}`);
- if (err.stack) {
- console.log(`[pageerror:${mode}:stack] ${err.stack}`);
- }
- });
- page.on('console', msg => {
- if (msg.type() === 'error' || msg.text().includes('[rsc-mf]')) {
- const location = msg.location();
- const suffix = location?.url
- ? ` @ ${location.url}:${location.lineNumber}:${location.columnNumber}`
- : '';
- console.log(`[browser:${mode}] ${msg.text()}${suffix}`);
- }
- });
- page.on('response', async response => {
- if (response.status() >= 400 && response.url().includes(HOST_RSC_URL)) {
- console.log(
- `[response:${mode}] ${response.status()} ${response.url()}`,
- );
- const body = await response.text().catch(() => '');
- if (body) {
- console.log(`[response:${mode}:body] ${body}`);
- }
- }
- });
- page.on('request', request => {
- if (
- request.method() === 'POST' &&
- request.url().includes(HOST_RSC_URL)
- ) {
- const actionId = request.headers()['x-rsc-action'];
- console.log(`[request:${mode}] action=${actionId || 'missing'}`);
- }
});
});
From 830c1a198ff329e649ca7532a4272adfd6a610cb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 22:19:32 +0000
Subject: [PATCH 070/324] test(rsc-mf): simplify server action-id mapping in
host app
---
.../host/src/server-component-root/App.tsx | 50 +++++++++----------
1 file changed, 24 insertions(+), 26 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 2a7c65d908ed..4c8bb2701192 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -17,32 +17,30 @@ import {
proxyRemoteActionEcho,
} from './remoteActionProxy';
-const App = () => {
- const remoteActionIdToHostProxyActionId: Record = {};
- const remoteIncrementActionId = (incrementRemoteCount as any)?.$$id;
- const remoteEchoActionId = (remoteActionEcho as any)?.$$id;
- const remoteNestedActionId = (nestedRemoteAction as any)?.$$id;
- const remoteDefaultActionId = (defaultRemoteAction as any)?.$$id;
- const proxyIncrementActionId = (proxyIncrementRemoteCount as any)?.$$id;
- const proxyEchoActionId = (proxyRemoteActionEcho as any)?.$$id;
- const proxyNestedActionId = (proxyNestedRemoteAction as any)?.$$id;
- const proxyDefaultActionId = (proxyDefaultRemoteAction as any)?.$$id;
+const getServerActionId = (action: unknown) =>
+ (action as { $$id?: string } | undefined)?.$$id;
- if (remoteIncrementActionId && proxyIncrementActionId) {
- remoteActionIdToHostProxyActionId[remoteIncrementActionId] =
- proxyIncrementActionId;
- }
- if (remoteEchoActionId && proxyEchoActionId) {
- remoteActionIdToHostProxyActionId[remoteEchoActionId] = proxyEchoActionId;
- }
- if (remoteNestedActionId && proxyNestedActionId) {
- remoteActionIdToHostProxyActionId[remoteNestedActionId] =
- proxyNestedActionId;
- }
- if (remoteDefaultActionId && proxyDefaultActionId) {
- remoteActionIdToHostProxyActionId[remoteDefaultActionId] =
- proxyDefaultActionId;
- }
+const App = () => {
+ const remoteActionIdToHostProxyActionId = Object.fromEntries(
+ [
+ [
+ getServerActionId(incrementRemoteCount),
+ getServerActionId(proxyIncrementRemoteCount),
+ ],
+ [
+ getServerActionId(remoteActionEcho),
+ getServerActionId(proxyRemoteActionEcho),
+ ],
+ [
+ getServerActionId(nestedRemoteAction),
+ getServerActionId(proxyNestedRemoteAction),
+ ],
+ [
+ getServerActionId(defaultRemoteAction),
+ getServerActionId(proxyDefaultRemoteAction),
+ ],
+ ].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1])),
+ );
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
@@ -64,7 +62,7 @@ const App = () => {
Loading Remote RSC...}>
-
+
From 3fa1479c841f97cabcd450f79fafbcb0ec5d0da3 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 22:29:06 +0000
Subject: [PATCH 071/324] test(rsc-mf): document host proxy action mapping
intent
---
.../integration/rsc-mf/host/src/server-component-root/App.tsx | 4 ++++
.../host/src/server-component-root/HostRemoteActionRunner.tsx | 2 ++
2 files changed, 6 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 4c8bb2701192..61d006f039f0 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -21,6 +21,9 @@ const getServerActionId = (action: unknown) =>
(action as { $$id?: string } | undefined)?.$$id;
const App = () => {
+ // Map remote action IDs to host-local proxy action IDs so client-side
+ // callbacks can always post a host-resolvable action id. This keeps
+ // remote action execution in-process on the host via proxy imports.
const remoteActionIdToHostProxyActionId = Object.fromEntries(
[
[
@@ -62,6 +65,7 @@ const App = () => {
Loading Remote RSC...
}>
+ {/* Anchor host proxy actions in the server action manifest. */}
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 50221035f94c..ea6e807d40b0 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -20,6 +20,8 @@ export default function HostRemoteActionRunner({
const [isPending, setIsPending] = useState(false);
useEffect(() => {
+ // Register once with host endpoint + id mapping so remote client-side
+ // server actions are routed through host proxy actions.
registerRemoteServerCallback(
`${window.location.origin}/server-component-root`,
'rscRemote',
From cb8a21bf2d1b4915d4a0b9b6bcb3050d51659958 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:01:12 +0000
Subject: [PATCH 072/324] test(rsc-mf): expand exposure coverage for bundled
action exports
---
.../HostRemoteActionRunner.tsx | 25 +++++--
.../rsc-mf/remote/module-federation.config.ts | 4 ++
.../remote/src/components/actionBundle.ts | 6 ++
tests/integration/rsc-mf/tests/index.test.ts | 67 +++++++++++++------
4 files changed, 77 insertions(+), 25 deletions(-)
create mode 100644 tests/integration/rsc-mf/remote/src/components/actionBundle.ts
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index ea6e807d40b0..38ed89e54fad 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -3,6 +3,10 @@
import { useEffect, useState } from 'react';
import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteClientCounter as RemoteClientCounterBridge } from 'rscRemote/RemoteClientCounter';
+import {
+ bundledDefaultRemoteAction,
+ bundledRemoteActionEcho,
+} from 'rscRemote/actionBundle';
import { remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
@@ -17,6 +21,8 @@ export default function HostRemoteActionRunner({
void RemoteClientCounterBridge;
const [defaultResult, setDefaultResult] = useState('');
const [echoResult, setEchoResult] = useState('');
+ const [bundledDefaultResult, setBundledDefaultResult] = useState('');
+ const [bundledEchoResult, setBundledEchoResult] = useState('');
const [isPending, setIsPending] = useState(false);
useEffect(() => {
@@ -32,12 +38,17 @@ export default function HostRemoteActionRunner({
const runActions = async () => {
setIsPending(true);
try {
- const [defaultValue, echoValue] = await Promise.all([
- defaultRemoteAction('from-host-client'),
- remoteActionEcho('from-host-client'),
- ]);
+ const [defaultValue, echoValue, bundledDefaultValue, bundledEchoValue] =
+ await Promise.all([
+ defaultRemoteAction('from-host-client'),
+ remoteActionEcho('from-host-client'),
+ bundledDefaultRemoteAction('from-host-client-bundled'),
+ bundledRemoteActionEcho('from-host-client-bundled'),
+ ]);
setDefaultResult(defaultValue);
setEchoResult(echoValue);
+ setBundledDefaultResult(bundledDefaultValue);
+ setBundledEchoResult(bundledEchoValue);
} finally {
setIsPending(false);
}
@@ -56,6 +67,12 @@ export default function HostRemoteActionRunner({
{defaultResult}
{echoResult}
+
+ {bundledDefaultResult}
+
+
+ {bundledEchoResult}
+
);
}
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index ee50385e41df..4ef6df8aecb9 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -155,6 +155,10 @@ export default createModuleFederationConfig({
import: './src/components/defaultAction.ts',
layer: LAYERS.rsc,
} as any,
+ './actionBundle': {
+ import: './src/components/actionBundle.ts',
+ layer: LAYERS.rsc,
+ } as any,
'./registerServerCallback': {
import: './src/components/registerServerCallback.ts',
layer: LAYERS.rsc,
diff --git a/tests/integration/rsc-mf/remote/src/components/actionBundle.ts b/tests/integration/rsc-mf/remote/src/components/actionBundle.ts
new file mode 100644
index 000000000000..596e1df4087d
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/actionBundle.ts
@@ -0,0 +1,6 @@
+export {
+ incrementRemoteCount as bundledIncrementRemoteCount,
+ remoteActionEcho as bundledRemoteActionEcho,
+} from './actions';
+export { defaultRemoteAction as bundledDefaultRemoteAction } from './defaultAction';
+export { nestedRemoteAction as bundledNestedRemoteAction } from './nestedActions';
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 16bff89c62fa..914663e4f468 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -98,40 +98,52 @@ async function supportRemoteClientAndServerActions({
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
});
- await page.waitForSelector('.remote-client-local-increment');
+ await page.waitForSelector(
+ '.host-remote-action-runner .remote-client-local-increment',
+ );
- let localCount = await page.$eval('.remote-client-local-count', el =>
- el.textContent?.trim(),
+ let localCount = await page.$eval(
+ '.host-remote-action-runner .remote-client-local-count',
+ el => el.textContent?.trim(),
);
- let serverCount = await page.$eval('.remote-client-server-count', el =>
- el.textContent?.trim(),
+ let serverCount = await page.$eval(
+ '.host-remote-action-runner .remote-client-server-count',
+ el => el.textContent?.trim(),
);
expect(localCount).toBe('0');
expect(serverCount).toBe('0');
- await page.click('.remote-client-local-increment');
- localCount = await page.$eval('.remote-client-local-count', el =>
- el.textContent?.trim(),
+ await page.click('.host-remote-action-runner .remote-client-local-increment');
+ localCount = await page.$eval(
+ '.host-remote-action-runner .remote-client-local-count',
+ el => el.textContent?.trim(),
);
expect(localCount).toBe('1');
- await page.click('.remote-client-server-increment');
+ await page.click(
+ '.host-remote-action-runner .remote-client-server-increment',
+ );
await page.waitForFunction(
() =>
!document
- .querySelector('.remote-client-server-increment')
+ .querySelector(
+ '.host-remote-action-runner .remote-client-server-increment',
+ )
?.hasAttribute('disabled'),
);
- serverCount = await page.$eval('.remote-client-server-count', el =>
- el.textContent?.trim(),
+ serverCount = await page.$eval(
+ '.host-remote-action-runner .remote-client-server-count',
+ el => el.textContent?.trim(),
);
expect(serverCount).toBe('1');
- await page.click('.remote-client-run-actions');
+ await page.click('.host-remote-action-runner .remote-client-run-actions');
await page.waitForFunction(() => {
- const nested = document.querySelector('.remote-client-nested-result');
+ const nested = document.querySelector(
+ '.host-remote-action-runner .remote-client-nested-result',
+ );
const remoteAction = document.querySelector(
- '.remote-client-remote-action-result',
+ '.host-remote-action-runner .remote-client-remote-action-result',
);
return (
nested?.textContent?.trim() === 'nested-action:from-client' &&
@@ -139,13 +151,15 @@ async function supportRemoteClientAndServerActions({
);
});
- let badgeValue = await page.$eval('.remote-client-badge-value', el =>
- el.textContent?.trim(),
+ let badgeValue = await page.$eval(
+ '.host-remote-action-runner .remote-client-badge-value',
+ el => el.textContent?.trim(),
);
expect(badgeValue).toBe('remote-client-badge-initial');
- await page.click('.remote-client-badge-toggle');
- badgeValue = await page.$eval('.remote-client-badge-value', el =>
- el.textContent?.trim(),
+ await page.click('.host-remote-action-runner .remote-client-badge-toggle');
+ badgeValue = await page.$eval(
+ '.host-remote-action-runner .remote-client-badge-value',
+ el => el.textContent?.trim(),
);
expect(badgeValue).toBe('remote-client-badge-toggled');
@@ -157,10 +171,21 @@ async function supportRemoteClientAndServerActions({
const echoActionResult = document.querySelector(
'.host-remote-echo-action-result',
);
+ const bundledDefaultActionResult = document.querySelector(
+ '.host-remote-bundled-default-action-result',
+ );
+ const bundledEchoActionResult = document.querySelector(
+ '.host-remote-bundled-echo-action-result',
+ );
return (
defaultActionResult?.textContent?.trim() ===
'default-action:from-host-client' &&
- echoActionResult?.textContent?.trim() === 'remote-action:from-host-client'
+ echoActionResult?.textContent?.trim() ===
+ 'remote-action:from-host-client' &&
+ bundledDefaultActionResult?.textContent?.trim() ===
+ 'default-action:from-host-client-bundled' &&
+ bundledEchoActionResult?.textContent?.trim() ===
+ 'remote-action:from-host-client-bundled'
);
});
}
From 77b3b26ebd0e83057600835def04eeb9e4c36796 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:08:18 +0000
Subject: [PATCH 073/324] test(rsc-mf): add bundled server-info expose coverage
---
.../host/src/server-component-root/App.tsx | 15 ++++++++++++
.../rsc-mf/remote/module-federation.config.ts | 4 ++++
.../remote/src/components/infoBundle.ts | 6 +++++
tests/integration/rsc-mf/tests/index.test.ts | 24 +++++++++++++++++++
4 files changed, 49 insertions(+)
create mode 100644 tests/integration/rsc-mf/remote/src/components/infoBundle.ts
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 61d006f039f0..47f1a2864099 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -4,6 +4,12 @@ import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
+import {
+ bundledRemoteMeta,
+ getBundledRemoteMetaLabel,
+ getBundledServerOnlyDefaultInfo,
+ getBundledServerOnlyInfo,
+} from 'rscRemote/infoBundle';
import { nestedRemoteAction } from 'rscRemote/nestedActions';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
@@ -48,6 +54,9 @@ const App = () => {
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
const remoteMetaLabel = getRemoteMetaLabel();
+ const bundledServerOnlyInfo = getBundledServerOnlyInfo();
+ const bundledServerOnlyDefaultInfo = getBundledServerOnlyDefaultInfo();
+ const bundledRemoteMetaLabel = getBundledRemoteMetaLabel();
return (
@@ -58,6 +67,12 @@ const App = () => {
{remoteMeta.kind}
{remoteMetaLabel}
+
{bundledServerOnlyInfo}
+
+ {bundledServerOnlyDefaultInfo}
+
+
{bundledRemoteMeta.kind}
+
{bundledRemoteMetaLabel}
Loading Remote Async Server Info... }>
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 4ef6df8aecb9..8c2a687d83f6 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -159,6 +159,10 @@ export default createModuleFederationConfig({
import: './src/components/actionBundle.ts',
layer: LAYERS.rsc,
} as any,
+ './infoBundle': {
+ import: './src/components/infoBundle.ts',
+ layer: LAYERS.rsc,
+ } as any,
'./registerServerCallback': {
import: './src/components/registerServerCallback.ts',
layer: LAYERS.rsc,
diff --git a/tests/integration/rsc-mf/remote/src/components/infoBundle.ts b/tests/integration/rsc-mf/remote/src/components/infoBundle.ts
new file mode 100644
index 000000000000..a6a5a1811abe
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/infoBundle.ts
@@ -0,0 +1,6 @@
+export { getServerOnlyInfo as getBundledServerOnlyInfo } from './serverOnly';
+export { default as getBundledServerOnlyDefaultInfo } from './serverOnlyDefault';
+export {
+ default as bundledRemoteMeta,
+ getRemoteMetaLabel as getBundledRemoteMetaLabel,
+} from './remoteMeta';
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 914663e4f468..19c035ff7962 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -62,6 +62,8 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('rsc|mf|actions');
expect(html).toContain('remote-async-server-info-ok');
expect(html).toContain('Remote Default Server Card');
+ expect(html).toContain('host-remote-bundled-server-only');
+ expect(html).toContain('host-remote-bundled-meta-kind');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -84,6 +86,28 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el.textContent?.trim(),
);
expect(hostRemoteMetaLabel).toBe('rsc|mf|actions');
+ const hostRemoteBundledServerOnly = await page.$eval(
+ '.host-remote-bundled-server-only',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteBundledServerOnly).toBe('remote-server-only-ok');
+ const hostRemoteBundledServerOnlyDefault = await page.$eval(
+ '.host-remote-bundled-server-only-default',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteBundledServerOnlyDefault).toBe(
+ 'remote-server-only-default-ok',
+ );
+ const hostRemoteBundledMetaKind = await page.$eval(
+ '.host-remote-bundled-meta-kind',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteBundledMetaKind).toBe('remote-meta-default');
+ const hostRemoteBundledMetaLabel = await page.$eval(
+ '.host-remote-bundled-meta-label',
+ el => el.textContent?.trim(),
+ );
+ expect(hostRemoteBundledMetaLabel).toBe('rsc|mf|actions');
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
From e5c6575037138fc11fbb2e91553f5fc7ad838bff Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:16:33 +0000
Subject: [PATCH 074/324] test(rsc-mf): map bundled action re-export ids to
host proxies
---
.../host/src/server-component-root/App.tsx | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 47f1a2864099..3e7a7ad98b0d 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -2,6 +2,12 @@ import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
+import {
+ bundledDefaultRemoteAction,
+ bundledIncrementRemoteCount,
+ bundledNestedRemoteAction,
+ bundledRemoteActionEcho,
+} from 'rscRemote/actionBundle';
import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
import {
@@ -48,6 +54,22 @@ const App = () => {
getServerActionId(defaultRemoteAction),
getServerActionId(proxyDefaultRemoteAction),
],
+ [
+ getServerActionId(bundledIncrementRemoteCount),
+ getServerActionId(proxyIncrementRemoteCount),
+ ],
+ [
+ getServerActionId(bundledRemoteActionEcho),
+ getServerActionId(proxyRemoteActionEcho),
+ ],
+ [
+ getServerActionId(bundledNestedRemoteAction),
+ getServerActionId(proxyNestedRemoteAction),
+ ],
+ [
+ getServerActionId(bundledDefaultRemoteAction),
+ getServerActionId(proxyDefaultRemoteAction),
+ ],
].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1])),
);
From d680e23b4fd3ad84fa72c26d2a48f88f7240d34f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:19:54 +0000
Subject: [PATCH 075/324] refactor(rsc-mf): remove remote chunk text patching
middleware
---
.../rsc-mf/host/server/modern.server.ts | 38 -------------------
1 file changed, 38 deletions(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index 56827ed52ce1..205dc82a6c87 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -19,18 +19,6 @@ const shouldProxyRemoteAsset = (pathname: string) => {
return false;
};
-const REMOTE_COUNTER_ALIAS_MODULES = [
- 'remote-module:rscRemote:./src/components/RemoteClientCounter.tsx',
- 'remote-module:rscRemote:./RemoteClientCounter',
- 'remote-module:rscRemote:./RemoteClientCounter.tsx',
-];
-const REMOTE_COUNTER_SOURCE_MODULE = './src/components/RemoteClientCounter.tsx';
-const createRemoteNestedMixedAliasChunk = () =>
- `\n;(globalThis["chunk_rscHost"] = globalThis["chunk_rscHost"] || []).push([["__federation_expose_RemoteNestedMixed_alias"],{${REMOTE_COUNTER_ALIAS_MODULES.map(
- aliasModule =>
- `"${aliasModule}":function(module,__unused,__webpack_require__){module.exports=__webpack_require__("${REMOTE_COUNTER_SOURCE_MODULE}");}`,
- ).join(',')}}]);`;
-
const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
const reqUrl = new URL(c.req.url);
const pathname = reqUrl.pathname;
@@ -54,32 +42,6 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
return;
}
- const shouldPatchCounterAlias =
- pathname.startsWith('/static/js/async/__federation_expose_') &&
- pathname.endsWith('.js');
- if (shouldPatchCounterAlias) {
- let chunkText = await upstream.text();
- if (!chunkText.includes('remote-client-server-count')) {
- c.res = new Response(chunkText, {
- status: upstream.status,
- headers: {
- 'content-type': 'application/javascript; charset=utf-8',
- },
- });
- return;
- }
-
- chunkText = `${chunkText}${createRemoteNestedMixedAliasChunk()}`;
-
- c.res = new Response(chunkText, {
- status: upstream.status,
- headers: {
- 'content-type': 'application/javascript; charset=utf-8',
- },
- });
- return;
- }
-
c.res = new Response(await upstream.arrayBuffer(), {
status: upstream.status,
headers: upstream.headers,
From 92f8e4e5f9ae791a0c4bfd01803018fad05bcb3d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:27:20 +0000
Subject: [PATCH 076/324] test(rsc-mf): assert no browser runtime errors in dev
mode
---
tests/integration/rsc-mf/tests/index.test.ts | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 19c035ff7962..d8761051c835 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -293,11 +293,9 @@ function runTests({ mode }: TestConfig) {
it('should support remote use client and server actions', () =>
supportRemoteClientAndServerActions({ hostPort, page }));
- if (mode === 'build') {
- it('should have no browser runtime errors', () => {
- expect(runtimeErrors).toEqual([]);
- });
- }
+ it('should have no browser runtime errors', () => {
+ expect(runtimeErrors).toEqual([]);
+ });
});
}
From a1d8490397fc8ae8983b729b24871fb9de972176 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:29:43 +0000
Subject: [PATCH 077/324] test(rsc-mf): assert action posts stay on host
endpoint
---
tests/integration/rsc-mf/tests/index.test.ts | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index d8761051c835..87109825ff0a 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -223,6 +223,7 @@ function runTests({ mode }: TestConfig) {
let page: Page;
let browser: Browser;
const runtimeErrors: string[] = [];
+ const actionRequestUrls: string[] = [];
if (skipForLowerNodeVersion()) {
return;
@@ -273,6 +274,14 @@ function runTests({ mode }: TestConfig) {
const message = err.message;
runtimeErrors.push(message);
});
+
+ page.on('request', request => {
+ const headers = request.headers();
+ if (request.method() !== 'POST' || !headers['x-rsc-action']) {
+ return;
+ }
+ actionRequestUrls.push(request.url());
+ });
});
afterAll(async () => {
@@ -293,6 +302,15 @@ function runTests({ mode }: TestConfig) {
it('should support remote use client and server actions', () =>
supportRemoteClientAndServerActions({ hostPort, page }));
+ it('should route remote actions through host endpoint', () => {
+ expect(actionRequestUrls.length).toBeGreaterThan(0);
+ expect(
+ actionRequestUrls.every(url =>
+ url.startsWith(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`),
+ ),
+ ).toBe(true);
+ });
+
it('should have no browser runtime errors', () => {
expect(runtimeErrors).toEqual([]);
});
From 0f0ca8ee868fe4671b53a13ac2aac5b4e26feeb5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:30:45 +0000
Subject: [PATCH 078/324] refactor(rsc-mf): drop remote client
chunkLoadingGlobal override
---
tests/integration/rsc-mf/remote/modern.config.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/modern.config.ts b/tests/integration/rsc-mf/remote/modern.config.ts
index 8d61903ce6b5..a0fd50dd1597 100644
--- a/tests/integration/rsc-mf/remote/modern.config.ts
+++ b/tests/integration/rsc-mf/remote/modern.config.ts
@@ -65,7 +65,6 @@ export default defineConfig({
.layer('react-server-components');
} else {
chain.optimization.splitChunks(false);
- chain.output.chunkLoadingGlobal('chunk_rscHost');
chain.output.publicPath(`http://127.0.0.1:${remotePort}/`);
}
From e75f56ec7d4f88847e2df59b5777d3f32d4fd5c8 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:32:18 +0000
Subject: [PATCH 079/324] refactor(rsc-mf): consume bundled action expose via
namespace import
---
.../HostRemoteActionRunner.tsx | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 38ed89e54fad..fbec4c680e72 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -3,10 +3,7 @@
import { useEffect, useState } from 'react';
import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteClientCounter as RemoteClientCounterBridge } from 'rscRemote/RemoteClientCounter';
-import {
- bundledDefaultRemoteAction,
- bundledRemoteActionEcho,
-} from 'rscRemote/actionBundle';
+import * as remoteActionBundle from 'rscRemote/actionBundle';
import { remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
@@ -42,8 +39,12 @@ export default function HostRemoteActionRunner({
await Promise.all([
defaultRemoteAction('from-host-client'),
remoteActionEcho('from-host-client'),
- bundledDefaultRemoteAction('from-host-client-bundled'),
- bundledRemoteActionEcho('from-host-client-bundled'),
+ remoteActionBundle.bundledDefaultRemoteAction(
+ 'from-host-client-bundled',
+ ),
+ remoteActionBundle.bundledRemoteActionEcho(
+ 'from-host-client-bundled',
+ ),
]);
setDefaultResult(defaultValue);
setEchoResult(echoValue);
From 336d821cf4137d62af056bd333b34f6c53c1d3eb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:34:09 +0000
Subject: [PATCH 080/324] test(rsc-mf): assert action posts avoid remote origin
---
tests/integration/rsc-mf/tests/index.test.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 87109825ff0a..b0d51e9a915c 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -309,6 +309,11 @@ function runTests({ mode }: TestConfig) {
url.startsWith(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`),
),
).toBe(true);
+ expect(
+ actionRequestUrls.every(
+ url => !url.startsWith(`http://127.0.0.1:${remotePort}`),
+ ),
+ ).toBe(true);
});
it('should have no browser runtime errors', () => {
From 6c194520ab32e408c63a759a9dc3f08c14d364c5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:38:32 +0000
Subject: [PATCH 081/324] test(rsc-mf): assert host-resolvable x-rsc-action ids
---
tests/integration/rsc-mf/tests/index.test.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b0d51e9a915c..c8db9ce34826 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -224,6 +224,7 @@ function runTests({ mode }: TestConfig) {
let browser: Browser;
const runtimeErrors: string[] = [];
const actionRequestUrls: string[] = [];
+ const actionRequestIds: string[] = [];
if (skipForLowerNodeVersion()) {
return;
@@ -281,6 +282,7 @@ function runTests({ mode }: TestConfig) {
return;
}
actionRequestUrls.push(request.url());
+ actionRequestIds.push(headers['x-rsc-action']);
});
});
@@ -316,6 +318,17 @@ function runTests({ mode }: TestConfig) {
).toBe(true);
});
+ it('should post host-resolvable action ids for remote actions', () => {
+ expect(actionRequestIds.length).toBeGreaterThan(0);
+ expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
+ true,
+ );
+ expect(actionRequestIds.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
+ true,
+ );
+ expect(new Set(actionRequestIds).size).toBeGreaterThanOrEqual(4);
+ });
+
it('should have no browser runtime errors', () => {
expect(runtimeErrors).toEqual([]);
});
From ed0f9f5c1552ab37dbc5c8366b516a94775ab3d6 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:41:04 +0000
Subject: [PATCH 082/324] refactor(rsc-mf): use namespace imports in host
server bundle coverage
---
.../host/src/server-component-root/App.tsx | 33 ++++++++-----------
1 file changed, 13 insertions(+), 20 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 3e7a7ad98b0d..f68642ded67a 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -2,20 +2,10 @@ import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
-import {
- bundledDefaultRemoteAction,
- bundledIncrementRemoteCount,
- bundledNestedRemoteAction,
- bundledRemoteActionEcho,
-} from 'rscRemote/actionBundle';
+import * as remoteActionBundle from 'rscRemote/actionBundle';
import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
-import {
- bundledRemoteMeta,
- getBundledRemoteMetaLabel,
- getBundledServerOnlyDefaultInfo,
- getBundledServerOnlyInfo,
-} from 'rscRemote/infoBundle';
+import * as remoteInfoBundle from 'rscRemote/infoBundle';
import { nestedRemoteAction } from 'rscRemote/nestedActions';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
@@ -55,19 +45,19 @@ const App = () => {
getServerActionId(proxyDefaultRemoteAction),
],
[
- getServerActionId(bundledIncrementRemoteCount),
+ getServerActionId(remoteActionBundle.bundledIncrementRemoteCount),
getServerActionId(proxyIncrementRemoteCount),
],
[
- getServerActionId(bundledRemoteActionEcho),
+ getServerActionId(remoteActionBundle.bundledRemoteActionEcho),
getServerActionId(proxyRemoteActionEcho),
],
[
- getServerActionId(bundledNestedRemoteAction),
+ getServerActionId(remoteActionBundle.bundledNestedRemoteAction),
getServerActionId(proxyNestedRemoteAction),
],
[
- getServerActionId(bundledDefaultRemoteAction),
+ getServerActionId(remoteActionBundle.bundledDefaultRemoteAction),
getServerActionId(proxyDefaultRemoteAction),
],
].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1])),
@@ -76,9 +66,10 @@ const App = () => {
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
const remoteMetaLabel = getRemoteMetaLabel();
- const bundledServerOnlyInfo = getBundledServerOnlyInfo();
- const bundledServerOnlyDefaultInfo = getBundledServerOnlyDefaultInfo();
- const bundledRemoteMetaLabel = getBundledRemoteMetaLabel();
+ const bundledServerOnlyInfo = remoteInfoBundle.getBundledServerOnlyInfo();
+ const bundledServerOnlyDefaultInfo =
+ remoteInfoBundle.getBundledServerOnlyDefaultInfo();
+ const bundledRemoteMetaLabel = remoteInfoBundle.getBundledRemoteMetaLabel();
return (
@@ -93,7 +84,9 @@ const App = () => {
{bundledServerOnlyDefaultInfo}
-
{bundledRemoteMeta.kind}
+
+ {remoteInfoBundle.bundledRemoteMeta.kind}
+
{bundledRemoteMetaLabel}
Loading Remote Async Server Info... }>
From a40bae2dfc6f999cd8655ddf232f0590e4a0d3c7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:44:20 +0000
Subject: [PATCH 083/324] refactor(rsc-mf): route host proxy actions through
bundled expose imports
---
.../host/src/server-component-root/App.tsx | 16 +++++++++----
.../remoteActionProxy.ts | 23 +++++++++++++++++++
2 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index f68642ded67a..cf059a22cfc8 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -13,6 +13,10 @@ import getServerOnlyDefaultInfo from 'rscRemote/remoteServerOnlyDefault';
import styles from './App.module.less';
import HostRemoteActionRunner from './HostRemoteActionRunner';
import {
+ proxyBundledDefaultRemoteAction,
+ proxyBundledIncrementRemoteCount,
+ proxyBundledNestedRemoteAction,
+ proxyBundledRemoteActionEcho,
proxyDefaultRemoteAction,
proxyIncrementRemoteCount,
proxyNestedRemoteAction,
@@ -46,19 +50,19 @@ const App = () => {
],
[
getServerActionId(remoteActionBundle.bundledIncrementRemoteCount),
- getServerActionId(proxyIncrementRemoteCount),
+ getServerActionId(proxyBundledIncrementRemoteCount),
],
[
getServerActionId(remoteActionBundle.bundledRemoteActionEcho),
- getServerActionId(proxyRemoteActionEcho),
+ getServerActionId(proxyBundledRemoteActionEcho),
],
[
getServerActionId(remoteActionBundle.bundledNestedRemoteAction),
- getServerActionId(proxyNestedRemoteAction),
+ getServerActionId(proxyBundledNestedRemoteAction),
],
[
getServerActionId(remoteActionBundle.bundledDefaultRemoteAction),
- getServerActionId(proxyDefaultRemoteAction),
+ getServerActionId(proxyBundledDefaultRemoteAction),
],
].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1])),
);
@@ -101,6 +105,10 @@ const App = () => {
+
+
+
+
Date: Fri, 13 Feb 2026 23:47:24 +0000
Subject: [PATCH 084/324] test(rsc-mf): assert host proxy action manifest
coverage
---
.../rsc-mf/host/src/server-component-root/App.tsx | 15 +++++++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 6 ++++++
2 files changed, 21 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index cf059a22cfc8..c4740fbae801 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -27,6 +27,18 @@ const getServerActionId = (action: unknown) =>
(action as { $$id?: string } | undefined)?.$$id;
const App = () => {
+ const hostProxyActionIds = [
+ getServerActionId(proxyIncrementRemoteCount),
+ getServerActionId(proxyRemoteActionEcho),
+ getServerActionId(proxyNestedRemoteAction),
+ getServerActionId(proxyDefaultRemoteAction),
+ getServerActionId(proxyBundledIncrementRemoteCount),
+ getServerActionId(proxyBundledRemoteActionEcho),
+ getServerActionId(proxyBundledNestedRemoteAction),
+ getServerActionId(proxyBundledDefaultRemoteAction),
+ ].filter((actionId): actionId is string => Boolean(actionId));
+ const uniqueHostProxyActionIdsCount = new Set(hostProxyActionIds).size;
+
// Map remote action IDs to host-local proxy action IDs so client-side
// callbacks can always post a host-resolvable action id. This keeps
// remote action execution in-process on the host via proxy imports.
@@ -92,6 +104,9 @@ const App = () => {
{remoteInfoBundle.bundledRemoteMeta.kind}
{bundledRemoteMetaLabel}
+
+ {uniqueHostProxyActionIdsCount}
+
Loading Remote Async Server Info...}>
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index c8db9ce34826..9137ee8c55a9 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -64,6 +64,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('Remote Default Server Card');
expect(html).toContain('host-remote-bundled-server-only');
expect(html).toContain('host-remote-bundled-meta-kind');
+ expect(html).toContain('host-proxy-action-id-count');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -108,6 +109,11 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostRemoteBundledMetaLabel).toBe('rsc|mf|actions');
+ const hostProxyActionIdCount = await page.$eval(
+ '.host-proxy-action-id-count',
+ el => el.textContent?.trim(),
+ );
+ expect(hostProxyActionIdCount).toBe('8');
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
From cf1e7fb003136269b0e028abc9a22b68d28deab5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Fri, 13 Feb 2026 23:51:04 +0000
Subject: [PATCH 085/324] test(rsc-mf): cover bundled nested and increment host
actions
---
.../HostRemoteActionRunner.tsx | 45 ++++++++++++++-----
tests/integration/rsc-mf/tests/index.test.ts | 11 ++++-
2 files changed, 44 insertions(+), 12 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index fbec4c680e72..437c4892f005 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -20,6 +20,8 @@ export default function HostRemoteActionRunner({
const [echoResult, setEchoResult] = useState('');
const [bundledDefaultResult, setBundledDefaultResult] = useState('');
const [bundledEchoResult, setBundledEchoResult] = useState('');
+ const [bundledNestedResult, setBundledNestedResult] = useState('');
+ const [bundledIncrementResult, setBundledIncrementResult] = useState('');
const [isPending, setIsPending] = useState(false);
useEffect(() => {
@@ -35,21 +37,36 @@ export default function HostRemoteActionRunner({
const runActions = async () => {
setIsPending(true);
try {
- const [defaultValue, echoValue, bundledDefaultValue, bundledEchoValue] =
- await Promise.all([
- defaultRemoteAction('from-host-client'),
- remoteActionEcho('from-host-client'),
- remoteActionBundle.bundledDefaultRemoteAction(
- 'from-host-client-bundled',
- ),
- remoteActionBundle.bundledRemoteActionEcho(
- 'from-host-client-bundled',
- ),
- ]);
+ const bundledIncrementFormData = new FormData();
+ bundledIncrementFormData.set('count', '1');
+ const [
+ defaultValue,
+ echoValue,
+ bundledDefaultValue,
+ bundledEchoValue,
+ bundledNestedValue,
+ bundledIncrementValue,
+ ] = await Promise.all([
+ defaultRemoteAction('from-host-client'),
+ remoteActionEcho('from-host-client'),
+ remoteActionBundle.bundledDefaultRemoteAction(
+ 'from-host-client-bundled',
+ ),
+ remoteActionBundle.bundledRemoteActionEcho('from-host-client-bundled'),
+ remoteActionBundle.bundledNestedRemoteAction(
+ 'from-host-client-bundled',
+ ),
+ remoteActionBundle.bundledIncrementRemoteCount(
+ 0,
+ bundledIncrementFormData,
+ ),
+ ]);
setDefaultResult(defaultValue);
setEchoResult(echoValue);
setBundledDefaultResult(bundledDefaultValue);
setBundledEchoResult(bundledEchoValue);
+ setBundledNestedResult(bundledNestedValue);
+ setBundledIncrementResult(String(bundledIncrementValue));
} finally {
setIsPending(false);
}
@@ -74,6 +91,12 @@ export default function HostRemoteActionRunner({
{bundledEchoResult}
+
+ {bundledNestedResult}
+
+
+ {bundledIncrementResult}
+
);
}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 9137ee8c55a9..e8c9581d89e1 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -207,6 +207,12 @@ async function supportRemoteClientAndServerActions({
const bundledEchoActionResult = document.querySelector(
'.host-remote-bundled-echo-action-result',
);
+ const bundledNestedActionResult = document.querySelector(
+ '.host-remote-bundled-nested-action-result',
+ );
+ const bundledIncrementActionResult = document.querySelector(
+ '.host-remote-bundled-increment-action-result',
+ );
return (
defaultActionResult?.textContent?.trim() ===
'default-action:from-host-client' &&
@@ -215,7 +221,10 @@ async function supportRemoteClientAndServerActions({
bundledDefaultActionResult?.textContent?.trim() ===
'default-action:from-host-client-bundled' &&
bundledEchoActionResult?.textContent?.trim() ===
- 'remote-action:from-host-client-bundled'
+ 'remote-action:from-host-client-bundled' &&
+ bundledNestedActionResult?.textContent?.trim() ===
+ 'nested-action:from-host-client-bundled' &&
+ bundledIncrementActionResult?.textContent?.trim() === '2'
);
});
}
From 6871db71414bb38e8195141c7cf767b3e132e21d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:10:02 +0000
Subject: [PATCH 086/324] refactor(rsc-mf): stabilize remote callback
registration keying
---
.../remote/src/components/registerServerCallback.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
index 720891760029..1ca1b6e65cb1 100644
--- a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
@@ -6,6 +6,13 @@ import {
} from 'rsc-mf-react-server-dom-client-browser';
let registeredCallbackKey = '';
+const getStableProxyActionIdEntries = (
+ remoteActionIdToHostProxyActionId?: Record,
+) =>
+ Object.entries(remoteActionIdToHostProxyActionId ?? {}).sort(
+ ([left], [right]) => left.localeCompare(right),
+ );
+
const getHostActionId = (rawActionId: string, remoteAlias: string) => {
if (rawActionId.startsWith('remote:')) {
return rawActionId;
@@ -25,7 +32,9 @@ export function registerRemoteServerCallback(
const callbackKey = JSON.stringify({
remoteAlias,
remoteOrigin,
- remoteActionIdToHostProxyActionId,
+ remoteActionIdToHostProxyActionId: getStableProxyActionIdEntries(
+ remoteActionIdToHostProxyActionId,
+ ),
});
if (registeredCallbackKey === callbackKey) {
return;
From 051929d0605c3baf77eea728462d7cc2e240de7c Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:12:48 +0000
Subject: [PATCH 087/324] refactor(rsc-mf): avoid client stringify in callback
dependency
---
.../host/src/server-component-root/App.tsx | 73 ++++++++++---------
.../HostRemoteActionRunner.tsx | 4 +-
2 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index c4740fbae801..c443f8b47823 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -42,41 +42,45 @@ const App = () => {
// Map remote action IDs to host-local proxy action IDs so client-side
// callbacks can always post a host-resolvable action id. This keeps
// remote action execution in-process on the host via proxy imports.
- const remoteActionIdToHostProxyActionId = Object.fromEntries(
+ const remoteActionIdToHostProxyActionEntries = [
+ [
+ getServerActionId(incrementRemoteCount),
+ getServerActionId(proxyIncrementRemoteCount),
+ ],
+ [
+ getServerActionId(remoteActionEcho),
+ getServerActionId(proxyRemoteActionEcho),
+ ],
+ [
+ getServerActionId(nestedRemoteAction),
+ getServerActionId(proxyNestedRemoteAction),
+ ],
+ [
+ getServerActionId(defaultRemoteAction),
+ getServerActionId(proxyDefaultRemoteAction),
+ ],
[
- [
- getServerActionId(incrementRemoteCount),
- getServerActionId(proxyIncrementRemoteCount),
- ],
- [
- getServerActionId(remoteActionEcho),
- getServerActionId(proxyRemoteActionEcho),
- ],
- [
- getServerActionId(nestedRemoteAction),
- getServerActionId(proxyNestedRemoteAction),
- ],
- [
- getServerActionId(defaultRemoteAction),
- getServerActionId(proxyDefaultRemoteAction),
- ],
- [
- getServerActionId(remoteActionBundle.bundledIncrementRemoteCount),
- getServerActionId(proxyBundledIncrementRemoteCount),
- ],
- [
- getServerActionId(remoteActionBundle.bundledRemoteActionEcho),
- getServerActionId(proxyBundledRemoteActionEcho),
- ],
- [
- getServerActionId(remoteActionBundle.bundledNestedRemoteAction),
- getServerActionId(proxyBundledNestedRemoteAction),
- ],
- [
- getServerActionId(remoteActionBundle.bundledDefaultRemoteAction),
- getServerActionId(proxyBundledDefaultRemoteAction),
- ],
- ].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1])),
+ getServerActionId(remoteActionBundle.bundledIncrementRemoteCount),
+ getServerActionId(proxyBundledIncrementRemoteCount),
+ ],
+ [
+ getServerActionId(remoteActionBundle.bundledRemoteActionEcho),
+ getServerActionId(proxyBundledRemoteActionEcho),
+ ],
+ [
+ getServerActionId(remoteActionBundle.bundledNestedRemoteAction),
+ getServerActionId(proxyBundledNestedRemoteAction),
+ ],
+ [
+ getServerActionId(remoteActionBundle.bundledDefaultRemoteAction),
+ getServerActionId(proxyBundledDefaultRemoteAction),
+ ],
+ ].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1]));
+ const remoteActionIdToHostProxyActionId = Object.fromEntries(
+ remoteActionIdToHostProxyActionEntries,
+ );
+ const remoteActionIdMapKey = JSON.stringify(
+ remoteActionIdToHostProxyActionEntries,
);
const remoteServerOnlyInfo = getServerOnlyInfo();
@@ -126,6 +130,7 @@ const App = () => {
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 437c4892f005..5b97e718fe58 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -9,8 +9,10 @@ import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
export default function HostRemoteActionRunner({
+ remoteActionIdMapKey,
remoteActionIdToHostProxyActionId,
}: {
+ remoteActionIdMapKey: string;
remoteActionIdToHostProxyActionId: Record;
}) {
// Keep this import in the client graph so federated RSC bridge IDs
@@ -32,7 +34,7 @@ export default function HostRemoteActionRunner({
'rscRemote',
remoteActionIdToHostProxyActionId,
);
- }, [JSON.stringify(remoteActionIdToHostProxyActionId)]);
+ }, [remoteActionIdMapKey]);
const runActions = async () => {
setIsPending(true);
From 6cb557435bd74f7715759918c4be55e7570e49f4 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:16:51 +0000
Subject: [PATCH 088/324] test(rsc-mf): assert posted action ids match host
proxy set
---
.../rsc-mf/host/src/server-component-root/App.tsx | 8 +++++++-
tests/integration/rsc-mf/tests/index.test.ts | 15 ++++++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index c443f8b47823..8e227e7cb085 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -37,7 +37,10 @@ const App = () => {
getServerActionId(proxyBundledNestedRemoteAction),
getServerActionId(proxyBundledDefaultRemoteAction),
].filter((actionId): actionId is string => Boolean(actionId));
- const uniqueHostProxyActionIdsCount = new Set(hostProxyActionIds).size;
+ const uniqueHostProxyActionIds = Array.from(
+ new Set(hostProxyActionIds),
+ ).sort();
+ const uniqueHostProxyActionIdsCount = uniqueHostProxyActionIds.length;
// Map remote action IDs to host-local proxy action IDs so client-side
// callbacks can always post a host-resolvable action id. This keeps
@@ -111,6 +114,9 @@ const App = () => {
{uniqueHostProxyActionIdsCount}
+
+ {uniqueHostProxyActionIds.join(',')}
+
Loading Remote Async Server Info...}>
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index e8c9581d89e1..2d2b1f999e85 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -65,6 +65,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-remote-bundled-server-only');
expect(html).toContain('host-remote-bundled-meta-kind');
expect(html).toContain('host-proxy-action-id-count');
+ expect(html).toContain('host-proxy-action-ids');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -114,6 +115,10 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostProxyActionIdCount).toBe('8');
+ const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
+ el.textContent?.trim(),
+ );
+ expect(hostProxyActionIds?.split(',').filter(Boolean).length).toBe(8);
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
@@ -333,7 +338,7 @@ function runTests({ mode }: TestConfig) {
).toBe(true);
});
- it('should post host-resolvable action ids for remote actions', () => {
+ it('should post host-resolvable action ids for remote actions', async () => {
expect(actionRequestIds.length).toBeGreaterThan(0);
expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
true,
@@ -342,6 +347,14 @@ function runTests({ mode }: TestConfig) {
true,
);
expect(new Set(actionRequestIds).size).toBeGreaterThanOrEqual(4);
+ const hostProxyActionIdSet = new Set(
+ (await page.$eval('.host-proxy-action-ids', el => el.textContent || ''))
+ .split(',')
+ .filter(Boolean),
+ );
+ expect(actionRequestIds.every(id => hostProxyActionIdSet.has(id))).toBe(
+ true,
+ );
});
it('should have no browser runtime errors', () => {
From 76ec2292496b47130569be204185d8f6f3a8e80b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:20:15 +0000
Subject: [PATCH 089/324] refactor(rsc-mf): centralize host proxy mapping and
manifest forms
---
.../host/src/server-component-root/App.tsx | 89 +++++++++----------
1 file changed, 41 insertions(+), 48 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 8e227e7cb085..480ef480471c 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -27,16 +27,19 @@ const getServerActionId = (action: unknown) =>
(action as { $$id?: string } | undefined)?.$$id;
const App = () => {
- const hostProxyActionIds = [
- getServerActionId(proxyIncrementRemoteCount),
- getServerActionId(proxyRemoteActionEcho),
- getServerActionId(proxyNestedRemoteAction),
- getServerActionId(proxyDefaultRemoteAction),
- getServerActionId(proxyBundledIncrementRemoteCount),
- getServerActionId(proxyBundledRemoteActionEcho),
- getServerActionId(proxyBundledNestedRemoteAction),
- getServerActionId(proxyBundledDefaultRemoteAction),
- ].filter((actionId): actionId is string => Boolean(actionId));
+ const hostProxyActions = [
+ proxyIncrementRemoteCount,
+ proxyRemoteActionEcho,
+ proxyNestedRemoteAction,
+ proxyDefaultRemoteAction,
+ proxyBundledIncrementRemoteCount,
+ proxyBundledRemoteActionEcho,
+ proxyBundledNestedRemoteAction,
+ proxyBundledDefaultRemoteAction,
+ ] as const;
+ const hostProxyActionIds = hostProxyActions
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId));
const uniqueHostProxyActionIds = Array.from(
new Set(hostProxyActionIds),
).sort();
@@ -45,40 +48,39 @@ const App = () => {
// Map remote action IDs to host-local proxy action IDs so client-side
// callbacks can always post a host-resolvable action id. This keeps
// remote action execution in-process on the host via proxy imports.
- const remoteActionIdToHostProxyActionEntries = [
+ const remoteActionToHostProxyActionPairs = [
+ [incrementRemoteCount, proxyIncrementRemoteCount],
+ [remoteActionEcho, proxyRemoteActionEcho],
+ [nestedRemoteAction, proxyNestedRemoteAction],
+ [defaultRemoteAction, proxyDefaultRemoteAction],
[
- getServerActionId(incrementRemoteCount),
- getServerActionId(proxyIncrementRemoteCount),
+ remoteActionBundle.bundledIncrementRemoteCount,
+ proxyBundledIncrementRemoteCount,
],
+ [remoteActionBundle.bundledRemoteActionEcho, proxyBundledRemoteActionEcho],
[
- getServerActionId(remoteActionEcho),
- getServerActionId(proxyRemoteActionEcho),
+ remoteActionBundle.bundledNestedRemoteAction,
+ proxyBundledNestedRemoteAction,
],
[
- getServerActionId(nestedRemoteAction),
- getServerActionId(proxyNestedRemoteAction),
+ remoteActionBundle.bundledDefaultRemoteAction,
+ proxyBundledDefaultRemoteAction,
],
- [
- getServerActionId(defaultRemoteAction),
- getServerActionId(proxyDefaultRemoteAction),
- ],
- [
- getServerActionId(remoteActionBundle.bundledIncrementRemoteCount),
- getServerActionId(proxyBundledIncrementRemoteCount),
- ],
- [
- getServerActionId(remoteActionBundle.bundledRemoteActionEcho),
- getServerActionId(proxyBundledRemoteActionEcho),
- ],
- [
- getServerActionId(remoteActionBundle.bundledNestedRemoteAction),
- getServerActionId(proxyBundledNestedRemoteAction),
- ],
- [
- getServerActionId(remoteActionBundle.bundledDefaultRemoteAction),
- getServerActionId(proxyBundledDefaultRemoteAction),
- ],
- ].filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1]));
+ ] as const;
+ const remoteActionIdToHostProxyActionEntries =
+ remoteActionToHostProxyActionPairs
+ .map(([remoteAction, hostProxyAction]) => [
+ getServerActionId(remoteAction),
+ getServerActionId(hostProxyAction),
+ ])
+ .filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1]));
+ const hostProxyActionDebugKeys = hostProxyActions.map(
+ (action, index) =>
+ [action, getServerActionId(action) ?? `proxy-action-${index}`] as const,
+ );
+ const hostProxyManifestForms = hostProxyActionDebugKeys.map(
+ ([action, actionId]) => ,
+ );
const remoteActionIdToHostProxyActionId = Object.fromEntries(
remoteActionIdToHostProxyActionEntries,
);
@@ -125,16 +127,7 @@ const App = () => {
{/* Anchor host proxy actions in the server action manifest. */}
-
-
-
-
-
-
-
-
-
-
+ {hostProxyManifestForms}
Date: Sat, 14 Feb 2026 00:22:53 +0000
Subject: [PATCH 090/324] test(rsc-mf): assert host proxy id list uniqueness
and format
---
tests/integration/rsc-mf/tests/index.test.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 2d2b1f999e85..4d11e22ec0c5 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -118,7 +118,14 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
el.textContent?.trim(),
);
- expect(hostProxyActionIds?.split(',').filter(Boolean).length).toBe(8);
+ const hostProxyActionIdList = hostProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostProxyActionIdList.length).toBe(8);
+ expect(new Set(hostProxyActionIdList).size).toBe(8);
+ expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
+ true,
+ );
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
From 25af76821891e79ab55f4dbe82180b3aca7d095b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:26:31 +0000
Subject: [PATCH 091/324] test(rsc-mf): surface direct and bundled proxy id
groups
---
.../host/src/server-component-root/App.tsx | 20 ++++++++-
tests/integration/rsc-mf/tests/index.test.ts | 45 +++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 480ef480471c..8b96272b0ff1 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -27,16 +27,28 @@ const getServerActionId = (action: unknown) =>
(action as { $$id?: string } | undefined)?.$$id;
const App = () => {
- const hostProxyActions = [
+ const directHostProxyActions = [
proxyIncrementRemoteCount,
proxyRemoteActionEcho,
proxyNestedRemoteAction,
proxyDefaultRemoteAction,
+ ] as const;
+ const bundledHostProxyActions = [
proxyBundledIncrementRemoteCount,
proxyBundledRemoteActionEcho,
proxyBundledNestedRemoteAction,
proxyBundledDefaultRemoteAction,
] as const;
+ const hostProxyActions = [
+ ...directHostProxyActions,
+ ...bundledHostProxyActions,
+ ] as const;
+ const directHostProxyActionIds = directHostProxyActions
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId));
+ const bundledHostProxyActionIds = bundledHostProxyActions
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId));
const hostProxyActionIds = hostProxyActions
.map(action => getServerActionId(action))
.filter((actionId): actionId is string => Boolean(actionId));
@@ -119,6 +131,12 @@ const App = () => {
{uniqueHostProxyActionIds.join(',')}
+
+ {directHostProxyActionIds.join(',')}
+
+
+ {bundledHostProxyActionIds.join(',')}
+
Loading Remote Async Server Info...}>
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 4d11e22ec0c5..bb715f7146c8 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -66,6 +66,8 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-remote-bundled-meta-kind');
expect(html).toContain('host-proxy-action-id-count');
expect(html).toContain('host-proxy-action-ids');
+ expect(html).toContain('host-direct-proxy-action-ids');
+ expect(html).toContain('host-bundled-proxy-action-ids');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -126,6 +128,22 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
);
+ const hostDirectProxyActionIds = await page.$eval(
+ '.host-direct-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostDirectProxyActionIdList = hostDirectProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostDirectProxyActionIdList.length).toBe(4);
+ const hostBundledProxyActionIds = await page.$eval(
+ '.host-bundled-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostBundledProxyActionIdList = hostBundledProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostBundledProxyActionIdList.length).toBe(4);
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
@@ -362,6 +380,33 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.every(id => hostProxyActionIdSet.has(id))).toBe(
true,
);
+ const directProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-direct-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ const bundledProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-bundled-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ const usesDirectProxyIds = actionRequestIds.some(id =>
+ directProxyActionIdSet.has(id),
+ );
+ const usesBundledProxyIds = actionRequestIds.some(id =>
+ bundledProxyActionIdSet.has(id),
+ );
+ expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
});
it('should have no browser runtime errors', () => {
From 6256addc7d90f52531bd46b94d8ab54be2b37e4e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:30:20 +0000
Subject: [PATCH 092/324] test(rsc-mf): validate proxy id group union
membership
---
tests/integration/rsc-mf/tests/index.test.ts | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index bb715f7146c8..b9f2c8a4b64e 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -144,6 +144,16 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostBundledProxyActionIdList.length).toBe(4);
+ const groupedProxyActionIdUnion = new Set([
+ ...hostDirectProxyActionIdList,
+ ...hostBundledProxyActionIdList,
+ ]);
+ expect(groupedProxyActionIdUnion.size).toBe(hostProxyActionIdList.length);
+ expect(
+ hostProxyActionIdList.every(actionId =>
+ groupedProxyActionIdUnion.has(actionId),
+ ),
+ ).toBe(true);
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
@@ -407,6 +417,12 @@ function runTests({ mode }: TestConfig) {
bundledProxyActionIdSet.has(id),
);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
+ expect(
+ actionRequestIds.every(
+ id =>
+ directProxyActionIdSet.has(id) || bundledProxyActionIdSet.has(id),
+ ),
+ ).toBe(true);
});
it('should have no browser runtime errors', () => {
From 225df155997b92d2350a0f86afbe9863301071ca Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:34:09 +0000
Subject: [PATCH 093/324] test(rsc-mf): assert proxy map entry count aligns
with ids
---
.../rsc-mf/host/src/server-component-root/App.tsx | 5 +++++
tests/integration/rsc-mf/tests/index.test.ts | 7 +++++++
2 files changed, 12 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 8b96272b0ff1..090e8f461a6b 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -99,6 +99,8 @@ const App = () => {
const remoteActionIdMapKey = JSON.stringify(
remoteActionIdToHostProxyActionEntries,
);
+ const remoteActionIdMapEntryCount =
+ remoteActionIdToHostProxyActionEntries.length;
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
@@ -128,6 +130,9 @@ const App = () => {
{uniqueHostProxyActionIdsCount}
+
+ {remoteActionIdMapEntryCount}
+
{uniqueHostProxyActionIds.join(',')}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b9f2c8a4b64e..fa9d64289d3e 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -65,6 +65,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-remote-bundled-server-only');
expect(html).toContain('host-remote-bundled-meta-kind');
expect(html).toContain('host-proxy-action-id-count');
+ expect(html).toContain('host-proxy-map-entry-count');
expect(html).toContain('host-proxy-action-ids');
expect(html).toContain('host-direct-proxy-action-ids');
expect(html).toContain('host-bundled-proxy-action-ids');
@@ -117,6 +118,11 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostProxyActionIdCount).toBe('8');
+ const hostProxyMapEntryCount = await page.$eval(
+ '.host-proxy-map-entry-count',
+ el => el.textContent?.trim(),
+ );
+ expect(hostProxyMapEntryCount).toBe('8');
const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
el.textContent?.trim(),
);
@@ -124,6 +130,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostProxyActionIdList.length).toBe(8);
+ expect(hostProxyActionIdList.length).toBe(Number(hostProxyMapEntryCount));
expect(new Set(hostProxyActionIdList).size).toBe(8);
expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
From d806ec0d1ff23313642d8617e9999fc8479fb654 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:36:59 +0000
Subject: [PATCH 094/324] test(rsc-mf): assert proxy map entry count aligns
with ids
---
.../host/src/server-component-root/App.tsx | 14 +++++++++
tests/integration/rsc-mf/tests/index.test.ts | 31 +++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 090e8f461a6b..ab4143469e98 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -101,6 +101,14 @@ const App = () => {
);
const remoteActionIdMapEntryCount =
remoteActionIdToHostProxyActionEntries.length;
+ const mappedHostProxyActionIds = Array.from(
+ new Set(remoteActionIdToHostProxyActionEntries.map(([, hostId]) => hostId)),
+ ).sort();
+ const doesMappingCoverAllHostProxyActions =
+ mappedHostProxyActionIds.length === uniqueHostProxyActionIds.length &&
+ mappedHostProxyActionIds.every(
+ (actionId, index) => actionId === uniqueHostProxyActionIds[index],
+ );
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
@@ -133,6 +141,12 @@ const App = () => {
{remoteActionIdMapEntryCount}
+
+ {mappedHostProxyActionIds.join(',')}
+
+
+ {String(doesMappingCoverAllHostProxyActions)}
+
{uniqueHostProxyActionIds.join(',')}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index fa9d64289d3e..5a68d71e410c 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -66,6 +66,8 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-remote-bundled-meta-kind');
expect(html).toContain('host-proxy-action-id-count');
expect(html).toContain('host-proxy-map-entry-count');
+ expect(html).toContain('host-mapped-proxy-action-ids');
+ expect(html).toContain('host-proxy-map-covers-all');
expect(html).toContain('host-proxy-action-ids');
expect(html).toContain('host-direct-proxy-action-ids');
expect(html).toContain('host-bundled-proxy-action-ids');
@@ -123,6 +125,19 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostProxyMapEntryCount).toBe('8');
+ const hostMappedProxyActionIds = await page.$eval(
+ '.host-mapped-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostMappedProxyActionIdList = hostMappedProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostMappedProxyActionIdList.length).toBe(8);
+ const hostProxyMapCoversAll = await page.$eval(
+ '.host-proxy-map-covers-all',
+ el => el.textContent?.trim(),
+ );
+ expect(hostProxyMapCoversAll).toBe('true');
const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
el.textContent?.trim(),
);
@@ -135,6 +150,9 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
);
+ expect(
+ hostMappedProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
+ ).toBe(true);
const hostDirectProxyActionIds = await page.$eval(
'.host-direct-proxy-action-ids',
el => el.textContent?.trim(),
@@ -397,6 +415,19 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.every(id => hostProxyActionIdSet.has(id))).toBe(
true,
);
+ const mappedProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-mapped-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ expect(actionRequestIds.every(id => mappedProxyActionIdSet.has(id))).toBe(
+ true,
+ );
const directProxyActionIdSet = new Set(
(
await page.$eval(
From f02e2cf1793c1b243cdaf514e1b8325dc68f8e47 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:40:32 +0000
Subject: [PATCH 095/324] test(rsc-mf): assert mapped proxy id coverage markers
---
tests/integration/rsc-mf/tests/index.test.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 5a68d71e410c..35492e38489f 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -133,6 +133,9 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostMappedProxyActionIdList.length).toBe(8);
+ expect(hostMappedProxyActionIdList.length).toBe(
+ Number(hostProxyMapEntryCount),
+ );
const hostProxyMapCoversAll = await page.$eval(
'.host-proxy-map-covers-all',
el => el.textContent?.trim(),
@@ -150,8 +153,12 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
);
+ const sortedHostProxyActionIds = [...hostProxyActionIdList].sort();
+ const sortedMappedProxyActionIds = [...hostMappedProxyActionIdList].sort();
expect(
- hostMappedProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
+ sortedHostProxyActionIds.every(
+ (id, index) => id === sortedMappedProxyActionIds[index],
+ ),
).toBe(true);
const hostDirectProxyActionIds = await page.$eval(
'.host-direct-proxy-action-ids',
From c220479c693b6a014038ef6cb1c5926f590ef742 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:46:04 +0000
Subject: [PATCH 096/324] refactor(rsc-mf): model effective remote action map
keys
---
.../host/src/server-component-root/App.tsx | 16 +++++++++++-----
tests/integration/rsc-mf/tests/index.test.ts | 18 ++++++++++++------
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index ab4143469e98..33f303b48481 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -96,18 +96,23 @@ const App = () => {
const remoteActionIdToHostProxyActionId = Object.fromEntries(
remoteActionIdToHostProxyActionEntries,
);
+ const remoteActionIdMapKeyCount = Object.keys(
+ remoteActionIdToHostProxyActionId,
+ ).length;
const remoteActionIdMapKey = JSON.stringify(
- remoteActionIdToHostProxyActionEntries,
+ Object.entries(remoteActionIdToHostProxyActionId).sort(([left], [right]) =>
+ left.localeCompare(right),
+ ),
);
const remoteActionIdMapEntryCount =
remoteActionIdToHostProxyActionEntries.length;
const mappedHostProxyActionIds = Array.from(
- new Set(remoteActionIdToHostProxyActionEntries.map(([, hostId]) => hostId)),
+ new Set(Object.values(remoteActionIdToHostProxyActionId)),
).sort();
const doesMappingCoverAllHostProxyActions =
- mappedHostProxyActionIds.length === uniqueHostProxyActionIds.length &&
- mappedHostProxyActionIds.every(
- (actionId, index) => actionId === uniqueHostProxyActionIds[index],
+ mappedHostProxyActionIds.length <= uniqueHostProxyActionIds.length &&
+ mappedHostProxyActionIds.every(actionId =>
+ uniqueHostProxyActionIds.includes(actionId),
);
const remoteServerOnlyInfo = getServerOnlyInfo();
@@ -141,6 +146,7 @@ const App = () => {
{remoteActionIdMapEntryCount}
+ {remoteActionIdMapKeyCount}
{mappedHostProxyActionIds.join(',')}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 35492e38489f..6257ffed19ab 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -66,6 +66,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-remote-bundled-meta-kind');
expect(html).toContain('host-proxy-action-id-count');
expect(html).toContain('host-proxy-map-entry-count');
+ expect(html).toContain('host-proxy-map-key-count');
expect(html).toContain('host-mapped-proxy-action-ids');
expect(html).toContain('host-proxy-map-covers-all');
expect(html).toContain('host-proxy-action-ids');
@@ -125,6 +126,14 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostProxyMapEntryCount).toBe('8');
+ const hostProxyMapKeyCount = await page.$eval(
+ '.host-proxy-map-key-count',
+ el => el.textContent?.trim(),
+ );
+ expect(Number(hostProxyMapKeyCount)).toBeGreaterThan(0);
+ expect(Number(hostProxyMapKeyCount)).toBeLessThanOrEqual(
+ Number(hostProxyMapEntryCount),
+ );
const hostMappedProxyActionIds = await page.$eval(
'.host-mapped-proxy-action-ids',
el => el.textContent?.trim(),
@@ -132,10 +141,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostMappedProxyActionIdList = hostMappedProxyActionIds
?.split(',')
.filter(Boolean) as string[];
- expect(hostMappedProxyActionIdList.length).toBe(8);
- expect(hostMappedProxyActionIdList.length).toBe(
- Number(hostProxyMapEntryCount),
- );
+ expect(hostMappedProxyActionIdList.length).toBe(Number(hostProxyMapKeyCount));
const hostProxyMapCoversAll = await page.$eval(
'.host-proxy-map-covers-all',
el => el.textContent?.trim(),
@@ -156,8 +162,8 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const sortedHostProxyActionIds = [...hostProxyActionIdList].sort();
const sortedMappedProxyActionIds = [...hostMappedProxyActionIdList].sort();
expect(
- sortedHostProxyActionIds.every(
- (id, index) => id === sortedMappedProxyActionIds[index],
+ sortedMappedProxyActionIds.every(mappedId =>
+ sortedHostProxyActionIds.includes(mappedId),
),
).toBe(true);
const hostDirectProxyActionIds = await page.$eval(
From db078ac53c4d8b637b54ebafe170ab0dd46fc415 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 00:59:02 +0000
Subject: [PATCH 097/324] test(rsc-mf): bind posted action ids to effective map
key count
---
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6257ffed19ab..ee3c8f3263c0 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -438,6 +438,16 @@ function runTests({ mode }: TestConfig) {
.split(',')
.filter(Boolean),
);
+ const hostProxyMapKeyCount = Number(
+ await page.$eval(
+ '.host-proxy-map-key-count',
+ el => el.textContent || '0',
+ ),
+ );
+ expect(hostProxyMapKeyCount).toBe(mappedProxyActionIdSet.size);
+ expect(new Set(actionRequestIds).size).toBeLessThanOrEqual(
+ hostProxyMapKeyCount,
+ );
expect(actionRequestIds.every(id => mappedProxyActionIdSet.has(id))).toBe(
true,
);
From 35e033cc4f44a2c62bd3b93a850bd15b643b3672 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:04:51 +0000
Subject: [PATCH 098/324] test(rsc-mf): handle direct-bundled id collisions in
request checks
---
tests/integration/rsc-mf/tests/index.test.ts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index ee3c8f3263c0..68e0204ac923 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -444,6 +444,12 @@ function runTests({ mode }: TestConfig) {
el => el.textContent || '0',
),
);
+ const hostProxyMapEntryCount = Number(
+ await page.$eval(
+ '.host-proxy-map-entry-count',
+ el => el.textContent || '0',
+ ),
+ );
expect(hostProxyMapKeyCount).toBe(mappedProxyActionIdSet.size);
expect(new Set(actionRequestIds).size).toBeLessThanOrEqual(
hostProxyMapKeyCount,
@@ -478,6 +484,9 @@ function runTests({ mode }: TestConfig) {
bundledProxyActionIdSet.has(id),
);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
+ if (!usesDirectProxyIds || !usesBundledProxyIds) {
+ expect(hostProxyMapKeyCount).toBeLessThan(hostProxyMapEntryCount);
+ }
expect(
actionRequestIds.every(
id =>
From 12dd1e0ae38067401f6522d377b904cfa2d989cd Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:06:22 +0000
Subject: [PATCH 099/324] test(rsc-mf): expose exact proxy-map equality
diagnostics
---
.../rsc-mf/host/src/server-component-root/App.tsx | 8 ++++++++
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++++
2 files changed, 18 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 33f303b48481..0fc40f020814 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -114,6 +114,11 @@ const App = () => {
mappedHostProxyActionIds.every(actionId =>
uniqueHostProxyActionIds.includes(actionId),
);
+ const doesMappingExactlyMatchAllHostProxyActions =
+ mappedHostProxyActionIds.length === uniqueHostProxyActionIds.length &&
+ mappedHostProxyActionIds.every(
+ (actionId, index) => actionId === uniqueHostProxyActionIds[index],
+ );
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
@@ -153,6 +158,9 @@ const App = () => {
{String(doesMappingCoverAllHostProxyActions)}
+
+ {String(doesMappingExactlyMatchAllHostProxyActions)}
+
{uniqueHostProxyActionIds.join(',')}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 68e0204ac923..9be4473ad1d1 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -69,6 +69,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-proxy-map-key-count');
expect(html).toContain('host-mapped-proxy-action-ids');
expect(html).toContain('host-proxy-map-covers-all');
+ expect(html).toContain('host-proxy-map-equals-all');
expect(html).toContain('host-proxy-action-ids');
expect(html).toContain('host-direct-proxy-action-ids');
expect(html).toContain('host-bundled-proxy-action-ids');
@@ -147,6 +148,15 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostProxyMapCoversAll).toBe('true');
+ const hostProxyMapEqualsAll = await page.$eval(
+ '.host-proxy-map-equals-all',
+ el => el.textContent?.trim(),
+ );
+ expect(hostProxyMapEqualsAll).toBe(
+ Number(hostProxyMapKeyCount) === Number(hostProxyMapEntryCount)
+ ? 'true'
+ : 'false',
+ );
const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
el.textContent?.trim(),
);
From 661c5c32ee21c85cb6a1968e4a86edbb91e5748b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:13:44 +0000
Subject: [PATCH 100/324] test(rsc-mf): expose proxy map collision count
diagnostics
---
.../host/src/server-component-root/App.tsx | 7 +++++++
tests/integration/rsc-mf/tests/index.test.ts | 20 ++++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 0fc40f020814..ab87ad27f18e 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -106,6 +106,10 @@ const App = () => {
);
const remoteActionIdMapEntryCount =
remoteActionIdToHostProxyActionEntries.length;
+ const remoteActionIdMapCollisionCount = Math.max(
+ remoteActionIdMapEntryCount - remoteActionIdMapKeyCount,
+ 0,
+ );
const mappedHostProxyActionIds = Array.from(
new Set(Object.values(remoteActionIdToHostProxyActionId)),
).sort();
@@ -152,6 +156,9 @@ const App = () => {
{remoteActionIdMapEntryCount}
{remoteActionIdMapKeyCount}
+
+ {remoteActionIdMapCollisionCount}
+
{mappedHostProxyActionIds.join(',')}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 9be4473ad1d1..a1678e211abf 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -67,6 +67,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-proxy-action-id-count');
expect(html).toContain('host-proxy-map-entry-count');
expect(html).toContain('host-proxy-map-key-count');
+ expect(html).toContain('host-proxy-map-collision-count');
expect(html).toContain('host-mapped-proxy-action-ids');
expect(html).toContain('host-proxy-map-covers-all');
expect(html).toContain('host-proxy-map-equals-all');
@@ -135,6 +136,14 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(Number(hostProxyMapKeyCount)).toBeLessThanOrEqual(
Number(hostProxyMapEntryCount),
);
+ const hostProxyMapCollisionCount = await page.$eval(
+ '.host-proxy-map-collision-count',
+ el => el.textContent?.trim(),
+ );
+ expect(Number(hostProxyMapCollisionCount)).toBeGreaterThanOrEqual(0);
+ expect(Number(hostProxyMapCollisionCount)).toBe(
+ Number(hostProxyMapEntryCount) - Number(hostProxyMapKeyCount),
+ );
const hostMappedProxyActionIds = await page.$eval(
'.host-mapped-proxy-action-ids',
el => el.textContent?.trim(),
@@ -460,10 +469,19 @@ function runTests({ mode }: TestConfig) {
el => el.textContent || '0',
),
);
+ const hostProxyMapCollisionCount = Number(
+ await page.$eval(
+ '.host-proxy-map-collision-count',
+ el => el.textContent || '0',
+ ),
+ );
expect(hostProxyMapKeyCount).toBe(mappedProxyActionIdSet.size);
expect(new Set(actionRequestIds).size).toBeLessThanOrEqual(
hostProxyMapKeyCount,
);
+ expect(hostProxyMapCollisionCount).toBe(
+ hostProxyMapEntryCount - hostProxyMapKeyCount,
+ );
expect(actionRequestIds.every(id => mappedProxyActionIdSet.has(id))).toBe(
true,
);
@@ -495,7 +513,7 @@ function runTests({ mode }: TestConfig) {
);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
if (!usesDirectProxyIds || !usesBundledProxyIds) {
- expect(hostProxyMapKeyCount).toBeLessThan(hostProxyMapEntryCount);
+ expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
}
expect(
actionRequestIds.every(
From ee24d539e50016ea49e135ac0269c8e63395688e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:17:22 +0000
Subject: [PATCH 101/324] test(rsc-mf): cover remote client default server
action path
---
.../src/components/RemoteClientCounter.tsx | 16 ++++++++++++----
tests/integration/rsc-mf/tests/index.test.ts | 6 +++++-
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
index 599622852f3b..67483b2203b5 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -2,6 +2,7 @@
import { useActionState, useState } from 'react';
import './RemoteClientCounter.css';
import { incrementRemoteCount, remoteActionEcho } from './actions';
+import { defaultRemoteAction } from './defaultAction';
import { nestedRemoteAction } from './nestedActions';
export function RemoteClientCounter() {
@@ -12,14 +13,18 @@ export function RemoteClientCounter() {
);
const [nestedResult, setNestedResult] = useState('');
const [remoteActionResult, setRemoteActionResult] = useState('');
+ const [defaultActionResult, setDefaultActionResult] = useState('');
const handleRunActions = async () => {
- const [nestedResultValue, remoteActionValue] = await Promise.all([
- nestedRemoteAction('from-client'),
- remoteActionEcho('from-client'),
- ]);
+ const [nestedResultValue, remoteActionValue, defaultActionValue] =
+ await Promise.all([
+ nestedRemoteAction('from-client'),
+ remoteActionEcho('from-client'),
+ defaultRemoteAction('from-client'),
+ ]);
setNestedResult(nestedResultValue);
setRemoteActionResult(remoteActionValue);
+ setDefaultActionResult(defaultActionValue);
};
return (
@@ -49,6 +54,9 @@ export function RemoteClientCounter() {
{nestedResult}
{remoteActionResult}
+
+ {defaultActionResult}
+
);
}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index a1678e211abf..fa48bafc2589 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -272,9 +272,13 @@ async function supportRemoteClientAndServerActions({
const remoteAction = document.querySelector(
'.host-remote-action-runner .remote-client-remote-action-result',
);
+ const defaultAction = document.querySelector(
+ '.host-remote-action-runner .remote-client-default-action-result',
+ );
return (
nested?.textContent?.trim() === 'nested-action:from-client' &&
- remoteAction?.textContent?.trim() === 'remote-action:from-client'
+ remoteAction?.textContent?.trim() === 'remote-action:from-client' &&
+ defaultAction?.textContent?.trim() === 'default-action:from-client'
);
});
From 748302951fd6e4a48df606340f9c8e838652faf9 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:21:22 +0000
Subject: [PATCH 102/324] test(rsc-mf): assert request coverage across action
families
---
.../host/src/server-component-root/App.tsx | 40 +++++++++
tests/integration/rsc-mf/tests/index.test.ts | 88 +++++++++++++++++++
2 files changed, 128 insertions(+)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index ab87ad27f18e..9a5e71fb3415 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -56,6 +56,34 @@ const App = () => {
new Set(hostProxyActionIds),
).sort();
const uniqueHostProxyActionIdsCount = uniqueHostProxyActionIds.length;
+ const incrementProxyActionIds = Array.from(
+ new Set(
+ [proxyIncrementRemoteCount, proxyBundledIncrementRemoteCount]
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId)),
+ ),
+ ).sort();
+ const echoProxyActionIds = Array.from(
+ new Set(
+ [proxyRemoteActionEcho, proxyBundledRemoteActionEcho]
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId)),
+ ),
+ ).sort();
+ const nestedProxyActionIds = Array.from(
+ new Set(
+ [proxyNestedRemoteAction, proxyBundledNestedRemoteAction]
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId)),
+ ),
+ ).sort();
+ const defaultProxyActionIds = Array.from(
+ new Set(
+ [proxyDefaultRemoteAction, proxyBundledDefaultRemoteAction]
+ .map(action => getServerActionId(action))
+ .filter((actionId): actionId is string => Boolean(actionId)),
+ ),
+ ).sort();
// Map remote action IDs to host-local proxy action IDs so client-side
// callbacks can always post a host-resolvable action id. This keeps
@@ -177,6 +205,18 @@ const App = () => {
{bundledHostProxyActionIds.join(',')}
+
+ {incrementProxyActionIds.join(',')}
+
+
+ {echoProxyActionIds.join(',')}
+
+
+ {nestedProxyActionIds.join(',')}
+
+
+ {defaultProxyActionIds.join(',')}
+
Loading Remote Async Server Info...}>
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index fa48bafc2589..b96f287e0343 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -74,6 +74,10 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('host-proxy-action-ids');
expect(html).toContain('host-direct-proxy-action-ids');
expect(html).toContain('host-bundled-proxy-action-ids');
+ expect(html).toContain('host-increment-proxy-action-ids');
+ expect(html).toContain('host-echo-proxy-action-ids');
+ expect(html).toContain('host-nested-proxy-action-ids');
+ expect(html).toContain('host-default-proxy-action-ids');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -201,6 +205,38 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostBundledProxyActionIdList.length).toBe(4);
+ const hostIncrementProxyActionIds = await page.$eval(
+ '.host-increment-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostIncrementProxyActionIdList = hostIncrementProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostIncrementProxyActionIdList.length).toBeGreaterThan(0);
+ const hostEchoProxyActionIds = await page.$eval(
+ '.host-echo-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostEchoProxyActionIdList = hostEchoProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostEchoProxyActionIdList.length).toBeGreaterThan(0);
+ const hostNestedProxyActionIds = await page.$eval(
+ '.host-nested-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostNestedProxyActionIdList = hostNestedProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostNestedProxyActionIdList.length).toBeGreaterThan(0);
+ const hostDefaultProxyActionIds = await page.$eval(
+ '.host-default-proxy-action-ids',
+ el => el.textContent?.trim(),
+ );
+ const hostDefaultProxyActionIdList = hostDefaultProxyActionIds
+ ?.split(',')
+ .filter(Boolean) as string[];
+ expect(hostDefaultProxyActionIdList.length).toBeGreaterThan(0);
const groupedProxyActionIdUnion = new Set([
...hostDirectProxyActionIdList,
...hostBundledProxyActionIdList,
@@ -515,10 +551,62 @@ function runTests({ mode }: TestConfig) {
const usesBundledProxyIds = actionRequestIds.some(id =>
bundledProxyActionIdSet.has(id),
);
+ const incrementProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-increment-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ const echoProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-echo-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ const nestedProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-nested-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
+ const defaultProxyActionIdSet = new Set(
+ (
+ await page.$eval(
+ '.host-default-proxy-action-ids',
+ el => el.textContent || '',
+ )
+ )
+ .split(',')
+ .filter(Boolean),
+ );
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
if (!usesDirectProxyIds || !usesBundledProxyIds) {
expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
}
+ expect(
+ actionRequestIds.some(id => incrementProxyActionIdSet.has(id)),
+ ).toBe(true);
+ expect(actionRequestIds.some(id => echoProxyActionIdSet.has(id))).toBe(
+ true,
+ );
+ expect(actionRequestIds.some(id => nestedProxyActionIdSet.has(id))).toBe(
+ true,
+ );
+ expect(actionRequestIds.some(id => defaultProxyActionIdSet.has(id))).toBe(
+ true,
+ );
expect(
actionRequestIds.every(
id =>
From 9d3c307201f9a2ceaa5479213061187e5031d1a6 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:25:46 +0000
Subject: [PATCH 103/324] test(rsc-mf): cover direct host nested and increment
actions
---
.../HostRemoteActionRunner.tsx | 25 +++++++++++++++----
tests/integration/rsc-mf/tests/index.test.ts | 11 +++++++-
2 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index 5b97e718fe58..d34f161ce05e 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -4,8 +4,9 @@ import { useEffect, useState } from 'react';
import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteClientCounter as RemoteClientCounterBridge } from 'rscRemote/RemoteClientCounter';
import * as remoteActionBundle from 'rscRemote/actionBundle';
-import { remoteActionEcho } from 'rscRemote/actions';
+import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
+import { nestedRemoteAction } from 'rscRemote/nestedActions';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
export default function HostRemoteActionRunner({
@@ -20,6 +21,8 @@ export default function HostRemoteActionRunner({
void RemoteClientCounterBridge;
const [defaultResult, setDefaultResult] = useState('');
const [echoResult, setEchoResult] = useState('');
+ const [nestedResult, setNestedResult] = useState('');
+ const [incrementResult, setIncrementResult] = useState('');
const [bundledDefaultResult, setBundledDefaultResult] = useState('');
const [bundledEchoResult, setBundledEchoResult] = useState('');
const [bundledNestedResult, setBundledNestedResult] = useState('');
@@ -39,18 +42,21 @@ export default function HostRemoteActionRunner({
const runActions = async () => {
setIsPending(true);
try {
+ const directIncrementFormData = new FormData();
+ directIncrementFormData.set('count', '1');
const bundledIncrementFormData = new FormData();
bundledIncrementFormData.set('count', '1');
const [
defaultValue,
echoValue,
+ nestedValue,
bundledDefaultValue,
bundledEchoValue,
bundledNestedValue,
- bundledIncrementValue,
] = await Promise.all([
defaultRemoteAction('from-host-client'),
remoteActionEcho('from-host-client'),
+ nestedRemoteAction('from-host-client-direct'),
remoteActionBundle.bundledDefaultRemoteAction(
'from-host-client-bundled',
),
@@ -58,13 +64,20 @@ export default function HostRemoteActionRunner({
remoteActionBundle.bundledNestedRemoteAction(
'from-host-client-bundled',
),
- remoteActionBundle.bundledIncrementRemoteCount(
+ ]);
+ const directIncrementValue = await incrementRemoteCount(
+ 0,
+ directIncrementFormData,
+ );
+ const bundledIncrementValue =
+ await remoteActionBundle.bundledIncrementRemoteCount(
0,
bundledIncrementFormData,
- ),
- ]);
+ );
setDefaultResult(defaultValue);
setEchoResult(echoValue);
+ setNestedResult(nestedValue);
+ setIncrementResult(String(directIncrementValue));
setBundledDefaultResult(bundledDefaultValue);
setBundledEchoResult(bundledEchoValue);
setBundledNestedResult(bundledNestedValue);
@@ -87,6 +100,8 @@ export default function HostRemoteActionRunner({
{defaultResult}
{echoResult}
+ {nestedResult}
+ {incrementResult}
{bundledDefaultResult}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b96f287e0343..d138403cb642 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -338,6 +338,12 @@ async function supportRemoteClientAndServerActions({
const echoActionResult = document.querySelector(
'.host-remote-echo-action-result',
);
+ const nestedActionResult = document.querySelector(
+ '.host-remote-nested-action-result',
+ );
+ const incrementActionResult = document.querySelector(
+ '.host-remote-increment-action-result',
+ );
const bundledDefaultActionResult = document.querySelector(
'.host-remote-bundled-default-action-result',
);
@@ -355,13 +361,16 @@ async function supportRemoteClientAndServerActions({
'default-action:from-host-client' &&
echoActionResult?.textContent?.trim() ===
'remote-action:from-host-client' &&
+ nestedActionResult?.textContent?.trim() ===
+ 'nested-action:from-host-client-direct' &&
+ incrementActionResult?.textContent?.trim() === '2' &&
bundledDefaultActionResult?.textContent?.trim() ===
'default-action:from-host-client-bundled' &&
bundledEchoActionResult?.textContent?.trim() ===
'remote-action:from-host-client-bundled' &&
bundledNestedActionResult?.textContent?.trim() ===
'nested-action:from-host-client-bundled' &&
- bundledIncrementActionResult?.textContent?.trim() === '2'
+ bundledIncrementActionResult?.textContent?.trim() === '3'
);
});
}
From 0c0ca338978a596997ca7075df778bc1231abdad Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:28:33 +0000
Subject: [PATCH 104/324] test(rsc-mf): enforce minimum action post volume per
mode
---
tests/integration/rsc-mf/tests/index.test.ts | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index d138403cb642..f04f5384e5e3 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -16,6 +16,7 @@ const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
const HOST_RSC_URL = '/server-component-root';
+const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 10;
type Mode = 'dev' | 'build';
@@ -466,7 +467,9 @@ function runTests({ mode }: TestConfig) {
supportRemoteClientAndServerActions({ hostPort, page }));
it('should route remote actions through host endpoint', () => {
- expect(actionRequestUrls.length).toBeGreaterThan(0);
+ expect(actionRequestUrls.length).toBeGreaterThanOrEqual(
+ MIN_EXPECTED_ACTION_POSTS_PER_MODE,
+ );
expect(
actionRequestUrls.every(url =>
url.startsWith(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`),
@@ -480,7 +483,9 @@ function runTests({ mode }: TestConfig) {
});
it('should post host-resolvable action ids for remote actions', async () => {
- expect(actionRequestIds.length).toBeGreaterThan(0);
+ expect(actionRequestIds.length).toBeGreaterThanOrEqual(
+ MIN_EXPECTED_ACTION_POSTS_PER_MODE,
+ );
expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
true,
);
From 963c240efbe4f7ff39745565865a582999bbabc5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:32:36 +0000
Subject: [PATCH 105/324] test(rsc-mf): require action-family union coverage
for posted ids
---
tests/integration/rsc-mf/tests/index.test.ts | 25 ++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index f04f5384e5e3..4e448501b68a 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -214,6 +214,11 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostIncrementProxyActionIdList.length).toBeGreaterThan(0);
+ expect(
+ hostIncrementProxyActionIdList.every(id =>
+ hostProxyActionIdList.includes(id),
+ ),
+ ).toBe(true);
const hostEchoProxyActionIds = await page.$eval(
'.host-echo-proxy-action-ids',
el => el.textContent?.trim(),
@@ -222,6 +227,9 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostEchoProxyActionIdList.length).toBeGreaterThan(0);
+ expect(
+ hostEchoProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
+ ).toBe(true);
const hostNestedProxyActionIds = await page.$eval(
'.host-nested-proxy-action-ids',
el => el.textContent?.trim(),
@@ -230,6 +238,9 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostNestedProxyActionIdList.length).toBeGreaterThan(0);
+ expect(
+ hostNestedProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
+ ).toBe(true);
const hostDefaultProxyActionIds = await page.$eval(
'.host-default-proxy-action-ids',
el => el.textContent?.trim(),
@@ -238,6 +249,11 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
?.split(',')
.filter(Boolean) as string[];
expect(hostDefaultProxyActionIdList.length).toBeGreaterThan(0);
+ expect(
+ hostDefaultProxyActionIdList.every(id =>
+ hostProxyActionIdList.includes(id),
+ ),
+ ).toBe(true);
const groupedProxyActionIdUnion = new Set([
...hostDirectProxyActionIdList,
...hostBundledProxyActionIdList,
@@ -605,6 +621,12 @@ function runTests({ mode }: TestConfig) {
.split(',')
.filter(Boolean),
);
+ const actionFamilyProxyActionIdSet = new Set([
+ ...incrementProxyActionIdSet,
+ ...echoProxyActionIdSet,
+ ...nestedProxyActionIdSet,
+ ...defaultProxyActionIdSet,
+ ]);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
if (!usesDirectProxyIds || !usesBundledProxyIds) {
expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
@@ -621,6 +643,9 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.some(id => defaultProxyActionIdSet.has(id))).toBe(
true,
);
+ expect(
+ actionRequestIds.every(id => actionFamilyProxyActionIdSet.has(id)),
+ ).toBe(true);
expect(
actionRequestIds.every(
id =>
From 6f81467a70602f430ea761d4454de5b029d4912c Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:35:13 +0000
Subject: [PATCH 106/324] test(rsc-mf): require action-family union coverage
for posted ids
---
tests/integration/rsc-mf/tests/index.test.ts | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 4e448501b68a..b11ab5404581 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -16,7 +16,7 @@ const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
const HOST_RSC_URL = '/server-component-root';
-const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 10;
+const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 18;
type Mode = 'dev' | 'build';
@@ -390,6 +390,20 @@ async function supportRemoteClientAndServerActions({
bundledIncrementActionResult?.textContent?.trim() === '3'
);
});
+
+ await page.click('.host-remote-run-actions');
+ await page.waitForFunction(() => {
+ const incrementActionResult = document.querySelector(
+ '.host-remote-increment-action-result',
+ );
+ const bundledIncrementActionResult = document.querySelector(
+ '.host-remote-bundled-increment-action-result',
+ );
+ return (
+ incrementActionResult?.textContent?.trim() === '4' &&
+ bundledIncrementActionResult?.textContent?.trim() === '5'
+ );
+ });
}
function runTests({ mode }: TestConfig) {
From 125651563a4147a96634201e6d5873aa662ae516 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:39:04 +0000
Subject: [PATCH 107/324] test(rsc-mf): assert repeated client callback request
growth
---
tests/integration/rsc-mf/tests/index.test.ts | 68 +++++++++++++++++++-
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b11ab5404581..7727e1d9cb34 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -16,7 +16,7 @@ const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
const HOST_RSC_URL = '/server-component-root';
-const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 18;
+const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 22;
type Mode = 'dev' | 'build';
@@ -27,6 +27,29 @@ interface TestConfig {
interface TestContext {
hostPort: number;
page: Page;
+ actionRequestIds?: string[];
+}
+
+async function waitForActionRequestCount({
+ actionRequestIds,
+ minimumCount,
+ timeoutMs = 15000,
+}: {
+ actionRequestIds: string[];
+ minimumCount: number;
+ timeoutMs?: number;
+}) {
+ const startTime = Date.now();
+ while (Date.now() - startTime < timeoutMs) {
+ if (actionRequestIds.length >= minimumCount) {
+ return;
+ }
+ await sleep(50);
+ }
+
+ throw new Error(
+ `Timed out waiting for action request count ${minimumCount}, received ${actionRequestIds.length}`,
+ );
}
function skipForLowerNodeVersion() {
@@ -274,6 +297,7 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
async function supportRemoteClientAndServerActions({
hostPort,
page,
+ actionRequestIds,
}: TestContext) {
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -317,7 +341,10 @@ async function supportRemoteClientAndServerActions({
);
expect(serverCount).toBe('1');
+ const actionRequestCountBeforeFirstClientRun = actionRequestIds?.length || 0;
await page.click('.host-remote-action-runner .remote-client-run-actions');
+ const actionRequestCountAfterFirstClientRun =
+ actionRequestCountBeforeFirstClientRun + 3;
await page.waitForFunction(() => {
const nested = document.querySelector(
'.host-remote-action-runner .remote-client-nested-result',
@@ -334,6 +361,39 @@ async function supportRemoteClientAndServerActions({
defaultAction?.textContent?.trim() === 'default-action:from-client'
);
});
+ if (actionRequestIds) {
+ await waitForActionRequestCount({
+ actionRequestIds,
+ minimumCount: actionRequestCountAfterFirstClientRun,
+ });
+ }
+
+ const actionRequestCountBeforeSecondClientRun = actionRequestIds?.length || 0;
+ await page.click('.host-remote-action-runner .remote-client-run-actions');
+ const actionRequestCountAfterSecondClientRun =
+ actionRequestCountBeforeSecondClientRun + 3;
+ await page.waitForFunction(() => {
+ const nested = document.querySelector(
+ '.host-remote-action-runner .remote-client-nested-result',
+ );
+ const remoteAction = document.querySelector(
+ '.host-remote-action-runner .remote-client-remote-action-result',
+ );
+ const defaultAction = document.querySelector(
+ '.host-remote-action-runner .remote-client-default-action-result',
+ );
+ return (
+ nested?.textContent?.trim() === 'nested-action:from-client' &&
+ remoteAction?.textContent?.trim() === 'remote-action:from-client' &&
+ defaultAction?.textContent?.trim() === 'default-action:from-client'
+ );
+ });
+ if (actionRequestIds) {
+ await waitForActionRequestCount({
+ actionRequestIds,
+ minimumCount: actionRequestCountAfterSecondClientRun,
+ });
+ }
let badgeValue = await page.$eval(
'.host-remote-action-runner .remote-client-badge-value',
@@ -494,7 +554,11 @@ function runTests({ mode }: TestConfig) {
renderRemoteRscIntoHost({ hostPort, page }));
it('should support remote use client and server actions', () =>
- supportRemoteClientAndServerActions({ hostPort, page }));
+ supportRemoteClientAndServerActions({
+ hostPort,
+ page,
+ actionRequestIds,
+ }));
it('should route remote actions through host endpoint', () => {
expect(actionRequestUrls.length).toBeGreaterThanOrEqual(
From d3212372d29369d97540d9d9d6a0f1cd36265791 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:42:44 +0000
Subject: [PATCH 108/324] test(rsc-mf): align unique posted ids with effective
action keys
---
tests/integration/rsc-mf/tests/index.test.ts | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 7727e1d9cb34..abe77bc59bfa 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -580,13 +580,14 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.length).toBeGreaterThanOrEqual(
MIN_EXPECTED_ACTION_POSTS_PER_MODE,
);
+ const uniqueActionRequestIds = new Set(actionRequestIds);
expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
true,
);
expect(actionRequestIds.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
);
- expect(new Set(actionRequestIds).size).toBeGreaterThanOrEqual(4);
+ expect(uniqueActionRequestIds.size).toBeGreaterThanOrEqual(4);
const hostProxyActionIdSet = new Set(
(await page.$eval('.host-proxy-action-ids', el => el.textContent || ''))
.split(',')
@@ -624,7 +625,7 @@ function runTests({ mode }: TestConfig) {
),
);
expect(hostProxyMapKeyCount).toBe(mappedProxyActionIdSet.size);
- expect(new Set(actionRequestIds).size).toBeLessThanOrEqual(
+ expect(uniqueActionRequestIds.size).toBeLessThanOrEqual(
hostProxyMapKeyCount,
);
expect(hostProxyMapCollisionCount).toBe(
@@ -705,6 +706,8 @@ function runTests({ mode }: TestConfig) {
...nestedProxyActionIdSet,
...defaultProxyActionIdSet,
]);
+ expect(actionFamilyProxyActionIdSet.size).toBe(hostProxyActionIdSet.size);
+ expect(uniqueActionRequestIds.size).toBe(hostProxyMapKeyCount);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
if (!usesDirectProxyIds || !usesBundledProxyIds) {
expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
From bf250398bb1f419926fc9f011951a88195ff02c0 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:46:58 +0000
Subject: [PATCH 109/324] test(rsc-mf): tighten per-family proxy id cardinality
checks
---
tests/integration/rsc-mf/tests/index.test.ts | 72 ++++++++++++++++++--
1 file changed, 68 insertions(+), 4 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index abe77bc59bfa..b959fab57b1a 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -236,12 +236,15 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostIncrementProxyActionIdList = hostIncrementProxyActionIds
?.split(',')
.filter(Boolean) as string[];
- expect(hostIncrementProxyActionIdList.length).toBeGreaterThan(0);
+ expect(hostIncrementProxyActionIdList.length).toBe(2);
expect(
hostIncrementProxyActionIdList.every(id =>
hostProxyActionIdList.includes(id),
),
).toBe(true);
+ expect(
+ hostIncrementProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
+ ).toBe(true);
const hostEchoProxyActionIds = await page.$eval(
'.host-echo-proxy-action-ids',
el => el.textContent?.trim(),
@@ -249,10 +252,13 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostEchoProxyActionIdList = hostEchoProxyActionIds
?.split(',')
.filter(Boolean) as string[];
- expect(hostEchoProxyActionIdList.length).toBeGreaterThan(0);
+ expect(hostEchoProxyActionIdList.length).toBe(2);
expect(
hostEchoProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
).toBe(true);
+ expect(
+ hostEchoProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
+ ).toBe(true);
const hostNestedProxyActionIds = await page.$eval(
'.host-nested-proxy-action-ids',
el => el.textContent?.trim(),
@@ -260,10 +266,13 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostNestedProxyActionIdList = hostNestedProxyActionIds
?.split(',')
.filter(Boolean) as string[];
- expect(hostNestedProxyActionIdList.length).toBeGreaterThan(0);
+ expect(hostNestedProxyActionIdList.length).toBe(2);
expect(
hostNestedProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
).toBe(true);
+ expect(
+ hostNestedProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
+ ).toBe(true);
const hostDefaultProxyActionIds = await page.$eval(
'.host-default-proxy-action-ids',
el => el.textContent?.trim(),
@@ -271,12 +280,67 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const hostDefaultProxyActionIdList = hostDefaultProxyActionIds
?.split(',')
.filter(Boolean) as string[];
- expect(hostDefaultProxyActionIdList.length).toBeGreaterThan(0);
+ expect(hostDefaultProxyActionIdList.length).toBe(2);
expect(
hostDefaultProxyActionIdList.every(id =>
hostProxyActionIdList.includes(id),
),
).toBe(true);
+ expect(
+ hostDefaultProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
+ ).toBe(true);
+ const getGroupMembershipCount = (
+ actionIds: string[],
+ groupIds: string[],
+ ): number => actionIds.filter(id => groupIds.includes(id)).length;
+ expect(
+ getGroupMembershipCount(
+ hostIncrementProxyActionIdList,
+ hostDirectProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostIncrementProxyActionIdList,
+ hostBundledProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostEchoProxyActionIdList,
+ hostDirectProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostEchoProxyActionIdList,
+ hostBundledProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostNestedProxyActionIdList,
+ hostDirectProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostNestedProxyActionIdList,
+ hostBundledProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostDefaultProxyActionIdList,
+ hostDirectProxyActionIdList,
+ ),
+ ).toBe(1);
+ expect(
+ getGroupMembershipCount(
+ hostDefaultProxyActionIdList,
+ hostBundledProxyActionIdList,
+ ),
+ ).toBe(1);
const groupedProxyActionIdUnion = new Set([
...hostDirectProxyActionIdList,
...hostBundledProxyActionIdList,
From 93890ab13dda3bb9b8a06310618cb1f4ce78fa56 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:49:53 +0000
Subject: [PATCH 110/324] test(rsc-mf): tighten per-family proxy id cardinality
checks
---
tests/integration/rsc-mf/tests/index.test.ts | 24 ++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b959fab57b1a..c17f45c06e92 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -404,6 +404,22 @@ async function supportRemoteClientAndServerActions({
el => el.textContent?.trim(),
);
expect(serverCount).toBe('1');
+ await page.click(
+ '.host-remote-action-runner .remote-client-server-increment',
+ );
+ await page.waitForFunction(
+ () =>
+ !document
+ .querySelector(
+ '.host-remote-action-runner .remote-client-server-increment',
+ )
+ ?.hasAttribute('disabled'),
+ );
+ serverCount = await page.$eval(
+ '.host-remote-action-runner .remote-client-server-count',
+ el => el.textContent?.trim(),
+ );
+ expect(serverCount).toBe('2');
const actionRequestCountBeforeFirstClientRun = actionRequestIds?.length || 0;
await page.click('.host-remote-action-runner .remote-client-run-actions');
@@ -504,14 +520,14 @@ async function supportRemoteClientAndServerActions({
'remote-action:from-host-client' &&
nestedActionResult?.textContent?.trim() ===
'nested-action:from-host-client-direct' &&
- incrementActionResult?.textContent?.trim() === '2' &&
+ incrementActionResult?.textContent?.trim() === '3' &&
bundledDefaultActionResult?.textContent?.trim() ===
'default-action:from-host-client-bundled' &&
bundledEchoActionResult?.textContent?.trim() ===
'remote-action:from-host-client-bundled' &&
bundledNestedActionResult?.textContent?.trim() ===
'nested-action:from-host-client-bundled' &&
- bundledIncrementActionResult?.textContent?.trim() === '3'
+ bundledIncrementActionResult?.textContent?.trim() === '4'
);
});
@@ -524,8 +540,8 @@ async function supportRemoteClientAndServerActions({
'.host-remote-bundled-increment-action-result',
);
return (
- incrementActionResult?.textContent?.trim() === '4' &&
- bundledIncrementActionResult?.textContent?.trim() === '5'
+ incrementActionResult?.textContent?.trim() === '5' &&
+ bundledIncrementActionResult?.textContent?.trim() === '6'
);
});
}
From 0dec94caba6239eaa4d05693ac7c0a43e8c7c69f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:51:03 +0000
Subject: [PATCH 111/324] test(rsc-mf): assert action request URL-id parity
---
tests/integration/rsc-mf/tests/index.test.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index c17f45c06e92..059a87c35c60 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -644,6 +644,7 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestUrls.length).toBeGreaterThanOrEqual(
MIN_EXPECTED_ACTION_POSTS_PER_MODE,
);
+ expect(actionRequestUrls.length).toBe(actionRequestIds.length);
expect(
actionRequestUrls.every(url =>
url.startsWith(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`),
@@ -660,6 +661,7 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.length).toBeGreaterThanOrEqual(
MIN_EXPECTED_ACTION_POSTS_PER_MODE,
);
+ expect(actionRequestIds.length).toBe(actionRequestUrls.length);
const uniqueActionRequestIds = new Set(actionRequestIds);
expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
true,
From 047f7d28a17c3b3fe24b1b88cf043e627bf31df0 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:55:00 +0000
Subject: [PATCH 112/324] test(rsc-mf): assert family union spans all host
proxy ids
---
tests/integration/rsc-mf/tests/index.test.ts | 60 ++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 059a87c35c60..2aa2692ff290 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -341,6 +341,18 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
hostBundledProxyActionIdList,
),
).toBe(1);
+ const familyProxyActionIdUnion = new Set([
+ ...hostIncrementProxyActionIdList,
+ ...hostEchoProxyActionIdList,
+ ...hostNestedProxyActionIdList,
+ ...hostDefaultProxyActionIdList,
+ ]);
+ expect(familyProxyActionIdUnion.size).toBe(hostProxyActionIdList.length);
+ expect(
+ hostProxyActionIdList.every(actionId =>
+ familyProxyActionIdUnion.has(actionId),
+ ),
+ ).toBe(true);
const groupedProxyActionIdUnion = new Set([
...hostDirectProxyActionIdList,
...hostBundledProxyActionIdList,
@@ -788,6 +800,44 @@ function runTests({ mode }: TestConfig) {
...nestedProxyActionIdSet,
...defaultProxyActionIdSet,
]);
+ const getSetIntersectionSize = (left: Set, right: Set) =>
+ [...left].filter(id => right.has(id)).length;
+ expect(
+ getSetIntersectionSize(incrementProxyActionIdSet, echoProxyActionIdSet),
+ ).toBe(0);
+ expect(
+ getSetIntersectionSize(
+ incrementProxyActionIdSet,
+ nestedProxyActionIdSet,
+ ),
+ ).toBe(0);
+ expect(
+ getSetIntersectionSize(
+ incrementProxyActionIdSet,
+ defaultProxyActionIdSet,
+ ),
+ ).toBe(0);
+ expect(
+ getSetIntersectionSize(echoProxyActionIdSet, nestedProxyActionIdSet),
+ ).toBe(0);
+ expect(
+ getSetIntersectionSize(echoProxyActionIdSet, defaultProxyActionIdSet),
+ ).toBe(0);
+ expect(
+ getSetIntersectionSize(nestedProxyActionIdSet, defaultProxyActionIdSet),
+ ).toBe(0);
+ const incrementRequestCount = actionRequestIds.filter(id =>
+ incrementProxyActionIdSet.has(id),
+ ).length;
+ const echoRequestCount = actionRequestIds.filter(id =>
+ echoProxyActionIdSet.has(id),
+ ).length;
+ const nestedRequestCount = actionRequestIds.filter(id =>
+ nestedProxyActionIdSet.has(id),
+ ).length;
+ const defaultRequestCount = actionRequestIds.filter(id =>
+ defaultProxyActionIdSet.has(id),
+ ).length;
expect(actionFamilyProxyActionIdSet.size).toBe(hostProxyActionIdSet.size);
expect(uniqueActionRequestIds.size).toBe(hostProxyMapKeyCount);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
@@ -806,6 +856,16 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.some(id => defaultProxyActionIdSet.has(id))).toBe(
true,
);
+ expect(incrementRequestCount).toBeGreaterThanOrEqual(6);
+ expect(echoRequestCount).toBeGreaterThanOrEqual(6);
+ expect(nestedRequestCount).toBeGreaterThanOrEqual(6);
+ expect(defaultRequestCount).toBeGreaterThanOrEqual(6);
+ expect(
+ incrementRequestCount +
+ echoRequestCount +
+ nestedRequestCount +
+ defaultRequestCount,
+ ).toBe(actionRequestIds.length);
expect(
actionRequestIds.every(id => actionFamilyProxyActionIdSet.has(id)),
).toBe(true);
From b4705d97ccd8aa05b7016566f4e6d00690dda156 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 01:59:01 +0000
Subject: [PATCH 113/324] test(rsc-mf): enforce exact action post cardinality
profile
---
tests/integration/rsc-mf/tests/index.test.ts | 24 ++++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 2aa2692ff290..e3b1f2831f77 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -16,7 +16,9 @@ const fixtureDir = path.resolve(__dirname, '../');
const hostDir = path.resolve(fixtureDir, 'host');
const remoteDir = path.resolve(fixtureDir, 'remote');
const HOST_RSC_URL = '/server-component-root';
-const MIN_EXPECTED_ACTION_POSTS_PER_MODE = 22;
+const EXPECTED_ACTION_POSTS_PER_MODE = 24;
+const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
+const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
type Mode = 'dev' | 'build';
@@ -653,9 +655,7 @@ function runTests({ mode }: TestConfig) {
}));
it('should route remote actions through host endpoint', () => {
- expect(actionRequestUrls.length).toBeGreaterThanOrEqual(
- MIN_EXPECTED_ACTION_POSTS_PER_MODE,
- );
+ expect(actionRequestUrls.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestUrls.length).toBe(actionRequestIds.length);
expect(
actionRequestUrls.every(url =>
@@ -670,9 +670,7 @@ function runTests({ mode }: TestConfig) {
});
it('should post host-resolvable action ids for remote actions', async () => {
- expect(actionRequestIds.length).toBeGreaterThanOrEqual(
- MIN_EXPECTED_ACTION_POSTS_PER_MODE,
- );
+ expect(actionRequestIds.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestIds.length).toBe(actionRequestUrls.length);
const uniqueActionRequestIds = new Set(actionRequestIds);
expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
@@ -681,7 +679,9 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
true,
);
- expect(uniqueActionRequestIds.size).toBeGreaterThanOrEqual(4);
+ expect(uniqueActionRequestIds.size).toBe(
+ EXPECTED_UNIQUE_ACTION_IDS_PER_MODE,
+ );
const hostProxyActionIdSet = new Set(
(await page.$eval('.host-proxy-action-ids', el => el.textContent || ''))
.split(',')
@@ -856,10 +856,10 @@ function runTests({ mode }: TestConfig) {
expect(actionRequestIds.some(id => defaultProxyActionIdSet.has(id))).toBe(
true,
);
- expect(incrementRequestCount).toBeGreaterThanOrEqual(6);
- expect(echoRequestCount).toBeGreaterThanOrEqual(6);
- expect(nestedRequestCount).toBeGreaterThanOrEqual(6);
- expect(defaultRequestCount).toBeGreaterThanOrEqual(6);
+ expect(incrementRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
+ expect(echoRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
+ expect(nestedRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
+ expect(defaultRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
expect(
incrementRequestCount +
echoRequestCount +
From 542a4adc3f50e82b8149544d7283eb5003ebb078 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:02:01 +0000
Subject: [PATCH 114/324] test(rsc-mf): enforce exact action post cardinality
profile
---
tests/integration/rsc-mf/tests/index.test.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index e3b1f2831f77..b69faa90c640 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -838,8 +838,21 @@ function runTests({ mode }: TestConfig) {
const defaultRequestCount = actionRequestIds.filter(id =>
defaultProxyActionIdSet.has(id),
).length;
+ const actionRequestCountById = new Map();
+ for (const actionId of actionRequestIds) {
+ actionRequestCountById.set(
+ actionId,
+ (actionRequestCountById.get(actionId) || 0) + 1,
+ );
+ }
expect(actionFamilyProxyActionIdSet.size).toBe(hostProxyActionIdSet.size);
expect(uniqueActionRequestIds.size).toBe(hostProxyMapKeyCount);
+ expect(actionRequestCountById.size).toBe(uniqueActionRequestIds.size);
+ expect(
+ [...actionRequestCountById.values()].every(
+ count => count === EXPECTED_ACTION_POSTS_PER_FAMILY,
+ ),
+ ).toBe(true);
expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
if (!usesDirectProxyIds || !usesBundledProxyIds) {
expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
From be0ceaabbee6e273833409ce1e84dba9b26851a6 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:07:29 +0000
Subject: [PATCH 115/324] test(rsc-mf): assert uniform per-id action request
frequency
---
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index b69faa90c640..31cc14de4006 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -657,6 +657,10 @@ function runTests({ mode }: TestConfig) {
it('should route remote actions through host endpoint', () => {
expect(actionRequestUrls.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestUrls.length).toBe(actionRequestIds.length);
+ const uniqueActionRequestUrls = Array.from(new Set(actionRequestUrls));
+ expect(uniqueActionRequestUrls).toEqual([
+ `http://127.0.0.1:${hostPort}${HOST_RSC_URL}`,
+ ]);
expect(
actionRequestUrls.every(url =>
url.startsWith(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`),
From 549ba4e241300ed7db4ff05899248e39bb9ba8b1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:18:29 +0000
Subject: [PATCH 116/324] refactor(rsc-mf): remove host proxy action glue and
use bridge ids
---
.../host/src/server-component-root/App.tsx | 189 +-------
.../HostRemoteActionRunner.tsx | 13 +-
.../remoteActionProxy.ts | 47 --
.../src/components/registerServerCallback.ts | 15 +-
tests/integration/rsc-mf/tests/index.test.ts | 437 +-----------------
5 files changed, 10 insertions(+), 691 deletions(-)
delete mode 100644 tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
index 9a5e71fb3415..d50d7620b882 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/App.tsx
@@ -2,156 +2,14 @@ import 'server-only';
import { Suspense } from 'react';
import { AsyncRemoteServerInfo } from 'rscRemote/AsyncRemoteServerInfo';
import RemoteServerDefault from 'rscRemote/RemoteServerDefault';
-import * as remoteActionBundle from 'rscRemote/actionBundle';
-import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
-import { defaultRemoteAction } from 'rscRemote/defaultAction';
import * as remoteInfoBundle from 'rscRemote/infoBundle';
-import { nestedRemoteAction } from 'rscRemote/nestedActions';
import remoteMeta, { getRemoteMetaLabel } from 'rscRemote/remoteMeta';
import { getServerOnlyInfo } from 'rscRemote/remoteServerOnly';
import getServerOnlyDefaultInfo from 'rscRemote/remoteServerOnlyDefault';
import styles from './App.module.less';
import HostRemoteActionRunner from './HostRemoteActionRunner';
-import {
- proxyBundledDefaultRemoteAction,
- proxyBundledIncrementRemoteCount,
- proxyBundledNestedRemoteAction,
- proxyBundledRemoteActionEcho,
- proxyDefaultRemoteAction,
- proxyIncrementRemoteCount,
- proxyNestedRemoteAction,
- proxyRemoteActionEcho,
-} from './remoteActionProxy';
-
-const getServerActionId = (action: unknown) =>
- (action as { $$id?: string } | undefined)?.$$id;
const App = () => {
- const directHostProxyActions = [
- proxyIncrementRemoteCount,
- proxyRemoteActionEcho,
- proxyNestedRemoteAction,
- proxyDefaultRemoteAction,
- ] as const;
- const bundledHostProxyActions = [
- proxyBundledIncrementRemoteCount,
- proxyBundledRemoteActionEcho,
- proxyBundledNestedRemoteAction,
- proxyBundledDefaultRemoteAction,
- ] as const;
- const hostProxyActions = [
- ...directHostProxyActions,
- ...bundledHostProxyActions,
- ] as const;
- const directHostProxyActionIds = directHostProxyActions
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId));
- const bundledHostProxyActionIds = bundledHostProxyActions
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId));
- const hostProxyActionIds = hostProxyActions
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId));
- const uniqueHostProxyActionIds = Array.from(
- new Set(hostProxyActionIds),
- ).sort();
- const uniqueHostProxyActionIdsCount = uniqueHostProxyActionIds.length;
- const incrementProxyActionIds = Array.from(
- new Set(
- [proxyIncrementRemoteCount, proxyBundledIncrementRemoteCount]
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId)),
- ),
- ).sort();
- const echoProxyActionIds = Array.from(
- new Set(
- [proxyRemoteActionEcho, proxyBundledRemoteActionEcho]
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId)),
- ),
- ).sort();
- const nestedProxyActionIds = Array.from(
- new Set(
- [proxyNestedRemoteAction, proxyBundledNestedRemoteAction]
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId)),
- ),
- ).sort();
- const defaultProxyActionIds = Array.from(
- new Set(
- [proxyDefaultRemoteAction, proxyBundledDefaultRemoteAction]
- .map(action => getServerActionId(action))
- .filter((actionId): actionId is string => Boolean(actionId)),
- ),
- ).sort();
-
- // Map remote action IDs to host-local proxy action IDs so client-side
- // callbacks can always post a host-resolvable action id. This keeps
- // remote action execution in-process on the host via proxy imports.
- const remoteActionToHostProxyActionPairs = [
- [incrementRemoteCount, proxyIncrementRemoteCount],
- [remoteActionEcho, proxyRemoteActionEcho],
- [nestedRemoteAction, proxyNestedRemoteAction],
- [defaultRemoteAction, proxyDefaultRemoteAction],
- [
- remoteActionBundle.bundledIncrementRemoteCount,
- proxyBundledIncrementRemoteCount,
- ],
- [remoteActionBundle.bundledRemoteActionEcho, proxyBundledRemoteActionEcho],
- [
- remoteActionBundle.bundledNestedRemoteAction,
- proxyBundledNestedRemoteAction,
- ],
- [
- remoteActionBundle.bundledDefaultRemoteAction,
- proxyBundledDefaultRemoteAction,
- ],
- ] as const;
- const remoteActionIdToHostProxyActionEntries =
- remoteActionToHostProxyActionPairs
- .map(([remoteAction, hostProxyAction]) => [
- getServerActionId(remoteAction),
- getServerActionId(hostProxyAction),
- ])
- .filter((pair): pair is [string, string] => Boolean(pair[0] && pair[1]));
- const hostProxyActionDebugKeys = hostProxyActions.map(
- (action, index) =>
- [action, getServerActionId(action) ?? `proxy-action-${index}`] as const,
- );
- const hostProxyManifestForms = hostProxyActionDebugKeys.map(
- ([action, actionId]) => ,
- );
- const remoteActionIdToHostProxyActionId = Object.fromEntries(
- remoteActionIdToHostProxyActionEntries,
- );
- const remoteActionIdMapKeyCount = Object.keys(
- remoteActionIdToHostProxyActionId,
- ).length;
- const remoteActionIdMapKey = JSON.stringify(
- Object.entries(remoteActionIdToHostProxyActionId).sort(([left], [right]) =>
- left.localeCompare(right),
- ),
- );
- const remoteActionIdMapEntryCount =
- remoteActionIdToHostProxyActionEntries.length;
- const remoteActionIdMapCollisionCount = Math.max(
- remoteActionIdMapEntryCount - remoteActionIdMapKeyCount,
- 0,
- );
- const mappedHostProxyActionIds = Array.from(
- new Set(Object.values(remoteActionIdToHostProxyActionId)),
- ).sort();
- const doesMappingCoverAllHostProxyActions =
- mappedHostProxyActionIds.length <= uniqueHostProxyActionIds.length &&
- mappedHostProxyActionIds.every(actionId =>
- uniqueHostProxyActionIds.includes(actionId),
- );
- const doesMappingExactlyMatchAllHostProxyActions =
- mappedHostProxyActionIds.length === uniqueHostProxyActionIds.length &&
- mappedHostProxyActionIds.every(
- (actionId, index) => actionId === uniqueHostProxyActionIds[index],
- );
-
const remoteServerOnlyInfo = getServerOnlyInfo();
const remoteServerOnlyDefaultInfo = getServerOnlyDefaultInfo();
const remoteMetaLabel = getRemoteMetaLabel();
@@ -177,46 +35,6 @@ const App = () => {
{remoteInfoBundle.bundledRemoteMeta.kind}
{bundledRemoteMetaLabel}
-
- {uniqueHostProxyActionIdsCount}
-
-
- {remoteActionIdMapEntryCount}
-
- {remoteActionIdMapKeyCount}
-
- {remoteActionIdMapCollisionCount}
-
-
- {mappedHostProxyActionIds.join(',')}
-
-
- {String(doesMappingCoverAllHostProxyActions)}
-
-
- {String(doesMappingExactlyMatchAllHostProxyActions)}
-
-
- {uniqueHostProxyActionIds.join(',')}
-
-
- {directHostProxyActionIds.join(',')}
-
-
- {bundledHostProxyActionIds.join(',')}
-
-
- {incrementProxyActionIds.join(',')}
-
-
- {echoProxyActionIds.join(',')}
-
-
- {nestedProxyActionIds.join(',')}
-
-
- {defaultProxyActionIds.join(',')}
-
Loading Remote Async Server Info...}>
@@ -224,12 +42,7 @@ const App = () => {
Loading Remote RSC...}>
- {/* Anchor host proxy actions in the server action manifest. */}
- {hostProxyManifestForms}
-
+
);
};
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index d34f161ce05e..f80f09467491 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -9,13 +9,7 @@ import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { nestedRemoteAction } from 'rscRemote/nestedActions';
import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
-export default function HostRemoteActionRunner({
- remoteActionIdMapKey,
- remoteActionIdToHostProxyActionId,
-}: {
- remoteActionIdMapKey: string;
- remoteActionIdToHostProxyActionId: Record;
-}) {
+export default function HostRemoteActionRunner() {
// Keep this import in the client graph so federated RSC bridge IDs
// can map back to a concrete remote module factory at runtime.
void RemoteClientCounterBridge;
@@ -30,14 +24,11 @@ export default function HostRemoteActionRunner({
const [isPending, setIsPending] = useState(false);
useEffect(() => {
- // Register once with host endpoint + id mapping so remote client-side
- // server actions are routed through host proxy actions.
registerRemoteServerCallback(
`${window.location.origin}/server-component-root`,
'rscRemote',
- remoteActionIdToHostProxyActionId,
);
- }, [remoteActionIdMapKey]);
+ }, []);
const runActions = async () => {
setIsPending(true);
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts b/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
deleted file mode 100644
index fb6319bbefab..000000000000
--- a/tests/integration/rsc-mf/host/src/server-component-root/remoteActionProxy.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-'use server';
-
-export async function proxyIncrementRemoteCount(
- previousState: number,
- formData: FormData,
-) {
- const remote = await import('rscRemote/actions');
- return remote.incrementRemoteCount(previousState, formData);
-}
-
-export async function proxyRemoteActionEcho(value: string) {
- const remote = await import('rscRemote/actions');
- return remote.remoteActionEcho(value);
-}
-
-export async function proxyNestedRemoteAction(value: string) {
- const remote = await import('rscRemote/nestedActions');
- return remote.nestedRemoteAction(value);
-}
-
-export async function proxyDefaultRemoteAction(value: string) {
- const remote = await import('rscRemote/defaultAction');
- return remote.defaultRemoteAction(value);
-}
-
-export async function proxyBundledIncrementRemoteCount(
- previousState: number,
- formData: FormData,
-) {
- const remote = await import('rscRemote/actionBundle');
- return remote.bundledIncrementRemoteCount(previousState, formData);
-}
-
-export async function proxyBundledRemoteActionEcho(value: string) {
- const remote = await import('rscRemote/actionBundle');
- return remote.bundledRemoteActionEcho(value);
-}
-
-export async function proxyBundledNestedRemoteAction(value: string) {
- const remote = await import('rscRemote/actionBundle');
- return remote.bundledNestedRemoteAction(value);
-}
-
-export async function proxyBundledDefaultRemoteAction(value: string) {
- const remote = await import('rscRemote/actionBundle');
- return remote.bundledDefaultRemoteAction(value);
-}
diff --git a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
index 1ca1b6e65cb1..39a7efea8681 100644
--- a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
@@ -6,13 +6,6 @@ import {
} from 'rsc-mf-react-server-dom-client-browser';
let registeredCallbackKey = '';
-const getStableProxyActionIdEntries = (
- remoteActionIdToHostProxyActionId?: Record,
-) =>
- Object.entries(remoteActionIdToHostProxyActionId ?? {}).sort(
- ([left], [right]) => left.localeCompare(right),
- );
-
const getHostActionId = (rawActionId: string, remoteAlias: string) => {
if (rawActionId.startsWith('remote:')) {
return rawActionId;
@@ -24,7 +17,6 @@ const getHostActionId = (rawActionId: string, remoteAlias: string) => {
export function registerRemoteServerCallback(
remoteOrigin: string,
remoteAlias = 'rscRemote',
- remoteActionIdToHostProxyActionId?: Record,
) {
if (!remoteOrigin) {
return;
@@ -32,9 +24,6 @@ export function registerRemoteServerCallback(
const callbackKey = JSON.stringify({
remoteAlias,
remoteOrigin,
- remoteActionIdToHostProxyActionId: getStableProxyActionIdEntries(
- remoteActionIdToHostProxyActionId,
- ),
});
if (registeredCallbackKey === callbackKey) {
return;
@@ -42,9 +31,7 @@ export function registerRemoteServerCallback(
const remoteActionUrl = new URL(remoteOrigin).toString();
setServerCallback(async (id, args) => {
- const hostActionId =
- remoteActionIdToHostProxyActionId?.[id] ||
- getHostActionId(id, remoteAlias);
+ const hostActionId = getHostActionId(id, remoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
const response = fetch(remoteActionUrl, {
method: 'POST',
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 31cc14de4006..7c990950f960 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -90,20 +90,6 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
expect(html).toContain('Remote Default Server Card');
expect(html).toContain('host-remote-bundled-server-only');
expect(html).toContain('host-remote-bundled-meta-kind');
- expect(html).toContain('host-proxy-action-id-count');
- expect(html).toContain('host-proxy-map-entry-count');
- expect(html).toContain('host-proxy-map-key-count');
- expect(html).toContain('host-proxy-map-collision-count');
- expect(html).toContain('host-mapped-proxy-action-ids');
- expect(html).toContain('host-proxy-map-covers-all');
- expect(html).toContain('host-proxy-map-equals-all');
- expect(html).toContain('host-proxy-action-ids');
- expect(html).toContain('host-direct-proxy-action-ids');
- expect(html).toContain('host-bundled-proxy-action-ids');
- expect(html).toContain('host-increment-proxy-action-ids');
- expect(html).toContain('host-echo-proxy-action-ids');
- expect(html).toContain('host-nested-proxy-action-ids');
- expect(html).toContain('host-default-proxy-action-ids');
await page.goto(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
@@ -148,223 +134,6 @@ async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
el => el.textContent?.trim(),
);
expect(hostRemoteBundledMetaLabel).toBe('rsc|mf|actions');
- const hostProxyActionIdCount = await page.$eval(
- '.host-proxy-action-id-count',
- el => el.textContent?.trim(),
- );
- expect(hostProxyActionIdCount).toBe('8');
- const hostProxyMapEntryCount = await page.$eval(
- '.host-proxy-map-entry-count',
- el => el.textContent?.trim(),
- );
- expect(hostProxyMapEntryCount).toBe('8');
- const hostProxyMapKeyCount = await page.$eval(
- '.host-proxy-map-key-count',
- el => el.textContent?.trim(),
- );
- expect(Number(hostProxyMapKeyCount)).toBeGreaterThan(0);
- expect(Number(hostProxyMapKeyCount)).toBeLessThanOrEqual(
- Number(hostProxyMapEntryCount),
- );
- const hostProxyMapCollisionCount = await page.$eval(
- '.host-proxy-map-collision-count',
- el => el.textContent?.trim(),
- );
- expect(Number(hostProxyMapCollisionCount)).toBeGreaterThanOrEqual(0);
- expect(Number(hostProxyMapCollisionCount)).toBe(
- Number(hostProxyMapEntryCount) - Number(hostProxyMapKeyCount),
- );
- const hostMappedProxyActionIds = await page.$eval(
- '.host-mapped-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostMappedProxyActionIdList = hostMappedProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostMappedProxyActionIdList.length).toBe(Number(hostProxyMapKeyCount));
- const hostProxyMapCoversAll = await page.$eval(
- '.host-proxy-map-covers-all',
- el => el.textContent?.trim(),
- );
- expect(hostProxyMapCoversAll).toBe('true');
- const hostProxyMapEqualsAll = await page.$eval(
- '.host-proxy-map-equals-all',
- el => el.textContent?.trim(),
- );
- expect(hostProxyMapEqualsAll).toBe(
- Number(hostProxyMapKeyCount) === Number(hostProxyMapEntryCount)
- ? 'true'
- : 'false',
- );
- const hostProxyActionIds = await page.$eval('.host-proxy-action-ids', el =>
- el.textContent?.trim(),
- );
- const hostProxyActionIdList = hostProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostProxyActionIdList.length).toBe(8);
- expect(hostProxyActionIdList.length).toBe(Number(hostProxyMapEntryCount));
- expect(new Set(hostProxyActionIdList).size).toBe(8);
- expect(hostProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
- true,
- );
- const sortedHostProxyActionIds = [...hostProxyActionIdList].sort();
- const sortedMappedProxyActionIds = [...hostMappedProxyActionIdList].sort();
- expect(
- sortedMappedProxyActionIds.every(mappedId =>
- sortedHostProxyActionIds.includes(mappedId),
- ),
- ).toBe(true);
- const hostDirectProxyActionIds = await page.$eval(
- '.host-direct-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostDirectProxyActionIdList = hostDirectProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostDirectProxyActionIdList.length).toBe(4);
- const hostBundledProxyActionIds = await page.$eval(
- '.host-bundled-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostBundledProxyActionIdList = hostBundledProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostBundledProxyActionIdList.length).toBe(4);
- const hostIncrementProxyActionIds = await page.$eval(
- '.host-increment-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostIncrementProxyActionIdList = hostIncrementProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostIncrementProxyActionIdList.length).toBe(2);
- expect(
- hostIncrementProxyActionIdList.every(id =>
- hostProxyActionIdList.includes(id),
- ),
- ).toBe(true);
- expect(
- hostIncrementProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
- ).toBe(true);
- const hostEchoProxyActionIds = await page.$eval(
- '.host-echo-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostEchoProxyActionIdList = hostEchoProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostEchoProxyActionIdList.length).toBe(2);
- expect(
- hostEchoProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
- ).toBe(true);
- expect(
- hostEchoProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
- ).toBe(true);
- const hostNestedProxyActionIds = await page.$eval(
- '.host-nested-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostNestedProxyActionIdList = hostNestedProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostNestedProxyActionIdList.length).toBe(2);
- expect(
- hostNestedProxyActionIdList.every(id => hostProxyActionIdList.includes(id)),
- ).toBe(true);
- expect(
- hostNestedProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
- ).toBe(true);
- const hostDefaultProxyActionIds = await page.$eval(
- '.host-default-proxy-action-ids',
- el => el.textContent?.trim(),
- );
- const hostDefaultProxyActionIdList = hostDefaultProxyActionIds
- ?.split(',')
- .filter(Boolean) as string[];
- expect(hostDefaultProxyActionIdList.length).toBe(2);
- expect(
- hostDefaultProxyActionIdList.every(id =>
- hostProxyActionIdList.includes(id),
- ),
- ).toBe(true);
- expect(
- hostDefaultProxyActionIdList.every(id => /^[a-f0-9]{64,}$/i.test(id)),
- ).toBe(true);
- const getGroupMembershipCount = (
- actionIds: string[],
- groupIds: string[],
- ): number => actionIds.filter(id => groupIds.includes(id)).length;
- expect(
- getGroupMembershipCount(
- hostIncrementProxyActionIdList,
- hostDirectProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostIncrementProxyActionIdList,
- hostBundledProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostEchoProxyActionIdList,
- hostDirectProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostEchoProxyActionIdList,
- hostBundledProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostNestedProxyActionIdList,
- hostDirectProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostNestedProxyActionIdList,
- hostBundledProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostDefaultProxyActionIdList,
- hostDirectProxyActionIdList,
- ),
- ).toBe(1);
- expect(
- getGroupMembershipCount(
- hostDefaultProxyActionIdList,
- hostBundledProxyActionIdList,
- ),
- ).toBe(1);
- const familyProxyActionIdUnion = new Set([
- ...hostIncrementProxyActionIdList,
- ...hostEchoProxyActionIdList,
- ...hostNestedProxyActionIdList,
- ...hostDefaultProxyActionIdList,
- ]);
- expect(familyProxyActionIdUnion.size).toBe(hostProxyActionIdList.length);
- expect(
- hostProxyActionIdList.every(actionId =>
- familyProxyActionIdUnion.has(actionId),
- ),
- ).toBe(true);
- const groupedProxyActionIdUnion = new Set([
- ...hostDirectProxyActionIdList,
- ...hostBundledProxyActionIdList,
- ]);
- expect(groupedProxyActionIdUnion.size).toBe(hostProxyActionIdList.length);
- expect(
- hostProxyActionIdList.every(actionId =>
- groupedProxyActionIdUnion.has(actionId),
- ),
- ).toBe(true);
const hostRemoteAsyncServerInfo = await page.$eval(
'.remote-async-server-info',
el => el.textContent?.trim(),
@@ -673,175 +442,18 @@ function runTests({ mode }: TestConfig) {
).toBe(true);
});
- it('should post host-resolvable action ids for remote actions', async () => {
+ it('should post bridge-prefixed action ids for remote actions', async () => {
expect(actionRequestIds.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestIds.length).toBe(actionRequestUrls.length);
const uniqueActionRequestIds = new Set(actionRequestIds);
- expect(actionRequestIds.every(id => !id.startsWith('remote:'))).toBe(
- true,
- );
- expect(actionRequestIds.every(id => /^[a-f0-9]{64,}$/i.test(id))).toBe(
- true,
- );
+ expect(
+ actionRequestIds.every(id =>
+ /^remote:rscRemote:[a-f0-9]{64,}$/i.test(id),
+ ),
+ ).toBe(true);
expect(uniqueActionRequestIds.size).toBe(
EXPECTED_UNIQUE_ACTION_IDS_PER_MODE,
);
- const hostProxyActionIdSet = new Set(
- (await page.$eval('.host-proxy-action-ids', el => el.textContent || ''))
- .split(',')
- .filter(Boolean),
- );
- expect(actionRequestIds.every(id => hostProxyActionIdSet.has(id))).toBe(
- true,
- );
- const mappedProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-mapped-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const hostProxyMapKeyCount = Number(
- await page.$eval(
- '.host-proxy-map-key-count',
- el => el.textContent || '0',
- ),
- );
- const hostProxyMapEntryCount = Number(
- await page.$eval(
- '.host-proxy-map-entry-count',
- el => el.textContent || '0',
- ),
- );
- const hostProxyMapCollisionCount = Number(
- await page.$eval(
- '.host-proxy-map-collision-count',
- el => el.textContent || '0',
- ),
- );
- expect(hostProxyMapKeyCount).toBe(mappedProxyActionIdSet.size);
- expect(uniqueActionRequestIds.size).toBeLessThanOrEqual(
- hostProxyMapKeyCount,
- );
- expect(hostProxyMapCollisionCount).toBe(
- hostProxyMapEntryCount - hostProxyMapKeyCount,
- );
- expect(actionRequestIds.every(id => mappedProxyActionIdSet.has(id))).toBe(
- true,
- );
- const directProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-direct-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const bundledProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-bundled-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const usesDirectProxyIds = actionRequestIds.some(id =>
- directProxyActionIdSet.has(id),
- );
- const usesBundledProxyIds = actionRequestIds.some(id =>
- bundledProxyActionIdSet.has(id),
- );
- const incrementProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-increment-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const echoProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-echo-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const nestedProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-nested-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const defaultProxyActionIdSet = new Set(
- (
- await page.$eval(
- '.host-default-proxy-action-ids',
- el => el.textContent || '',
- )
- )
- .split(',')
- .filter(Boolean),
- );
- const actionFamilyProxyActionIdSet = new Set([
- ...incrementProxyActionIdSet,
- ...echoProxyActionIdSet,
- ...nestedProxyActionIdSet,
- ...defaultProxyActionIdSet,
- ]);
- const getSetIntersectionSize = (left: Set, right: Set) =>
- [...left].filter(id => right.has(id)).length;
- expect(
- getSetIntersectionSize(incrementProxyActionIdSet, echoProxyActionIdSet),
- ).toBe(0);
- expect(
- getSetIntersectionSize(
- incrementProxyActionIdSet,
- nestedProxyActionIdSet,
- ),
- ).toBe(0);
- expect(
- getSetIntersectionSize(
- incrementProxyActionIdSet,
- defaultProxyActionIdSet,
- ),
- ).toBe(0);
- expect(
- getSetIntersectionSize(echoProxyActionIdSet, nestedProxyActionIdSet),
- ).toBe(0);
- expect(
- getSetIntersectionSize(echoProxyActionIdSet, defaultProxyActionIdSet),
- ).toBe(0);
- expect(
- getSetIntersectionSize(nestedProxyActionIdSet, defaultProxyActionIdSet),
- ).toBe(0);
- const incrementRequestCount = actionRequestIds.filter(id =>
- incrementProxyActionIdSet.has(id),
- ).length;
- const echoRequestCount = actionRequestIds.filter(id =>
- echoProxyActionIdSet.has(id),
- ).length;
- const nestedRequestCount = actionRequestIds.filter(id =>
- nestedProxyActionIdSet.has(id),
- ).length;
- const defaultRequestCount = actionRequestIds.filter(id =>
- defaultProxyActionIdSet.has(id),
- ).length;
const actionRequestCountById = new Map();
for (const actionId of actionRequestIds) {
actionRequestCountById.set(
@@ -849,49 +461,12 @@ function runTests({ mode }: TestConfig) {
(actionRequestCountById.get(actionId) || 0) + 1,
);
}
- expect(actionFamilyProxyActionIdSet.size).toBe(hostProxyActionIdSet.size);
- expect(uniqueActionRequestIds.size).toBe(hostProxyMapKeyCount);
expect(actionRequestCountById.size).toBe(uniqueActionRequestIds.size);
expect(
[...actionRequestCountById.values()].every(
count => count === EXPECTED_ACTION_POSTS_PER_FAMILY,
),
).toBe(true);
- expect(usesDirectProxyIds || usesBundledProxyIds).toBe(true);
- if (!usesDirectProxyIds || !usesBundledProxyIds) {
- expect(hostProxyMapCollisionCount).toBeGreaterThan(0);
- }
- expect(
- actionRequestIds.some(id => incrementProxyActionIdSet.has(id)),
- ).toBe(true);
- expect(actionRequestIds.some(id => echoProxyActionIdSet.has(id))).toBe(
- true,
- );
- expect(actionRequestIds.some(id => nestedProxyActionIdSet.has(id))).toBe(
- true,
- );
- expect(actionRequestIds.some(id => defaultProxyActionIdSet.has(id))).toBe(
- true,
- );
- expect(incrementRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
- expect(echoRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
- expect(nestedRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
- expect(defaultRequestCount).toBe(EXPECTED_ACTION_POSTS_PER_FAMILY);
- expect(
- incrementRequestCount +
- echoRequestCount +
- nestedRequestCount +
- defaultRequestCount,
- ).toBe(actionRequestIds.length);
- expect(
- actionRequestIds.every(id => actionFamilyProxyActionIdSet.has(id)),
- ).toBe(true);
- expect(
- actionRequestIds.every(
- id =>
- directProxyActionIdSet.has(id) || bundledProxyActionIdSet.has(id),
- ),
- ).toBe(true);
});
it('should have no browser runtime errors', () => {
From 301a7b40f71ad0911c1f703f6590d190b9c75c54 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:23:29 +0000
Subject: [PATCH 117/324] refactor(rsc-mf): auto-register remote callback in
federated client
---
.../server-component-root/HostRemoteActionRunner.tsx | 10 +---------
.../rsc-mf/remote/module-federation.config.ts | 4 ----
.../remote/src/components/RemoteClientCounter.tsx | 10 +++++++++-
3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index f80f09467491..a3d6047f21df 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -1,13 +1,12 @@
'use client';
-import { useEffect, useState } from 'react';
+import { useState } from 'react';
import RemoteClientBadge from 'rscRemote/RemoteClientBadge';
import { RemoteClientCounter as RemoteClientCounterBridge } from 'rscRemote/RemoteClientCounter';
import * as remoteActionBundle from 'rscRemote/actionBundle';
import { incrementRemoteCount, remoteActionEcho } from 'rscRemote/actions';
import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { nestedRemoteAction } from 'rscRemote/nestedActions';
-import { registerRemoteServerCallback } from 'rscRemote/registerServerCallback';
export default function HostRemoteActionRunner() {
// Keep this import in the client graph so federated RSC bridge IDs
@@ -23,13 +22,6 @@ export default function HostRemoteActionRunner() {
const [bundledIncrementResult, setBundledIncrementResult] = useState('');
const [isPending, setIsPending] = useState(false);
- useEffect(() => {
- registerRemoteServerCallback(
- `${window.location.origin}/server-component-root`,
- 'rscRemote',
- );
- }, []);
-
const runActions = async () => {
setIsPending(true);
try {
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 8c2a687d83f6..45423e836355 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -163,10 +163,6 @@ export default createModuleFederationConfig({
import: './src/components/infoBundle.ts',
layer: LAYERS.rsc,
} as any,
- './registerServerCallback': {
- import: './src/components/registerServerCallback.ts',
- layer: LAYERS.rsc,
- } as any,
},
shared: sharedByScope as any,
dts: false,
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
index 67483b2203b5..efd75f72924a 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -1,11 +1,19 @@
'use client';
-import { useActionState, useState } from 'react';
+import { useActionState, useEffect, useState } from 'react';
import './RemoteClientCounter.css';
import { incrementRemoteCount, remoteActionEcho } from './actions';
import { defaultRemoteAction } from './defaultAction';
import { nestedRemoteAction } from './nestedActions';
+import { registerRemoteServerCallback } from './registerServerCallback';
export function RemoteClientCounter() {
+ useEffect(() => {
+ const actionPathname = window.location.pathname || '/';
+ registerRemoteServerCallback(
+ `${window.location.origin}${actionPathname}`,
+ 'rscRemote',
+ );
+ }, []);
const [localCount, setLocalCount] = useState(0);
const [serverCount, formAction, isPending] = useActionState(
incrementRemoteCount,
From 72e8c86108210173fbb94f9a38a8af0a44cd92da Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:27:15 +0000
Subject: [PATCH 118/324] test(rsc-mf): assert callback helper no longer needs
expose
---
tests/integration/rsc-mf/tests/index.test.ts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 7c990950f960..2c7020bc51c6 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -416,6 +416,20 @@ function runTests({ mode }: TestConfig) {
it('should render remote RSC content in host app', () =>
renderRemoteRscIntoHost({ hostPort, page }));
+ it('should not require exposing callback registration helper', async () => {
+ const manifestResponse = await fetch(
+ `http://127.0.0.1:${remotePort}/static/mf-manifest.json`,
+ );
+ expect(manifestResponse.ok).toBe(true);
+ const manifest = (await manifestResponse.json()) as {
+ exposes?: Array<{ path?: string }>;
+ };
+ const exposedPaths = (manifest.exposes || [])
+ .map(item => item.path)
+ .filter((path): path is string => Boolean(path));
+ expect(exposedPaths).not.toContain('./registerServerCallback');
+ });
+
it('should support remote use client and server actions', () =>
supportRemoteClientAndServerActions({
hostPort,
From 13edc5b54f9f8055a8d6ffceec7afb89ab9cf6b3 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:30:20 +0000
Subject: [PATCH 119/324] refactor(rsc-mf): initialize callback bridge via
client side-effect module
---
.../remote/src/components/RemoteClientBadge.tsx | 1 +
.../remote/src/components/RemoteClientCounter.tsx | 11 ++---------
.../remote/src/components/initRemoteServerCallback.ts | 9 +++++++++
3 files changed, 12 insertions(+), 9 deletions(-)
create mode 100644 tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
index f46bcb0d5f33..bbcc58749fb7 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
@@ -1,6 +1,7 @@
'use client';
import 'client-only';
+import './initRemoteServerCallback';
import { useState } from 'react';
export default function RemoteClientBadge({
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
index efd75f72924a..c9c982781eac 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -1,19 +1,12 @@
'use client';
-import { useActionState, useEffect, useState } from 'react';
+import { useActionState, useState } from 'react';
import './RemoteClientCounter.css';
import { incrementRemoteCount, remoteActionEcho } from './actions';
import { defaultRemoteAction } from './defaultAction';
+import './initRemoteServerCallback';
import { nestedRemoteAction } from './nestedActions';
-import { registerRemoteServerCallback } from './registerServerCallback';
export function RemoteClientCounter() {
- useEffect(() => {
- const actionPathname = window.location.pathname || '/';
- registerRemoteServerCallback(
- `${window.location.origin}${actionPathname}`,
- 'rscRemote',
- );
- }, []);
const [localCount, setLocalCount] = useState(0);
const [serverCount, formAction, isPending] = useActionState(
incrementRemoteCount,
diff --git a/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
new file mode 100644
index 000000000000..cf0f113dbacc
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
@@ -0,0 +1,9 @@
+import { registerRemoteServerCallback } from './registerServerCallback';
+
+if (typeof window !== 'undefined') {
+ const actionPathname = window.location.pathname || '/';
+ registerRemoteServerCallback(
+ `${window.location.origin}${actionPathname}`,
+ 'rscRemote',
+ );
+}
From 8621bd2ab60747a303ccaba5f0ee7ed4139e32e4 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:35:27 +0000
Subject: [PATCH 120/324] test(rsc-mf): assert callback expose chunk is never
requested
---
tests/integration/rsc-mf/tests/index.test.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 2c7020bc51c6..eddbbd5a47f3 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -340,6 +340,7 @@ function runTests({ mode }: TestConfig) {
const runtimeErrors: string[] = [];
const actionRequestUrls: string[] = [];
const actionRequestIds: string[] = [];
+ const registerCallbackExposeRequestUrls: string[] = [];
if (skipForLowerNodeVersion()) {
return;
@@ -393,10 +394,14 @@ function runTests({ mode }: TestConfig) {
page.on('request', request => {
const headers = request.headers();
+ const url = request.url();
+ if (url.includes('__federation_expose_registerServerCallback')) {
+ registerCallbackExposeRequestUrls.push(url);
+ }
if (request.method() !== 'POST' || !headers['x-rsc-action']) {
return;
}
- actionRequestUrls.push(request.url());
+ actionRequestUrls.push(url);
actionRequestIds.push(headers['x-rsc-action']);
});
});
@@ -430,6 +435,10 @@ function runTests({ mode }: TestConfig) {
expect(exposedPaths).not.toContain('./registerServerCallback');
});
+ it('should not load callback helper expose chunk', () => {
+ expect(registerCallbackExposeRequestUrls).toEqual([]);
+ });
+
it('should support remote use client and server actions', () =>
supportRemoteClientAndServerActions({
hostPort,
From daaadd3fbe3507d44b6288440b3e5f8715caceb4 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:51:54 +0000
Subject: [PATCH 121/324] refactor(rsc-mf): centralize callback init in remote
counter entry
---
.../rsc-mf/remote/src/components/RemoteClientBadge.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
index bbcc58749fb7..f46bcb0d5f33 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientBadge.tsx
@@ -1,7 +1,6 @@
'use client';
import 'client-only';
-import './initRemoteServerCallback';
import { useState } from 'react';
export default function RemoteClientBadge({
From 18664e8600ee0986e4620936998e450f28f0cb7b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 02:57:28 +0000
Subject: [PATCH 122/324] docs(rsc-mf): clarify bridge callback helper intent
---
.../rsc-mf/remote/src/components/initRemoteServerCallback.ts | 2 ++
.../rsc-mf/remote/src/components/registerServerCallback.ts | 1 +
2 files changed, 3 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
index cf0f113dbacc..7d6b5ff31fba 100644
--- a/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
@@ -1,6 +1,8 @@
import { registerRemoteServerCallback } from './registerServerCallback';
if (typeof window !== 'undefined') {
+ // Fixture-level bootstrap: make federated client actions post back through
+ // host route using bridge-prefixed ids without requiring host userland wiring.
const actionPathname = window.location.pathname || '/';
registerRemoteServerCallback(
`${window.location.origin}${actionPathname}`,
diff --git a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
index 39a7efea8681..8230bc186531 100644
--- a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
@@ -11,6 +11,7 @@ const getHostActionId = (rawActionId: string, remoteAlias: string) => {
return rawActionId;
}
+ // Align with RSC bridge action-id format expected by host runtime plugin.
return `remote:${remoteAlias}:${rawActionId}`;
};
From d6464ff573f9488685ea13236c5a2c0f0d9ea867 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:01:03 +0000
Subject: [PATCH 123/324] refactor(rsc-mf): move callback bootstrap to runtime
module
---
.../rsc-mf/remote/src/components/RemoteClientCounter.tsx | 2 +-
.../initServerCallback.ts} | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
rename tests/integration/rsc-mf/remote/src/{components/initRemoteServerCallback.ts => runtime/initServerCallback.ts} (80%)
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
index c9c982781eac..a2b83401551d 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -3,8 +3,8 @@ import { useActionState, useState } from 'react';
import './RemoteClientCounter.css';
import { incrementRemoteCount, remoteActionEcho } from './actions';
import { defaultRemoteAction } from './defaultAction';
-import './initRemoteServerCallback';
import { nestedRemoteAction } from './nestedActions';
+import '../runtime/initServerCallback';
export function RemoteClientCounter() {
const [localCount, setLocalCount] = useState(0);
diff --git a/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
similarity index 80%
rename from tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
rename to tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index 7d6b5ff31fba..c4f4794439b3 100644
--- a/tests/integration/rsc-mf/remote/src/components/initRemoteServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,4 +1,4 @@
-import { registerRemoteServerCallback } from './registerServerCallback';
+import { registerRemoteServerCallback } from '../components/registerServerCallback';
if (typeof window !== 'undefined') {
// Fixture-level bootstrap: make federated client actions post back through
From 7f870fab17db7f3913b9a3a99e16d22107893560 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:05:35 +0000
Subject: [PATCH 124/324] refactor(rsc-mf): route exposed modules through
runtime bootstrap wrappers
---
.../rsc-mf/remote/module-federation.config.ts | 14 +++++++-------
.../remote/src/components/RemoteClientCounter.tsx | 1 -
.../src/runtime/exposes/RemoteClientBadge.tsx | 2 ++
.../src/runtime/exposes/RemoteClientCounter.tsx | 2 ++
.../remote/src/runtime/exposes/actionBundle.ts | 2 ++
.../rsc-mf/remote/src/runtime/exposes/actions.ts | 5 +++++
.../remote/src/runtime/exposes/defaultAction.ts | 2 ++
.../remote/src/runtime/exposes/nestedActions.ts | 2 ++
8 files changed, 22 insertions(+), 8 deletions(-)
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 45423e836355..c16bdbacb477 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -108,15 +108,15 @@ export default createModuleFederationConfig({
filename: 'static/remoteEntry.js',
exposes: {
'./RemoteClientCounter': {
- import: './src/components/RemoteClientCounter.tsx',
+ import: './src/runtime/exposes/RemoteClientCounter.tsx',
layer: LAYERS.rsc,
} as any,
'./src/components/RemoteClientCounter.tsx': {
- import: './src/components/RemoteClientCounter.tsx',
+ import: './src/runtime/exposes/RemoteClientCounter.tsx',
layer: LAYERS.rsc,
} as any,
'./RemoteClientBadge': {
- import: './src/components/RemoteClientBadge.tsx',
+ import: './src/runtime/exposes/RemoteClientBadge.tsx',
layer: LAYERS.rsc,
} as any,
'./RemoteServerCard': {
@@ -144,19 +144,19 @@ export default createModuleFederationConfig({
layer: LAYERS.rsc,
} as any,
'./actions': {
- import: './src/components/actions.ts',
+ import: './src/runtime/exposes/actions.ts',
layer: LAYERS.rsc,
} as any,
'./nestedActions': {
- import: './src/components/nestedActions.ts',
+ import: './src/runtime/exposes/nestedActions.ts',
layer: LAYERS.rsc,
} as any,
'./defaultAction': {
- import: './src/components/defaultAction.ts',
+ import: './src/runtime/exposes/defaultAction.ts',
layer: LAYERS.rsc,
} as any,
'./actionBundle': {
- import: './src/components/actionBundle.ts',
+ import: './src/runtime/exposes/actionBundle.ts',
layer: LAYERS.rsc,
} as any,
'./infoBundle': {
diff --git a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
index a2b83401551d..67483b2203b5 100644
--- a/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
+++ b/tests/integration/rsc-mf/remote/src/components/RemoteClientCounter.tsx
@@ -4,7 +4,6 @@ import './RemoteClientCounter.css';
import { incrementRemoteCount, remoteActionEcho } from './actions';
import { defaultRemoteAction } from './defaultAction';
import { nestedRemoteAction } from './nestedActions';
-import '../runtime/initServerCallback';
export function RemoteClientCounter() {
const [localCount, setLocalCount] = useState(0);
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
new file mode 100644
index 000000000000..cfcb31341f50
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
@@ -0,0 +1,2 @@
+import '../initServerCallback';
+export { default } from '../../components/RemoteClientBadge';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
new file mode 100644
index 000000000000..2588359d1a1e
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
@@ -0,0 +1,2 @@
+import '../initServerCallback';
+export { RemoteClientCounter } from '../../components/RemoteClientCounter';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
new file mode 100644
index 000000000000..d168ead856f0
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
@@ -0,0 +1,2 @@
+import '../initServerCallback';
+export * from '../../components/actionBundle';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
new file mode 100644
index 000000000000..c2323499156d
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
@@ -0,0 +1,5 @@
+import '../initServerCallback';
+export {
+ incrementRemoteCount,
+ remoteActionEcho,
+} from '../../components/actions';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
new file mode 100644
index 000000000000..0cff7b09f27c
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
@@ -0,0 +1,2 @@
+import '../initServerCallback';
+export { defaultRemoteAction } from '../../components/defaultAction';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
new file mode 100644
index 000000000000..3ac8a55c06bd
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
@@ -0,0 +1,2 @@
+import '../initServerCallback';
+export { nestedRemoteAction } from '../../components/nestedActions';
From a86f3b569e993aa30e9a193b9e1df839a0df1a31 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:10:31 +0000
Subject: [PATCH 125/324] refactor(rsc-mf): move callback registration helper
into runtime namespace
---
.../integration/rsc-mf/remote/src/runtime/initServerCallback.ts | 2 +-
.../src/{components => runtime}/registerServerCallback.ts | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename tests/integration/rsc-mf/remote/src/{components => runtime}/registerServerCallback.ts (100%)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index c4f4794439b3..7d6b5ff31fba 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,4 +1,4 @@
-import { registerRemoteServerCallback } from '../components/registerServerCallback';
+import { registerRemoteServerCallback } from './registerServerCallback';
if (typeof window !== 'undefined') {
// Fixture-level bootstrap: make federated client actions post back through
diff --git a/tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
similarity index 100%
rename from tests/integration/rsc-mf/remote/src/components/registerServerCallback.ts
rename to tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
From 790f31518aea79808c5836450d94ba6fce0eb434 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:13:11 +0000
Subject: [PATCH 126/324] test(rsc-mf): assert callback wiring stays in runtime
modules
---
tests/integration/rsc-mf/tests/index.test.ts | 25 ++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index eddbbd5a47f3..74addcd96097 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -1,3 +1,4 @@
+import fs from 'fs';
import path from 'path';
import { isVersionAtLeast18 } from '@modern-js/utils';
import type { Browser, Page } from 'puppeteer';
@@ -435,6 +436,30 @@ function runTests({ mode }: TestConfig) {
expect(exposedPaths).not.toContain('./registerServerCallback');
});
+ it('should keep callback runtime wiring out of component sources', () => {
+ const remoteClientCounterSource = fs.readFileSync(
+ path.join(remoteDir, 'src/components/RemoteClientCounter.tsx'),
+ 'utf-8',
+ );
+ const remoteClientBadgeSource = fs.readFileSync(
+ path.join(remoteDir, 'src/components/RemoteClientBadge.tsx'),
+ 'utf-8',
+ );
+ const runtimeInitSource = fs.readFileSync(
+ path.join(remoteDir, 'src/runtime/initServerCallback.ts'),
+ 'utf-8',
+ );
+ expect(remoteClientCounterSource).not.toContain('initServerCallback');
+ expect(remoteClientCounterSource).not.toContain(
+ 'registerRemoteServerCallback',
+ );
+ expect(remoteClientBadgeSource).not.toContain('initServerCallback');
+ expect(remoteClientBadgeSource).not.toContain(
+ 'registerRemoteServerCallback',
+ );
+ expect(runtimeInitSource).toContain('registerRemoteServerCallback');
+ });
+
it('should not load callback helper expose chunk', () => {
expect(registerCallbackExposeRequestUrls).toEqual([]);
});
From f53e08588112b257018a2cdabb449e7fc1273244 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:16:26 +0000
Subject: [PATCH 127/324] test(rsc-mf): enforce runtime boundary across all
component sources
---
tests/integration/rsc-mf/tests/index.test.ts | 50 +++++++++++++++-----
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 74addcd96097..6ba3187818bc 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -437,27 +437,51 @@ function runTests({ mode }: TestConfig) {
});
it('should keep callback runtime wiring out of component sources', () => {
- const remoteClientCounterSource = fs.readFileSync(
- path.join(remoteDir, 'src/components/RemoteClientCounter.tsx'),
- 'utf-8',
+ const getFilesRecursively = (directory: string): string[] =>
+ fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
+ const entryPath = path.join(directory, entry.name);
+ if (entry.isDirectory()) {
+ return getFilesRecursively(entryPath);
+ }
+ return [entryPath];
+ });
+
+ const componentFilePaths = getFilesRecursively(
+ path.join(remoteDir, 'src/components'),
);
- const remoteClientBadgeSource = fs.readFileSync(
- path.join(remoteDir, 'src/components/RemoteClientBadge.tsx'),
- 'utf-8',
+ const exposeRuntimeFilePaths = getFilesRecursively(
+ path.join(remoteDir, 'src/runtime/exposes'),
+ );
+
+ const componentSources = componentFilePaths.map(filePath =>
+ fs.readFileSync(filePath, 'utf-8'),
);
const runtimeInitSource = fs.readFileSync(
path.join(remoteDir, 'src/runtime/initServerCallback.ts'),
'utf-8',
);
- expect(remoteClientCounterSource).not.toContain('initServerCallback');
- expect(remoteClientCounterSource).not.toContain(
- 'registerRemoteServerCallback',
- );
- expect(remoteClientBadgeSource).not.toContain('initServerCallback');
- expect(remoteClientBadgeSource).not.toContain(
- 'registerRemoteServerCallback',
+ const runtimeRegisterSource = fs.readFileSync(
+ path.join(remoteDir, 'src/runtime/registerServerCallback.ts'),
+ 'utf-8',
);
+
+ expect(
+ componentSources.every(
+ source => !source.includes('initServerCallback'),
+ ),
+ ).toBe(true);
+ expect(
+ componentSources.every(
+ source => !source.includes('registerRemoteServerCallback'),
+ ),
+ ).toBe(true);
+ expect(
+ exposeRuntimeFilePaths.every(filePath =>
+ fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
+ ),
+ ).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
+ expect(runtimeRegisterSource).toContain('setServerCallback');
});
it('should not load callback helper expose chunk', () => {
From 6b3054d643081a60d21db185da1e39b56b80de2d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:21:26 +0000
Subject: [PATCH 128/324] refactor(rsc-mf): funnel all remote exposes through
runtime boundary
---
.../rsc-mf/remote/module-federation.config.ts | 14 +++---
.../runtime/exposes/AsyncRemoteServerInfo.tsx | 1 +
.../src/runtime/exposes/RemoteServerCard.tsx | 1 +
.../runtime/exposes/RemoteServerDefault.tsx | 1 +
.../remote/src/runtime/exposes/infoBundle.ts | 1 +
.../remote/src/runtime/exposes/remoteMeta.ts | 1 +
.../src/runtime/exposes/remoteServerOnly.ts | 1 +
.../exposes/remoteServerOnlyDefault.ts | 1 +
tests/integration/rsc-mf/tests/index.test.ts | 44 +++++++++++++++++--
9 files changed, 55 insertions(+), 10 deletions(-)
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index c16bdbacb477..42b8226a1bb3 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -120,27 +120,27 @@ export default createModuleFederationConfig({
layer: LAYERS.rsc,
} as any,
'./RemoteServerCard': {
- import: './src/components/RemoteServerCard.tsx',
+ import: './src/runtime/exposes/RemoteServerCard.tsx',
layer: LAYERS.rsc,
} as any,
'./RemoteServerDefault': {
- import: './src/components/RemoteServerDefault.tsx',
+ import: './src/runtime/exposes/RemoteServerDefault.tsx',
layer: LAYERS.rsc,
} as any,
'./AsyncRemoteServerInfo': {
- import: './src/components/AsyncRemoteServerInfo.tsx',
+ import: './src/runtime/exposes/AsyncRemoteServerInfo.tsx',
layer: LAYERS.rsc,
} as any,
'./remoteServerOnly': {
- import: './src/components/serverOnly.ts',
+ import: './src/runtime/exposes/remoteServerOnly.ts',
layer: LAYERS.rsc,
} as any,
'./remoteServerOnlyDefault': {
- import: './src/components/serverOnlyDefault.ts',
+ import: './src/runtime/exposes/remoteServerOnlyDefault.ts',
layer: LAYERS.rsc,
} as any,
'./remoteMeta': {
- import: './src/components/remoteMeta.ts',
+ import: './src/runtime/exposes/remoteMeta.ts',
layer: LAYERS.rsc,
} as any,
'./actions': {
@@ -160,7 +160,7 @@ export default createModuleFederationConfig({
layer: LAYERS.rsc,
} as any,
'./infoBundle': {
- import: './src/components/infoBundle.ts',
+ import: './src/runtime/exposes/infoBundle.ts',
layer: LAYERS.rsc,
} as any,
},
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
new file mode 100644
index 000000000000..b7aca908fc89
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
@@ -0,0 +1 @@
+export { AsyncRemoteServerInfo } from '../../components/AsyncRemoteServerInfo';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
new file mode 100644
index 000000000000..07ba89f342fe
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
@@ -0,0 +1 @@
+export { default } from '../../components/RemoteServerCard';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
new file mode 100644
index 000000000000..9687ba8272e9
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
@@ -0,0 +1 @@
+export { default } from '../../components/RemoteServerDefault';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
new file mode 100644
index 000000000000..b52d877ae796
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
@@ -0,0 +1 @@
+export * from '../../components/infoBundle';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
new file mode 100644
index 000000000000..9d04431a939e
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
@@ -0,0 +1 @@
+export { default, getRemoteMetaLabel } from '../../components/remoteMeta';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
new file mode 100644
index 000000000000..9d8750a799d8
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
@@ -0,0 +1 @@
+export { getServerOnlyInfo } from '../../components/serverOnly';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
new file mode 100644
index 000000000000..479a159f4884
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
@@ -0,0 +1 @@
+export { default } from '../../components/serverOnlyDefault';
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6ba3187818bc..71e107b123e8 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -464,6 +464,10 @@ function runTests({ mode }: TestConfig) {
path.join(remoteDir, 'src/runtime/registerServerCallback.ts'),
'utf-8',
);
+ const moduleFederationConfigSource = fs.readFileSync(
+ path.join(remoteDir, 'module-federation.config.ts'),
+ 'utf-8',
+ );
expect(
componentSources.every(
@@ -476,12 +480,46 @@ function runTests({ mode }: TestConfig) {
),
).toBe(true);
expect(
- exposeRuntimeFilePaths.every(filePath =>
- fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
- ),
+ exposeRuntimeFilePaths
+ .filter(filePath =>
+ [
+ 'RemoteClientCounter.tsx',
+ 'RemoteClientBadge.tsx',
+ 'actions.ts',
+ 'nestedActions.ts',
+ 'defaultAction.ts',
+ 'actionBundle.ts',
+ ].includes(path.basename(filePath)),
+ )
+ .every(filePath =>
+ fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
+ ),
+ ).toBe(true);
+ expect(
+ exposeRuntimeFilePaths
+ .filter(
+ filePath =>
+ ![
+ 'RemoteClientCounter.tsx',
+ 'RemoteClientBadge.tsx',
+ 'actions.ts',
+ 'nestedActions.ts',
+ 'defaultAction.ts',
+ 'actionBundle.ts',
+ ].includes(path.basename(filePath)),
+ )
+ .every(
+ filePath =>
+ !fs
+ .readFileSync(filePath, 'utf-8')
+ .includes('initServerCallback'),
+ ),
).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
expect(runtimeRegisterSource).toContain('setServerCallback');
+ expect(moduleFederationConfigSource).not.toContain(
+ "import: './src/components/",
+ );
});
it('should not load callback helper expose chunk', () => {
From 9c2099a8509a4a9f22b1acaceea1ac4fa19da2aa Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:24:39 +0000
Subject: [PATCH 129/324] refactor(rsc-mf): define remote exposes from single
runtime map
---
.../rsc-mf/remote/module-federation.config.ts | 87 +++++++------------
1 file changed, 29 insertions(+), 58 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 42b8226a1bb3..b7d2509f2c67 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -14,6 +14,29 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
+const createRscExpose = (importPath: string) =>
+ ({
+ import: importPath,
+ layer: LAYERS.rsc,
+ }) as any;
+const remoteExposeImports: Record = {
+ './RemoteClientCounter': './src/runtime/exposes/RemoteClientCounter.tsx',
+ './src/components/RemoteClientCounter.tsx':
+ './src/runtime/exposes/RemoteClientCounter.tsx',
+ './RemoteClientBadge': './src/runtime/exposes/RemoteClientBadge.tsx',
+ './RemoteServerCard': './src/runtime/exposes/RemoteServerCard.tsx',
+ './RemoteServerDefault': './src/runtime/exposes/RemoteServerDefault.tsx',
+ './AsyncRemoteServerInfo': './src/runtime/exposes/AsyncRemoteServerInfo.tsx',
+ './remoteServerOnly': './src/runtime/exposes/remoteServerOnly.ts',
+ './remoteServerOnlyDefault':
+ './src/runtime/exposes/remoteServerOnlyDefault.ts',
+ './remoteMeta': './src/runtime/exposes/remoteMeta.ts',
+ './actions': './src/runtime/exposes/actions.ts',
+ './nestedActions': './src/runtime/exposes/nestedActions.ts',
+ './defaultAction': './src/runtime/exposes/defaultAction.ts',
+ './actionBundle': './src/runtime/exposes/actionBundle.ts',
+ './infoBundle': './src/runtime/exposes/infoBundle.ts',
+};
const sharedByScope = [
{
@@ -106,64 +129,12 @@ export default createModuleFederationConfig({
filePath: 'static',
},
filename: 'static/remoteEntry.js',
- exposes: {
- './RemoteClientCounter': {
- import: './src/runtime/exposes/RemoteClientCounter.tsx',
- layer: LAYERS.rsc,
- } as any,
- './src/components/RemoteClientCounter.tsx': {
- import: './src/runtime/exposes/RemoteClientCounter.tsx',
- layer: LAYERS.rsc,
- } as any,
- './RemoteClientBadge': {
- import: './src/runtime/exposes/RemoteClientBadge.tsx',
- layer: LAYERS.rsc,
- } as any,
- './RemoteServerCard': {
- import: './src/runtime/exposes/RemoteServerCard.tsx',
- layer: LAYERS.rsc,
- } as any,
- './RemoteServerDefault': {
- import: './src/runtime/exposes/RemoteServerDefault.tsx',
- layer: LAYERS.rsc,
- } as any,
- './AsyncRemoteServerInfo': {
- import: './src/runtime/exposes/AsyncRemoteServerInfo.tsx',
- layer: LAYERS.rsc,
- } as any,
- './remoteServerOnly': {
- import: './src/runtime/exposes/remoteServerOnly.ts',
- layer: LAYERS.rsc,
- } as any,
- './remoteServerOnlyDefault': {
- import: './src/runtime/exposes/remoteServerOnlyDefault.ts',
- layer: LAYERS.rsc,
- } as any,
- './remoteMeta': {
- import: './src/runtime/exposes/remoteMeta.ts',
- layer: LAYERS.rsc,
- } as any,
- './actions': {
- import: './src/runtime/exposes/actions.ts',
- layer: LAYERS.rsc,
- } as any,
- './nestedActions': {
- import: './src/runtime/exposes/nestedActions.ts',
- layer: LAYERS.rsc,
- } as any,
- './defaultAction': {
- import: './src/runtime/exposes/defaultAction.ts',
- layer: LAYERS.rsc,
- } as any,
- './actionBundle': {
- import: './src/runtime/exposes/actionBundle.ts',
- layer: LAYERS.rsc,
- } as any,
- './infoBundle': {
- import: './src/runtime/exposes/infoBundle.ts',
- layer: LAYERS.rsc,
- } as any,
- },
+ exposes: Object.fromEntries(
+ Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
+ exposeKey,
+ createRscExpose(importPath),
+ ]),
+ ) as any,
shared: sharedByScope as any,
dts: false,
experiments: {
From 90c4dacef5fd416ca483bcb97d719ba1c7b11d0e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:27:24 +0000
Subject: [PATCH 130/324] refactor(rsc-mf): guard runtime expose paths in
remote config
---
.../rsc-mf/remote/module-federation.config.ts | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index b7d2509f2c67..67c684dda339 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -19,6 +19,7 @@ const createRscExpose = (importPath: string) =>
import: importPath,
layer: LAYERS.rsc,
}) as any;
+const RUNTIME_EXPOSE_PREFIX = './src/runtime/exposes/';
const remoteExposeImports: Record = {
'./RemoteClientCounter': './src/runtime/exposes/RemoteClientCounter.tsx',
'./src/components/RemoteClientCounter.tsx':
@@ -37,6 +38,16 @@ const remoteExposeImports: Record = {
'./actionBundle': './src/runtime/exposes/actionBundle.ts',
'./infoBundle': './src/runtime/exposes/infoBundle.ts',
};
+const nonRuntimeExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !importPath.startsWith(RUNTIME_EXPOSE_PREFIX),
+);
+if (nonRuntimeExposeEntries.length > 0) {
+ throw new Error(
+ `All remote exposes must point to runtime wrappers (${RUNTIME_EXPOSE_PREFIX}). Invalid entries: ${nonRuntimeExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+}
const sharedByScope = [
{
From 4da2b0aaa6f21bbb8dee4e742380613f79845844 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:30:39 +0000
Subject: [PATCH 131/324] test(rsc-mf): validate callback bootstrap wrapper set
coverage
---
tests/integration/rsc-mf/tests/index.test.ts | 42 +++++++++-----------
1 file changed, 19 insertions(+), 23 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 71e107b123e8..3705d1cb83f2 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -20,6 +20,14 @@ const HOST_RSC_URL = '/server-component-root';
const EXPECTED_ACTION_POSTS_PER_MODE = 24;
const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
+const CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES = new Set([
+ 'RemoteClientCounter.tsx',
+ 'RemoteClientBadge.tsx',
+ 'actions.ts',
+ 'nestedActions.ts',
+ 'defaultAction.ts',
+ 'actionBundle.ts',
+]);
type Mode = 'dev' | 'build';
@@ -480,33 +488,21 @@ function runTests({ mode }: TestConfig) {
),
).toBe(true);
expect(
- exposeRuntimeFilePaths
- .filter(filePath =>
- [
- 'RemoteClientCounter.tsx',
- 'RemoteClientBadge.tsx',
- 'actions.ts',
- 'nestedActions.ts',
- 'defaultAction.ts',
- 'actionBundle.ts',
- ].includes(path.basename(filePath)),
- )
- .every(filePath =>
- fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
- ),
- ).toBe(true);
+ new Set(
+ exposeRuntimeFilePaths
+ .filter(filePath =>
+ fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
+ )
+ .map(filePath => path.basename(filePath)),
+ ),
+ ).toEqual(CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES);
expect(
exposeRuntimeFilePaths
.filter(
filePath =>
- ![
- 'RemoteClientCounter.tsx',
- 'RemoteClientBadge.tsx',
- 'actions.ts',
- 'nestedActions.ts',
- 'defaultAction.ts',
- 'actionBundle.ts',
- ].includes(path.basename(filePath)),
+ !CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES.has(
+ path.basename(filePath),
+ ),
)
.every(
filePath =>
From f8aabd06d927de297276da59b07bc4277bee8a2f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:33:53 +0000
Subject: [PATCH 132/324] test(rsc-mf): assert remote manifest avoids
source-path exposes
---
tests/integration/rsc-mf/remote/module-federation.config.ts | 2 --
tests/integration/rsc-mf/tests/index.test.ts | 3 +++
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 67c684dda339..c2d05397746d 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -22,8 +22,6 @@ const createRscExpose = (importPath: string) =>
const RUNTIME_EXPOSE_PREFIX = './src/runtime/exposes/';
const remoteExposeImports: Record = {
'./RemoteClientCounter': './src/runtime/exposes/RemoteClientCounter.tsx',
- './src/components/RemoteClientCounter.tsx':
- './src/runtime/exposes/RemoteClientCounter.tsx',
'./RemoteClientBadge': './src/runtime/exposes/RemoteClientBadge.tsx',
'./RemoteServerCard': './src/runtime/exposes/RemoteServerCard.tsx',
'./RemoteServerDefault': './src/runtime/exposes/RemoteServerDefault.tsx',
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 3705d1cb83f2..7e444096925b 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -442,6 +442,9 @@ function runTests({ mode }: TestConfig) {
.map(item => item.path)
.filter((path): path is string => Boolean(path));
expect(exposedPaths).not.toContain('./registerServerCallback');
+ expect(
+ exposedPaths.every(path => !path.startsWith('./src/components/')),
+ ).toBe(true);
});
it('should keep callback runtime wiring out of component sources', () => {
From 25443dc2b169a598e0f7ff4118c58c4fc410f1aa Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:44:40 +0000
Subject: [PATCH 133/324] refactor(rsc-mf): inline callback bootstrap in expose
imports
---
.../rsc-mf/remote/module-federation.config.ts | 55 +++++++++++--------
.../runtime/exposes/AsyncRemoteServerInfo.tsx | 1 -
.../src/runtime/exposes/RemoteClientBadge.tsx | 2 -
.../runtime/exposes/RemoteClientCounter.tsx | 2 -
.../src/runtime/exposes/RemoteServerCard.tsx | 1 -
.../runtime/exposes/RemoteServerDefault.tsx | 1 -
.../src/runtime/exposes/actionBundle.ts | 2 -
.../remote/src/runtime/exposes/actions.ts | 5 --
.../src/runtime/exposes/defaultAction.ts | 2 -
.../remote/src/runtime/exposes/infoBundle.ts | 1 -
.../src/runtime/exposes/nestedActions.ts | 2 -
.../remote/src/runtime/exposes/remoteMeta.ts | 1 -
.../src/runtime/exposes/remoteServerOnly.ts | 1 -
.../exposes/remoteServerOnlyDefault.ts | 1 -
tests/integration/rsc-mf/tests/index.test.ts | 54 +++++++-----------
15 files changed, 51 insertions(+), 80 deletions(-)
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
delete mode 100644 tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index c2d05397746d..e0f0ae3a7247 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -14,36 +14,43 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
-const createRscExpose = (importPath: string) =>
+const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
+const callbackBootstrappedExposes = new Set([
+ './RemoteClientCounter',
+ './RemoteClientBadge',
+ './actions',
+ './nestedActions',
+ './defaultAction',
+ './actionBundle',
+]);
+const createRscExpose = (exposeKey: string, importPath: string) =>
({
- import: importPath,
+ import: callbackBootstrappedExposes.has(exposeKey)
+ ? [CALLBACK_BOOTSTRAP_IMPORT, importPath]
+ : importPath,
layer: LAYERS.rsc,
}) as any;
-const RUNTIME_EXPOSE_PREFIX = './src/runtime/exposes/';
const remoteExposeImports: Record = {
- './RemoteClientCounter': './src/runtime/exposes/RemoteClientCounter.tsx',
- './RemoteClientBadge': './src/runtime/exposes/RemoteClientBadge.tsx',
- './RemoteServerCard': './src/runtime/exposes/RemoteServerCard.tsx',
- './RemoteServerDefault': './src/runtime/exposes/RemoteServerDefault.tsx',
- './AsyncRemoteServerInfo': './src/runtime/exposes/AsyncRemoteServerInfo.tsx',
- './remoteServerOnly': './src/runtime/exposes/remoteServerOnly.ts',
- './remoteServerOnlyDefault':
- './src/runtime/exposes/remoteServerOnlyDefault.ts',
- './remoteMeta': './src/runtime/exposes/remoteMeta.ts',
- './actions': './src/runtime/exposes/actions.ts',
- './nestedActions': './src/runtime/exposes/nestedActions.ts',
- './defaultAction': './src/runtime/exposes/defaultAction.ts',
- './actionBundle': './src/runtime/exposes/actionBundle.ts',
- './infoBundle': './src/runtime/exposes/infoBundle.ts',
+ './RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
+ './RemoteClientBadge': './src/components/RemoteClientBadge.tsx',
+ './RemoteServerCard': './src/components/RemoteServerCard.tsx',
+ './RemoteServerDefault': './src/components/RemoteServerDefault.tsx',
+ './AsyncRemoteServerInfo': './src/components/AsyncRemoteServerInfo.tsx',
+ './remoteServerOnly': './src/components/serverOnly.ts',
+ './remoteServerOnlyDefault': './src/components/serverOnlyDefault.ts',
+ './remoteMeta': './src/components/remoteMeta.ts',
+ './actions': './src/components/actions.ts',
+ './nestedActions': './src/components/nestedActions.ts',
+ './defaultAction': './src/components/defaultAction.ts',
+ './actionBundle': './src/components/actionBundle.ts',
+ './infoBundle': './src/components/infoBundle.ts',
};
-const nonRuntimeExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !importPath.startsWith(RUNTIME_EXPOSE_PREFIX),
+const missingCallbackExposeEntries = [...callbackBootstrappedExposes].filter(
+ exposeKey => !(exposeKey in remoteExposeImports),
);
-if (nonRuntimeExposeEntries.length > 0) {
+if (missingCallbackExposeEntries.length > 0) {
throw new Error(
- `All remote exposes must point to runtime wrappers (${RUNTIME_EXPOSE_PREFIX}). Invalid entries: ${nonRuntimeExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Callback-bootstrapped exposes must exist in remoteExposeImports. Missing entries: ${missingCallbackExposeEntries.join(', ')}`,
);
}
@@ -141,7 +148,7 @@ export default createModuleFederationConfig({
exposes: Object.fromEntries(
Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
exposeKey,
- createRscExpose(importPath),
+ createRscExpose(exposeKey, importPath),
]),
) as any,
shared: sharedByScope as any,
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
deleted file mode 100644
index b7aca908fc89..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/AsyncRemoteServerInfo.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { AsyncRemoteServerInfo } from '../../components/AsyncRemoteServerInfo';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
deleted file mode 100644
index cfcb31341f50..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientBadge.tsx
+++ /dev/null
@@ -1,2 +0,0 @@
-import '../initServerCallback';
-export { default } from '../../components/RemoteClientBadge';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
deleted file mode 100644
index 2588359d1a1e..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteClientCounter.tsx
+++ /dev/null
@@ -1,2 +0,0 @@
-import '../initServerCallback';
-export { RemoteClientCounter } from '../../components/RemoteClientCounter';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
deleted file mode 100644
index 07ba89f342fe..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerCard.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '../../components/RemoteServerCard';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx b/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
deleted file mode 100644
index 9687ba8272e9..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/RemoteServerDefault.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '../../components/RemoteServerDefault';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
deleted file mode 100644
index d168ead856f0..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/actionBundle.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import '../initServerCallback';
-export * from '../../components/actionBundle';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
deleted file mode 100644
index c2323499156d..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/actions.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import '../initServerCallback';
-export {
- incrementRemoteCount,
- remoteActionEcho,
-} from '../../components/actions';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
deleted file mode 100644
index 0cff7b09f27c..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/defaultAction.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import '../initServerCallback';
-export { defaultRemoteAction } from '../../components/defaultAction';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
deleted file mode 100644
index b52d877ae796..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/infoBundle.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from '../../components/infoBundle';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
deleted file mode 100644
index 3ac8a55c06bd..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/nestedActions.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import '../initServerCallback';
-export { nestedRemoteAction } from '../../components/nestedActions';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
deleted file mode 100644
index 9d04431a939e..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteMeta.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default, getRemoteMetaLabel } from '../../components/remoteMeta';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
deleted file mode 100644
index 9d8750a799d8..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnly.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { getServerOnlyInfo } from '../../components/serverOnly';
diff --git a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts b/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
deleted file mode 100644
index 479a159f4884..000000000000
--- a/tests/integration/rsc-mf/remote/src/runtime/exposes/remoteServerOnlyDefault.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '../../components/serverOnlyDefault';
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 7e444096925b..eaa4b29b0bb5 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -20,13 +20,13 @@ const HOST_RSC_URL = '/server-component-root';
const EXPECTED_ACTION_POSTS_PER_MODE = 24;
const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
-const CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES = new Set([
- 'RemoteClientCounter.tsx',
- 'RemoteClientBadge.tsx',
- 'actions.ts',
- 'nestedActions.ts',
- 'defaultAction.ts',
- 'actionBundle.ts',
+const CALLBACK_BOOTSTRAPPED_EXPOSE_KEYS = new Set([
+ './RemoteClientCounter',
+ './RemoteClientBadge',
+ './actions',
+ './nestedActions',
+ './defaultAction',
+ './actionBundle',
]);
type Mode = 'dev' | 'build';
@@ -460,9 +460,6 @@ function runTests({ mode }: TestConfig) {
const componentFilePaths = getFilesRecursively(
path.join(remoteDir, 'src/components'),
);
- const exposeRuntimeFilePaths = getFilesRecursively(
- path.join(remoteDir, 'src/runtime/exposes'),
- );
const componentSources = componentFilePaths.map(filePath =>
fs.readFileSync(filePath, 'utf-8'),
@@ -490,35 +487,24 @@ function runTests({ mode }: TestConfig) {
source => !source.includes('registerRemoteServerCallback'),
),
).toBe(true);
+ expect(runtimeInitSource).toContain('registerRemoteServerCallback');
+ expect(runtimeRegisterSource).toContain('setServerCallback');
+ expect(moduleFederationConfigSource).toContain(
+ 'CALLBACK_BOOTSTRAP_IMPORT',
+ );
expect(
- new Set(
- exposeRuntimeFilePaths
- .filter(filePath =>
- fs.readFileSync(filePath, 'utf-8').includes('initServerCallback'),
- )
- .map(filePath => path.basename(filePath)),
+ moduleFederationConfigSource.includes(
+ '[CALLBACK_BOOTSTRAP_IMPORT, importPath]',
),
- ).toEqual(CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES);
- expect(
- exposeRuntimeFilePaths
- .filter(
- filePath =>
- !CALLBACK_BOOTSTRAPPED_RUNTIME_EXPOSE_FILES.has(
- path.basename(filePath),
- ),
- )
- .every(
- filePath =>
- !fs
- .readFileSync(filePath, 'utf-8')
- .includes('initServerCallback'),
- ),
).toBe(true);
- expect(runtimeInitSource).toContain('registerRemoteServerCallback');
- expect(runtimeRegisterSource).toContain('setServerCallback');
expect(moduleFederationConfigSource).not.toContain(
- "import: './src/components/",
+ './src/runtime/exposes/',
);
+ expect(
+ [...CALLBACK_BOOTSTRAPPED_EXPOSE_KEYS].every(exposeKey =>
+ moduleFederationConfigSource.includes(exposeKey),
+ ),
+ ).toBe(true);
});
it('should not load callback helper expose chunk', () => {
From 2ef0c802a89e47237b03c9d1595951974aad933b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:48:08 +0000
Subject: [PATCH 134/324] refactor(rsc-mf): bootstrap callback for all remote
exposes
---
.../rsc-mf/remote/module-federation.config.ts | 24 +++----------------
.../remote/src/runtime/initServerCallback.ts | 18 +++++++-------
tests/integration/rsc-mf/tests/index.test.ts | 19 +++++----------
3 files changed, 19 insertions(+), 42 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index e0f0ae3a7247..7874096135fd 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -15,19 +15,9 @@ const reactDomServerImport = path.join(
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
-const callbackBootstrappedExposes = new Set([
- './RemoteClientCounter',
- './RemoteClientBadge',
- './actions',
- './nestedActions',
- './defaultAction',
- './actionBundle',
-]);
-const createRscExpose = (exposeKey: string, importPath: string) =>
+const createRscExpose = (importPath: string) =>
({
- import: callbackBootstrappedExposes.has(exposeKey)
- ? [CALLBACK_BOOTSTRAP_IMPORT, importPath]
- : importPath,
+ import: [CALLBACK_BOOTSTRAP_IMPORT, importPath],
layer: LAYERS.rsc,
}) as any;
const remoteExposeImports: Record = {
@@ -45,14 +35,6 @@ const remoteExposeImports: Record = {
'./actionBundle': './src/components/actionBundle.ts',
'./infoBundle': './src/components/infoBundle.ts',
};
-const missingCallbackExposeEntries = [...callbackBootstrappedExposes].filter(
- exposeKey => !(exposeKey in remoteExposeImports),
-);
-if (missingCallbackExposeEntries.length > 0) {
- throw new Error(
- `Callback-bootstrapped exposes must exist in remoteExposeImports. Missing entries: ${missingCallbackExposeEntries.join(', ')}`,
- );
-}
const sharedByScope = [
{
@@ -148,7 +130,7 @@ export default createModuleFederationConfig({
exposes: Object.fromEntries(
Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
exposeKey,
- createRscExpose(exposeKey, importPath),
+ createRscExpose(importPath),
]),
) as any,
shared: sharedByScope as any,
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index 7d6b5ff31fba..02335339016a 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,11 +1,13 @@
-import { registerRemoteServerCallback } from './registerServerCallback';
-
if (typeof window !== 'undefined') {
- // Fixture-level bootstrap: make federated client actions post back through
- // host route using bridge-prefixed ids without requiring host userland wiring.
- const actionPathname = window.location.pathname || '/';
- registerRemoteServerCallback(
- `${window.location.origin}${actionPathname}`,
- 'rscRemote',
+ // Fixture-level bootstrap: keep callback wiring out of exposed modules while
+ // ensuring browser-evaluated federated code always posts bridge action IDs to host.
+ void import('./registerServerCallback').then(
+ ({ registerRemoteServerCallback }) => {
+ const actionPathname = window.location.pathname || '/';
+ registerRemoteServerCallback(
+ `${window.location.origin}${actionPathname}`,
+ 'rscRemote',
+ );
+ },
);
}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index eaa4b29b0bb5..eea31275befd 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -20,14 +20,6 @@ const HOST_RSC_URL = '/server-component-root';
const EXPECTED_ACTION_POSTS_PER_MODE = 24;
const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
-const CALLBACK_BOOTSTRAPPED_EXPOSE_KEYS = new Set([
- './RemoteClientCounter',
- './RemoteClientBadge',
- './actions',
- './nestedActions',
- './defaultAction',
- './actionBundle',
-]);
type Mode = 'dev' | 'build';
@@ -497,14 +489,15 @@ function runTests({ mode }: TestConfig) {
'[CALLBACK_BOOTSTRAP_IMPORT, importPath]',
),
).toBe(true);
+ expect(moduleFederationConfigSource).not.toContain(
+ 'callbackBootstrappedExposes',
+ );
+ expect(moduleFederationConfigSource).not.toContain(
+ 'missingCallbackExposeEntries',
+ );
expect(moduleFederationConfigSource).not.toContain(
'./src/runtime/exposes/',
);
- expect(
- [...CALLBACK_BOOTSTRAPPED_EXPOSE_KEYS].every(exposeKey =>
- moduleFederationConfigSource.includes(exposeKey),
- ),
- ).toBe(true);
});
it('should not load callback helper expose chunk', () => {
From 6953bab7dd42a85f309e4580c4a8b862018153f1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:51:09 +0000
Subject: [PATCH 135/324] refactor(rsc-mf): guard exposes to component modules
---
.../rsc-mf/remote/module-federation.config.ts | 11 +++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
2 files changed, 15 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 7874096135fd..29b3c0335d81 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -35,6 +35,17 @@ const remoteExposeImports: Record = {
'./actionBundle': './src/components/actionBundle.ts',
'./infoBundle': './src/components/infoBundle.ts',
};
+const COMPONENT_EXPOSE_PREFIX = './src/components/';
+const nonComponentExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !importPath.startsWith(COMPONENT_EXPOSE_PREFIX),
+);
+if (nonComponentExposeEntries.length > 0) {
+ throw new Error(
+ `Remote exposes must point to component userland modules (${COMPONENT_EXPOSE_PREFIX}). Invalid entries: ${nonComponentExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+}
const sharedByScope = [
{
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index eea31275befd..98012c20cfb6 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -498,6 +498,10 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).not.toContain(
'./src/runtime/exposes/',
);
+ expect(moduleFederationConfigSource).toContain('COMPONENT_EXPOSE_PREFIX');
+ expect(moduleFederationConfigSource).toContain(
+ 'nonComponentExposeEntries',
+ );
});
it('should not load callback helper expose chunk', () => {
From 347d2044224c5b2a1c6da8e859c2d0f2673419f4 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:52:26 +0000
Subject: [PATCH 136/324] test(rsc-mf): lock lazy callback bootstrap import
semantics
---
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 98012c20cfb6..1763b95d0248 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -480,6 +480,10 @@ function runTests({ mode }: TestConfig) {
),
).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
+ expect(runtimeInitSource).toContain("import('./registerServerCallback')");
+ expect(runtimeInitSource).not.toContain(
+ "from './registerServerCallback'",
+ );
expect(runtimeRegisterSource).toContain('setServerCallback');
expect(moduleFederationConfigSource).toContain(
'CALLBACK_BOOTSTRAP_IMPORT',
From 7dde578a69b1b495e5df8102367d17558de0af44 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 03:57:10 +0000
Subject: [PATCH 137/324] test(rsc-mf): validate manifest expose set is
userland subset
---
tests/integration/rsc-mf/tests/index.test.ts | 29 ++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 1763b95d0248..901b5882efc8 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -20,6 +20,21 @@ const HOST_RSC_URL = '/server-component-root';
const EXPECTED_ACTION_POSTS_PER_MODE = 24;
const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
+const EXPECTED_REMOTE_EXPOSE_PATHS = [
+ './RemoteClientCounter',
+ './RemoteClientBadge',
+ './RemoteServerCard',
+ './RemoteServerDefault',
+ './AsyncRemoteServerInfo',
+ './remoteServerOnly',
+ './remoteServerOnlyDefault',
+ './remoteMeta',
+ './actions',
+ './nestedActions',
+ './defaultAction',
+ './actionBundle',
+ './infoBundle',
+].sort();
type Mode = 'dev' | 'build';
@@ -433,10 +448,24 @@ function runTests({ mode }: TestConfig) {
const exposedPaths = (manifest.exposes || [])
.map(item => item.path)
.filter((path): path is string => Boolean(path));
+ const uniqueExposedPaths = Array.from(new Set(exposedPaths)).sort();
expect(exposedPaths).not.toContain('./registerServerCallback');
+ expect(uniqueExposedPaths.length).toBeGreaterThan(0);
+ expect(uniqueExposedPaths).toContain('./RemoteClientCounter');
+ expect(
+ uniqueExposedPaths.every(path =>
+ EXPECTED_REMOTE_EXPOSE_PATHS.includes(path),
+ ),
+ ).toBe(true);
+ expect(uniqueExposedPaths.length).toBeLessThanOrEqual(
+ EXPECTED_REMOTE_EXPOSE_PATHS.length,
+ );
expect(
exposedPaths.every(path => !path.startsWith('./src/components/')),
).toBe(true);
+ expect(
+ exposedPaths.every(path => !path.includes('initServerCallback')),
+ ).toBe(true);
});
it('should keep callback runtime wiring out of component sources', () => {
From e9f09d320d93d41a4e586f455e0c52f7127db1b7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:00:30 +0000
Subject: [PATCH 138/324] test(rsc-mf): assert config expose map matches
expected userland keys
---
tests/integration/rsc-mf/tests/index.test.ts | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 901b5882efc8..18147bda6fe3 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -35,6 +35,8 @@ const EXPECTED_REMOTE_EXPOSE_PATHS = [
'./actionBundle',
'./infoBundle',
].sort();
+const REMOTE_EXPOSE_ENTRY_PATTERN =
+ /'(\.\/[^']+)':\s*'(\.\/src\/components\/[^']+)'/g;
type Mode = 'dev' | 'build';
@@ -93,6 +95,15 @@ function createHostEnv(remotePort: number) {
};
}
+function getRemoteExposeEntries(configSource: string) {
+ return Array.from(configSource.matchAll(REMOTE_EXPOSE_ENTRY_PATTERN)).map(
+ ([, exposeKey, importPath]) => ({
+ exposeKey,
+ importPath,
+ }),
+ );
+}
+
async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const response = await fetch(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`);
const html = await response.text();
@@ -497,6 +508,12 @@ function runTests({ mode }: TestConfig) {
path.join(remoteDir, 'module-federation.config.ts'),
'utf-8',
);
+ const remoteExposeEntries = getRemoteExposeEntries(
+ moduleFederationConfigSource,
+ );
+ const remoteExposeKeys = remoteExposeEntries
+ .map(({ exposeKey }) => exposeKey)
+ .sort();
expect(
componentSources.every(
@@ -535,6 +552,12 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
);
+ expect(remoteExposeKeys).toEqual(EXPECTED_REMOTE_EXPOSE_PATHS);
+ expect(
+ remoteExposeEntries.every(({ importPath }) =>
+ importPath.startsWith('./src/components/'),
+ ),
+ ).toBe(true);
});
it('should not load callback helper expose chunk', () => {
From 36966a9c7db2615f7b2315becb711baaa676f0c5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:03:45 +0000
Subject: [PATCH 139/324] test(rsc-mf): ensure host sources stay
callback-wiring free
---
tests/integration/rsc-mf/tests/index.test.ts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 18147bda6fe3..d4e2986a66d8 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -492,10 +492,16 @@ function runTests({ mode }: TestConfig) {
const componentFilePaths = getFilesRecursively(
path.join(remoteDir, 'src/components'),
);
+ const hostSourceFilePaths = getFilesRecursively(
+ path.join(hostDir, 'src'),
+ ).filter(filePath => /\.(ts|tsx)$/.test(filePath));
const componentSources = componentFilePaths.map(filePath =>
fs.readFileSync(filePath, 'utf-8'),
);
+ const hostSourceTexts = hostSourceFilePaths.map(filePath =>
+ fs.readFileSync(filePath, 'utf-8'),
+ );
const runtimeInitSource = fs.readFileSync(
path.join(remoteDir, 'src/runtime/initServerCallback.ts'),
'utf-8',
@@ -525,6 +531,14 @@ function runTests({ mode }: TestConfig) {
source => !source.includes('registerRemoteServerCallback'),
),
).toBe(true);
+ expect(
+ hostSourceTexts.every(
+ source =>
+ !source.includes('registerRemoteServerCallback') &&
+ !source.includes('initServerCallback') &&
+ !source.includes('registerServerCallback'),
+ ),
+ ).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
expect(runtimeInitSource).not.toContain(
From f56389cf1ac3da78cec674151001387031e6dbb7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:06:33 +0000
Subject: [PATCH 140/324] test(rsc-mf): lock host runtime plugins to
transparent defaults
---
tests/integration/rsc-mf/tests/index.test.ts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index d4e2986a66d8..a9efddf8bc16 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -514,6 +514,10 @@ function runTests({ mode }: TestConfig) {
path.join(remoteDir, 'module-federation.config.ts'),
'utf-8',
);
+ const hostModuleFederationConfigSource = fs.readFileSync(
+ path.join(hostDir, 'module-federation.config.ts'),
+ 'utf-8',
+ );
const remoteExposeEntries = getRemoteExposeEntries(
moduleFederationConfigSource,
);
@@ -572,6 +576,16 @@ function runTests({ mode }: TestConfig) {
importPath.startsWith('./src/components/'),
),
).toBe(true);
+ expect(hostModuleFederationConfigSource).toContain('runtimePlugins');
+ expect(hostModuleFederationConfigSource).toContain(
+ './runtime/forceRemotePublicPath.ts',
+ );
+ expect(hostModuleFederationConfigSource).not.toContain(
+ 'registerServerCallbackRuntime',
+ );
+ expect(hostModuleFederationConfigSource).not.toContain(
+ 'initServerCallback',
+ );
});
it('should not load callback helper expose chunk', () => {
From b4da5b5a24880f183d5e8819c0627bc3140c5ae3 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:09:21 +0000
Subject: [PATCH 141/324] refactor(rsc-mf): memoize callback bootstrap
initialization
---
.../remote/src/runtime/initServerCallback.ts | 30 +++++++++++++------
tests/integration/rsc-mf/tests/index.test.ts | 2 ++
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index 02335339016a..0cd3b583006d 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,13 +1,25 @@
+let callbackBootstrapPromise: Promise | undefined;
+
+const bootstrapServerCallback = () => {
+ if (!callbackBootstrapPromise) {
+ callbackBootstrapPromise = import('./registerServerCallback').then(
+ ({ registerRemoteServerCallback }) => {
+ const actionPathname = window.location.pathname || '/';
+ registerRemoteServerCallback(
+ `${window.location.origin}${actionPathname}`,
+ 'rscRemote',
+ );
+ },
+ );
+ }
+
+ return callbackBootstrapPromise;
+};
+
if (typeof window !== 'undefined') {
// Fixture-level bootstrap: keep callback wiring out of exposed modules while
// ensuring browser-evaluated federated code always posts bridge action IDs to host.
- void import('./registerServerCallback').then(
- ({ registerRemoteServerCallback }) => {
- const actionPathname = window.location.pathname || '/';
- registerRemoteServerCallback(
- `${window.location.origin}${actionPathname}`,
- 'rscRemote',
- );
- },
- );
+ // Promise memoization avoids duplicate bootstrap work when multiple exposes
+ // import this runtime helper in the same browser session.
+ void bootstrapServerCallback();
}
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index a9efddf8bc16..21bb676eff1e 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -544,6 +544,8 @@ function runTests({ mode }: TestConfig) {
),
).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
+ expect(runtimeInitSource).toContain('bootstrapServerCallback');
+ expect(runtimeInitSource).toContain('callbackBootstrapPromise');
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
expect(runtimeInitSource).not.toContain(
"from './registerServerCallback'",
From 88fdf162e6833dd6fddbe662a11cb21055520856 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:12:16 +0000
Subject: [PATCH 142/324] refactor(rsc-mf): reset callback bootstrap promise
after failures
---
.../rsc-mf/remote/src/runtime/initServerCallback.ts | 3 +++
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index 0cd3b583006d..d8b383dc7695 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -11,6 +11,9 @@ const bootstrapServerCallback = () => {
);
},
);
+ callbackBootstrapPromise.catch(() => {
+ callbackBootstrapPromise = undefined;
+ });
}
return callbackBootstrapPromise;
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 21bb676eff1e..6fa4c2486be2 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -547,6 +547,10 @@ function runTests({ mode }: TestConfig) {
expect(runtimeInitSource).toContain('bootstrapServerCallback');
expect(runtimeInitSource).toContain('callbackBootstrapPromise');
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
+ expect(runtimeInitSource).toContain('callbackBootstrapPromise.catch');
+ expect(runtimeInitSource).toContain(
+ 'callbackBootstrapPromise = undefined',
+ );
expect(runtimeInitSource).not.toContain(
"from './registerServerCallback'",
);
From 088d64338696e4e5a7f3e6675fed6ddf4b0313fb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:14:56 +0000
Subject: [PATCH 143/324] test(rsc-mf): guard modern config callback wiring
boundaries
---
tests/integration/rsc-mf/tests/index.test.ts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6fa4c2486be2..6562ca0def24 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -518,6 +518,14 @@ function runTests({ mode }: TestConfig) {
path.join(hostDir, 'module-federation.config.ts'),
'utf-8',
);
+ const hostModernConfigSource = fs.readFileSync(
+ path.join(hostDir, 'modern.config.ts'),
+ 'utf-8',
+ );
+ const remoteModernConfigSource = fs.readFileSync(
+ path.join(remoteDir, 'modern.config.ts'),
+ 'utf-8',
+ );
const remoteExposeEntries = getRemoteExposeEntries(
moduleFederationConfigSource,
);
@@ -592,6 +600,12 @@ function runTests({ mode }: TestConfig) {
expect(hostModuleFederationConfigSource).not.toContain(
'initServerCallback',
);
+ expect(hostModernConfigSource).not.toContain('preEntry');
+ expect(hostModernConfigSource).not.toContain('registerServerCallback');
+ expect(remoteModernConfigSource).not.toContain('chunkLoadingGlobal');
+ expect(remoteModernConfigSource).toContain(
+ 'rsc-mf-react-server-dom-client-browser$',
+ );
});
it('should not load callback helper expose chunk', () => {
From 66097a4db68234227975701c5fa7634fdd5ef923 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:17:34 +0000
Subject: [PATCH 144/324] test(rsc-mf): assert modern config keeps transparent
runtime boundaries
---
tests/integration/rsc-mf/tests/index.test.ts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6562ca0def24..90da99dc3848 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -594,6 +594,12 @@ function runTests({ mode }: TestConfig) {
expect(hostModuleFederationConfigSource).toContain(
'./runtime/forceRemotePublicPath.ts',
);
+ expect(hostModuleFederationConfigSource).toContain(
+ '/static/mf-manifest.json',
+ );
+ expect(hostModuleFederationConfigSource).toContain('rscRemote:');
+ expect(hostModuleFederationConfigSource).toContain('asyncStartup: true');
+ expect(hostModuleFederationConfigSource).toContain('rsc: true');
expect(hostModuleFederationConfigSource).not.toContain(
'registerServerCallbackRuntime',
);
From 6a9e740ade7ce28003be39a60f3ec8818817d788 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:20:36 +0000
Subject: [PATCH 145/324] test(rsc-mf): enforce remote shared-scope and
experiment config invariants
---
tests/integration/rsc-mf/tests/index.test.ts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 90da99dc3848..6e11220c6a9a 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -532,6 +532,11 @@ function runTests({ mode }: TestConfig) {
const remoteExposeKeys = remoteExposeEntries
.map(({ exposeKey }) => exposeKey)
.sort();
+ const clientBrowserSharedScopeEntryCount = (
+ moduleFederationConfigSource.match(
+ /'react-server-dom-rspack\/client\.browser':\s*\{/g,
+ ) || []
+ ).length;
expect(
componentSources.every(
@@ -584,6 +589,13 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
);
+ expect(moduleFederationConfigSource).toContain("shareScope: 'default'");
+ expect(moduleFederationConfigSource).toContain("shareScope: 'ssr'");
+ expect(moduleFederationConfigSource).toContain("shareScope: 'rsc'");
+ expect(moduleFederationConfigSource).toContain('experiments:');
+ expect(moduleFederationConfigSource).toContain('asyncStartup: true');
+ expect(moduleFederationConfigSource).toContain('rsc: true');
+ expect(clientBrowserSharedScopeEntryCount).toBe(3);
expect(remoteExposeKeys).toEqual(EXPECTED_REMOTE_EXPOSE_PATHS);
expect(
remoteExposeEntries.every(({ importPath }) =>
From 8baab1f3a255f3de43af1e9ef489d589dd45dcb8 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:23:44 +0000
Subject: [PATCH 146/324] refactor(rsc-mf): validate expose keys and protect
bootstrap module from exposure
---
.../rsc-mf/remote/module-federation.config.ts | 18 ++++++++++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 2 ++
2 files changed, 20 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 29b3c0335d81..d35b9318ba82 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -35,6 +35,14 @@ const remoteExposeImports: Record = {
'./actionBundle': './src/components/actionBundle.ts',
'./infoBundle': './src/components/infoBundle.ts',
};
+const invalidExposeKeys = Object.keys(remoteExposeImports).filter(
+ exposeKey => !exposeKey.startsWith('./'),
+);
+if (invalidExposeKeys.length > 0) {
+ throw new Error(
+ `Remote expose keys must be module-federation paths starting with "./". Invalid keys: ${invalidExposeKeys.join(', ')}`,
+ );
+}
const COMPONENT_EXPOSE_PREFIX = './src/components/';
const nonComponentExposeEntries = Object.entries(remoteExposeImports).filter(
([, importPath]) => !importPath.startsWith(COMPONENT_EXPOSE_PREFIX),
@@ -46,6 +54,16 @@ if (nonComponentExposeEntries.length > 0) {
.join(', ')}`,
);
}
+const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
+);
+if (callbackExposeEntries.length > 0) {
+ throw new Error(
+ `Callback bootstrap module (${CALLBACK_BOOTSTRAP_IMPORT}) must remain internal-only and cannot be exposed. Invalid entries: ${callbackExposeEntries
+ .map(([exposeKey]) => exposeKey)
+ .join(', ')}`,
+ );
+}
const sharedByScope = [
{
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6e11220c6a9a..62eec23da6fe 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -589,6 +589,8 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
);
+ expect(moduleFederationConfigSource).toContain('invalidExposeKeys');
+ expect(moduleFederationConfigSource).toContain('callbackExposeEntries');
expect(moduleFederationConfigSource).toContain("shareScope: 'default'");
expect(moduleFederationConfigSource).toContain("shareScope: 'ssr'");
expect(moduleFederationConfigSource).toContain("shareScope: 'rsc'");
From 8435ed645898ecf470be99321ce8cc0bb6155369 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:26:43 +0000
Subject: [PATCH 147/324] test(rsc-mf): assert callback posting contract in
runtime register source
---
tests/integration/rsc-mf/tests/index.test.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 62eec23da6fe..424117974597 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -568,6 +568,19 @@ function runTests({ mode }: TestConfig) {
"from './registerServerCallback'",
);
expect(runtimeRegisterSource).toContain('setServerCallback');
+ expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
+ expect(runtimeRegisterSource).toContain(
+ "if (rawActionId.startsWith('remote:'))",
+ );
+ expect(runtimeRegisterSource).toContain(
+ 'return `remote:${remoteAlias}:${rawActionId}`',
+ );
+ expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
+ expect(runtimeRegisterSource).toContain("method: 'POST'");
+ expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
+ expect(runtimeRegisterSource).not.toContain(
+ 'remoteActionIdToHostProxyActionId',
+ );
expect(moduleFederationConfigSource).toContain(
'CALLBACK_BOOTSTRAP_IMPORT',
);
From b28577bbdf49a98ff6eb96d38b364c7e5d094b4b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:29:33 +0000
Subject: [PATCH 148/324] test(rsc-mf): lock runtime callback transport header
semantics
---
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 424117974597..6e9d426f2928 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -560,10 +560,14 @@ function runTests({ mode }: TestConfig) {
expect(runtimeInitSource).toContain('bootstrapServerCallback');
expect(runtimeInitSource).toContain('callbackBootstrapPromise');
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
+ expect(runtimeInitSource).toContain('window.location.origin');
+ expect(runtimeInitSource).toContain('window.location.pathname');
expect(runtimeInitSource).toContain('callbackBootstrapPromise.catch');
expect(runtimeInitSource).toContain(
'callbackBootstrapPromise = undefined',
);
+ expect(runtimeInitSource).not.toContain('RSC_MF_REMOTE_PORT');
+ expect(runtimeInitSource).not.toContain('127.0.0.1:');
expect(runtimeInitSource).not.toContain(
"from './registerServerCallback'",
);
From 82936feb94f948722f8c95fc628df5bf1bfd56d1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:32:51 +0000
Subject: [PATCH 149/324] test(rsc-mf): assert callback bootstrap derives host
origin dynamically
---
tests/integration/rsc-mf/tests/index.test.ts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6e9d426f2928..36999c94a7f5 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -367,6 +367,7 @@ function runTests({ mode }: TestConfig) {
const runtimeErrors: string[] = [];
const actionRequestUrls: string[] = [];
const actionRequestIds: string[] = [];
+ const actionRequestAcceptHeaders: string[] = [];
const registerCallbackExposeRequestUrls: string[] = [];
if (skipForLowerNodeVersion()) {
@@ -430,6 +431,7 @@ function runTests({ mode }: TestConfig) {
}
actionRequestUrls.push(url);
actionRequestIds.push(headers['x-rsc-action']);
+ actionRequestAcceptHeaders.push(headers.accept || '');
});
});
@@ -659,6 +661,7 @@ function runTests({ mode }: TestConfig) {
it('should route remote actions through host endpoint', () => {
expect(actionRequestUrls.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestUrls.length).toBe(actionRequestIds.length);
+ expect(actionRequestUrls.length).toBe(actionRequestAcceptHeaders.length);
const uniqueActionRequestUrls = Array.from(new Set(actionRequestUrls));
expect(uniqueActionRequestUrls).toEqual([
`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`,
@@ -678,12 +681,18 @@ function runTests({ mode }: TestConfig) {
it('should post bridge-prefixed action ids for remote actions', async () => {
expect(actionRequestIds.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestIds.length).toBe(actionRequestUrls.length);
+ expect(actionRequestIds.length).toBe(actionRequestAcceptHeaders.length);
const uniqueActionRequestIds = new Set(actionRequestIds);
expect(
actionRequestIds.every(id =>
/^remote:rscRemote:[a-f0-9]{64,}$/i.test(id),
),
).toBe(true);
+ expect(
+ actionRequestAcceptHeaders.every(
+ acceptHeader => acceptHeader.toLowerCase() === 'text/x-component',
+ ),
+ ).toBe(true);
expect(uniqueActionRequestIds.size).toBe(
EXPECTED_UNIQUE_ACTION_IDS_PER_MODE,
);
From 010fc9b4eb5130a5cb5813d389d42faa826afb0e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:35:56 +0000
Subject: [PATCH 150/324] refactor(rsc-mf): normalize callback action URL and
assert request Accept headers
---
.../remote/src/runtime/registerServerCallback.ts | 10 ++++++++--
tests/integration/rsc-mf/tests/index.test.ts | 4 ++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index 8230bc186531..bd6987c65da7 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -14,6 +14,12 @@ const getHostActionId = (rawActionId: string, remoteAlias: string) => {
// Align with RSC bridge action-id format expected by host runtime plugin.
return `remote:${remoteAlias}:${rawActionId}`;
};
+const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
+ const url = new URL(remoteOrigin);
+ url.search = '';
+ url.hash = '';
+ return url.toString();
+};
export function registerRemoteServerCallback(
remoteOrigin: string,
@@ -22,15 +28,15 @@ export function registerRemoteServerCallback(
if (!remoteOrigin) {
return;
}
+ const remoteActionUrl = getNormalizedRemoteActionUrl(remoteOrigin);
const callbackKey = JSON.stringify({
remoteAlias,
- remoteOrigin,
+ remoteActionUrl,
});
if (registeredCallbackKey === callbackKey) {
return;
}
- const remoteActionUrl = new URL(remoteOrigin).toString();
setServerCallback(async (id, args) => {
const hostActionId = getHostActionId(id, remoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 36999c94a7f5..11020f55865d 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -584,6 +584,10 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
expect(runtimeRegisterSource).toContain("method: 'POST'");
expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
+ expect(runtimeRegisterSource).toContain('getNormalizedRemoteActionUrl');
+ expect(runtimeRegisterSource).toContain("url.search = ''");
+ expect(runtimeRegisterSource).toContain("url.hash = ''");
+ expect(runtimeRegisterSource).toContain('remoteActionUrl,');
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
From 91e183eb19c1022c05f7db29ee491525b57de4c7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:38:55 +0000
Subject: [PATCH 151/324] test(rsc-mf): verify action requests preserve RSC
accept header
---
tests/integration/rsc-mf/tests/index.test.ts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 11020f55865d..19e9146d7143 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -645,10 +645,22 @@ function runTests({ mode }: TestConfig) {
);
expect(hostModernConfigSource).not.toContain('preEntry');
expect(hostModernConfigSource).not.toContain('registerServerCallback');
+ expect(hostModernConfigSource).toContain('enableAsyncEntry: false');
+ expect(hostModernConfigSource).toContain("chain.target('async-node')");
+ expect(hostModernConfigSource).toContain("'server-only$'");
+ expect(hostModernConfigSource).toContain(
+ 'moduleFederationPlugin({ ssr: true })',
+ );
expect(remoteModernConfigSource).not.toContain('chunkLoadingGlobal');
expect(remoteModernConfigSource).toContain(
'rsc-mf-react-server-dom-client-browser$',
);
+ expect(remoteModernConfigSource).toContain('enableAsyncEntry: false');
+ expect(remoteModernConfigSource).toContain("chain.target('async-node')");
+ expect(remoteModernConfigSource).toContain('splitChunks(false)');
+ expect(remoteModernConfigSource).toContain(
+ 'moduleFederationPlugin({ ssr: true })',
+ );
});
it('should not load callback helper expose chunk', () => {
From 2dbf23670102fa4311085852ebf404bdfe25a50a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:51:15 +0000
Subject: [PATCH 152/324] test(rsc-mf): verify expose import files exist via
source scan
---
tests/integration/rsc-mf/tests/index.test.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 19e9146d7143..8ce8e8e0c0ed 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -627,6 +627,11 @@ function runTests({ mode }: TestConfig) {
importPath.startsWith('./src/components/'),
),
).toBe(true);
+ expect(
+ remoteExposeEntries.every(({ importPath }) =>
+ fs.existsSync(path.resolve(remoteDir, importPath)),
+ ),
+ ).toBe(true);
expect(hostModuleFederationConfigSource).toContain('runtimePlugins');
expect(hostModuleFederationConfigSource).toContain(
'./runtime/forceRemotePublicPath.ts',
From d18d90bf9eb6d63328c749a87954b4519a3e2eea Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:56:36 +0000
Subject: [PATCH 153/324] refactor(rsc-mf): require explicit TypeScript expose
entry extensions
---
.../rsc-mf/remote/module-federation.config.ts | 10 ++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 8 ++++++++
2 files changed, 18 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index d35b9318ba82..c8cda0850c4b 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -54,6 +54,16 @@ if (nonComponentExposeEntries.length > 0) {
.join(', ')}`,
);
}
+const nonTypeScriptExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !/\.[tj]sx?$/.test(importPath),
+);
+if (nonTypeScriptExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution. Invalid entries: ${nonTypeScriptExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+}
const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
);
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 8ce8e8e0c0ed..6d6e9d5f9487 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -612,6 +612,9 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
);
+ expect(moduleFederationConfigSource).toContain(
+ 'nonTypeScriptExposeEntries',
+ );
expect(moduleFederationConfigSource).toContain('invalidExposeKeys');
expect(moduleFederationConfigSource).toContain('callbackExposeEntries');
expect(moduleFederationConfigSource).toContain("shareScope: 'default'");
@@ -627,6 +630,11 @@ function runTests({ mode }: TestConfig) {
importPath.startsWith('./src/components/'),
),
).toBe(true);
+ expect(
+ remoteExposeEntries.every(({ importPath }) =>
+ /\.[tj]sx?$/.test(importPath),
+ ),
+ ).toBe(true);
expect(
remoteExposeEntries.every(({ importPath }) =>
fs.existsSync(path.resolve(remoteDir, importPath)),
From fbd36bdfb45426dfe7398693e67bef8b55e8c7ad Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 04:59:07 +0000
Subject: [PATCH 154/324] test(rsc-mf): assert runtime exposes wrapper
directory stays empty
---
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 6d6e9d5f9487..00f547bd1b63 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -528,6 +528,15 @@ function runTests({ mode }: TestConfig) {
path.join(remoteDir, 'modern.config.ts'),
'utf-8',
);
+ const remoteRuntimeExposesDir = path.join(
+ remoteDir,
+ 'src/runtime/exposes',
+ );
+ const remoteRuntimeExposeEntries = fs.existsSync(remoteRuntimeExposesDir)
+ ? fs
+ .readdirSync(remoteRuntimeExposesDir)
+ .filter(entryName => !entryName.startsWith('.'))
+ : [];
const remoteExposeEntries = getRemoteExposeEntries(
moduleFederationConfigSource,
);
@@ -608,6 +617,7 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).not.toContain(
'./src/runtime/exposes/',
);
+ expect(remoteRuntimeExposeEntries).toEqual([]);
expect(moduleFederationConfigSource).toContain('COMPONENT_EXPOSE_PREFIX');
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
From b0e1593e36a6f50c6616308223ce94b8ecf47d9f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:02:42 +0000
Subject: [PATCH 155/324] test(rsc-mf): lock runtime callback helper file
surface
---
tests/integration/rsc-mf/tests/index.test.ts | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 00f547bd1b63..0239671cbf5c 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -537,6 +537,13 @@ function runTests({ mode }: TestConfig) {
.readdirSync(remoteRuntimeExposesDir)
.filter(entryName => !entryName.startsWith('.'))
: [];
+ const remoteRuntimeEntries = fs
+ .readdirSync(path.join(remoteDir, 'src/runtime'))
+ .filter(entryName => !entryName.startsWith('.'))
+ .sort();
+ const remoteRuntimeEntriesWithoutExposeDir = remoteRuntimeEntries.filter(
+ entryName => entryName !== 'exposes',
+ );
const remoteExposeEntries = getRemoteExposeEntries(
moduleFederationConfigSource,
);
@@ -618,6 +625,10 @@ function runTests({ mode }: TestConfig) {
'./src/runtime/exposes/',
);
expect(remoteRuntimeExposeEntries).toEqual([]);
+ expect(remoteRuntimeEntriesWithoutExposeDir).toEqual([
+ 'initServerCallback.ts',
+ 'registerServerCallback.ts',
+ ]);
expect(moduleFederationConfigSource).toContain('COMPONENT_EXPOSE_PREFIX');
expect(moduleFederationConfigSource).toContain(
'nonComponentExposeEntries',
From 114deee32206c731ee5626ec9eae46c4116ca889 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:06:08 +0000
Subject: [PATCH 156/324] test(rsc-mf): lock callback alias usage to runtime
helpers
---
tests/integration/rsc-mf/tests/index.test.ts | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 0239671cbf5c..f7684b1de452 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -566,6 +566,13 @@ function runTests({ mode }: TestConfig) {
source => !source.includes('registerRemoteServerCallback'),
),
).toBe(true);
+ expect(
+ componentSources.every(
+ source =>
+ !source.includes('setServerCallback') &&
+ !source.includes('rsc-mf-react-server-dom-client-browser'),
+ ),
+ ).toBe(true);
expect(
hostSourceTexts.every(
source =>
@@ -590,6 +597,12 @@ function runTests({ mode }: TestConfig) {
"from './registerServerCallback'",
);
expect(runtimeRegisterSource).toContain('setServerCallback');
+ expect(runtimeRegisterSource).toContain(
+ "from 'rsc-mf-react-server-dom-client-browser'",
+ );
+ expect(runtimeRegisterSource).not.toContain(
+ "from 'react-server-dom-rspack/client.browser'",
+ );
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
expect(runtimeRegisterSource).toContain(
"if (rawActionId.startsWith('remote:'))",
@@ -689,6 +702,9 @@ function runTests({ mode }: TestConfig) {
expect(remoteModernConfigSource).toContain(
'rsc-mf-react-server-dom-client-browser$',
);
+ expect(remoteModernConfigSource).toContain(
+ 'react-server-dom-rspack/client.browser',
+ );
expect(remoteModernConfigSource).toContain('enableAsyncEntry: false');
expect(remoteModernConfigSource).toContain("chain.target('async-node')");
expect(remoteModernConfigSource).toContain('splitChunks(false)');
From f071c8d0071464fb95c6aa5e61cba33ec55297a1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:08:48 +0000
Subject: [PATCH 157/324] test(rsc-mf): lock runtime callback initialization
contract
---
tests/integration/rsc-mf/tests/index.test.ts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index f7684b1de452..2480a92f1f39 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -584,25 +584,36 @@ function runTests({ mode }: TestConfig) {
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
expect(runtimeInitSource).toContain('bootstrapServerCallback');
expect(runtimeInitSource).toContain('callbackBootstrapPromise');
+ expect(runtimeInitSource).toContain("if (typeof window !== 'undefined')");
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
+ expect(runtimeInitSource).toContain('void bootstrapServerCallback()');
expect(runtimeInitSource).toContain('window.location.origin');
expect(runtimeInitSource).toContain('window.location.pathname');
expect(runtimeInitSource).toContain('callbackBootstrapPromise.catch');
expect(runtimeInitSource).toContain(
'callbackBootstrapPromise = undefined',
);
+ expect(runtimeInitSource).not.toContain('setServerCallback(');
expect(runtimeInitSource).not.toContain('RSC_MF_REMOTE_PORT');
expect(runtimeInitSource).not.toContain('127.0.0.1:');
expect(runtimeInitSource).not.toContain(
"from './registerServerCallback'",
);
expect(runtimeRegisterSource).toContain('setServerCallback');
+ expect(runtimeRegisterSource).toContain('createTemporaryReferenceSet');
+ expect(runtimeRegisterSource).toContain(
+ 'encodeReply(args, { temporaryReferences })',
+ );
+ expect(runtimeRegisterSource).toContain(
+ 'createFromFetch(response, { temporaryReferences })',
+ );
expect(runtimeRegisterSource).toContain(
"from 'rsc-mf-react-server-dom-client-browser'",
);
expect(runtimeRegisterSource).not.toContain(
"from 'react-server-dom-rspack/client.browser'",
);
+ expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
expect(runtimeRegisterSource).toContain(
"if (rawActionId.startsWith('remote:'))",
@@ -681,6 +692,7 @@ function runTests({ mode }: TestConfig) {
expect(hostModuleFederationConfigSource).toContain(
'/static/mf-manifest.json',
);
+ expect(hostModuleFederationConfigSource).toContain('RSC_MF_REMOTE_PORT');
expect(hostModuleFederationConfigSource).toContain('rscRemote:');
expect(hostModuleFederationConfigSource).toContain('asyncStartup: true');
expect(hostModuleFederationConfigSource).toContain('rsc: true');
From 1dba1cfd80a8c5f7c6ac896e9e5e6aea4007e200 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:11:28 +0000
Subject: [PATCH 158/324] test(rsc-mf): prevent host callback runtime leakage
---
tests/integration/rsc-mf/tests/index.test.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 2480a92f1f39..5c7b8af1d66b 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -578,7 +578,9 @@ function runTests({ mode }: TestConfig) {
source =>
!source.includes('registerRemoteServerCallback') &&
!source.includes('initServerCallback') &&
- !source.includes('registerServerCallback'),
+ !source.includes('registerServerCallback') &&
+ !source.includes('setServerCallback') &&
+ !source.includes('rsc-mf-react-server-dom-client-browser'),
),
).toBe(true);
expect(runtimeInitSource).toContain('registerRemoteServerCallback');
@@ -613,6 +615,7 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain(
"from 'react-server-dom-rspack/client.browser'",
);
+ expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
expect(runtimeRegisterSource).toContain(
@@ -689,6 +692,10 @@ function runTests({ mode }: TestConfig) {
expect(hostModuleFederationConfigSource).toContain(
'./runtime/forceRemotePublicPath.ts',
);
+ expect(hostModuleFederationConfigSource).toContain(
+ "process.env.NODE_ENV === 'production'",
+ );
+ expect(hostModuleFederationConfigSource).toContain(': []');
expect(hostModuleFederationConfigSource).toContain(
'/static/mf-manifest.json',
);
From 99b81e18d0e85c9d04974427c745e0a90a2125eb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:13:08 +0000
Subject: [PATCH 159/324] refactor(rsc-mf): guard expose imports against
traversal paths
---
.../rsc-mf/remote/module-federation.config.ts | 20 +++++++++++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++++
2 files changed, 30 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index c8cda0850c4b..b6f1d60d3631 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -64,6 +64,26 @@ if (nonTypeScriptExposeEntries.length > 0) {
.join(', ')}`,
);
}
+const parentTraversalExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => importPath.includes('..'),
+);
+if (parentTraversalExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must not contain parent directory traversal segments. Invalid entries: ${parentTraversalExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+}
+const nonPosixExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => importPath.includes('\\'),
+);
+if (nonPosixExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must use POSIX separators for deterministic module ids. Invalid entries: ${nonPosixExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+}
const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
);
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 5c7b8af1d66b..d720d01a3fb5 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -663,6 +663,10 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'nonTypeScriptExposeEntries',
);
+ expect(moduleFederationConfigSource).toContain(
+ 'parentTraversalExposeEntries',
+ );
+ expect(moduleFederationConfigSource).toContain('nonPosixExposeEntries');
expect(moduleFederationConfigSource).toContain('invalidExposeKeys');
expect(moduleFederationConfigSource).toContain('callbackExposeEntries');
expect(moduleFederationConfigSource).toContain("shareScope: 'default'");
@@ -683,6 +687,12 @@ function runTests({ mode }: TestConfig) {
/\.[tj]sx?$/.test(importPath),
),
).toBe(true);
+ expect(
+ remoteExposeEntries.every(
+ ({ importPath }) =>
+ !importPath.includes('..') && !importPath.includes('\\'),
+ ),
+ ).toBe(true);
expect(
remoteExposeEntries.every(({ importPath }) =>
fs.existsSync(path.resolve(remoteDir, importPath)),
From f8e30d16f4ebdd2c26ed047b4b345a240600b726 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:16:09 +0000
Subject: [PATCH 160/324] refactor(rsc-mf): validate callback bootstrap import
boundaries
---
.../rsc-mf/remote/module-federation.config.ts | 19 +++++++++++++++++++
tests/integration/rsc-mf/tests/index.test.ts | 12 ++++++++++++
2 files changed, 31 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index b6f1d60d3631..c28fbb37f8a8 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -15,6 +15,25 @@ const reactDomServerImport = path.join(
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
+const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
+if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
+ throw new Error(
+ `Callback bootstrap import must stay in runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
+if (!/\.[tj]sx?$/.test(CALLBACK_BOOTSTRAP_IMPORT)) {
+ throw new Error(
+ `Callback bootstrap import must use explicit source extension for deterministic resolution. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
+if (
+ CALLBACK_BOOTSTRAP_IMPORT.includes('..') ||
+ CALLBACK_BOOTSTRAP_IMPORT.includes('\\')
+) {
+ throw new Error(
+ `Callback bootstrap import must not contain traversal or Windows separators. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
const createRscExpose = (importPath: string) =>
({
import: [CALLBACK_BOOTSTRAP_IMPORT, importPath],
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index d720d01a3fb5..53ae830f477c 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -637,6 +637,18 @@ function runTests({ mode }: TestConfig) {
expect(moduleFederationConfigSource).toContain(
'CALLBACK_BOOTSTRAP_IMPORT',
);
+ expect(moduleFederationConfigSource).toContain(
+ 'CALLBACK_BOOTSTRAP_PREFIX',
+ );
+ expect(moduleFederationConfigSource).toContain(
+ 'Callback bootstrap import must stay in runtime namespace',
+ );
+ expect(moduleFederationConfigSource).toContain(
+ 'Callback bootstrap import must use explicit source extension',
+ );
+ expect(moduleFederationConfigSource).toContain(
+ 'Callback bootstrap import must not contain traversal or Windows separators',
+ );
expect(
moduleFederationConfigSource.includes(
'[CALLBACK_BOOTSTRAP_IMPORT, importPath]',
From 5762be3c7eafacc75dcabd03457ea617be98601f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:19:14 +0000
Subject: [PATCH 161/324] refactor(rsc-mf): validate remote alias before bridge
action prefixing
---
.../src/runtime/registerServerCallback.ts | 10 ++++++++--
tests/integration/rsc-mf/tests/index.test.ts | 18 ++++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index bd6987c65da7..dce97b6378c5 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -28,9 +28,15 @@ export function registerRemoteServerCallback(
if (!remoteOrigin) {
return;
}
+ const normalizedRemoteAlias = remoteAlias.trim();
+ if (!normalizedRemoteAlias || normalizedRemoteAlias.includes(':')) {
+ throw new Error(
+ `Remote alias must be a non-empty identifier without ":" delimiters. Received: ${remoteAlias}`,
+ );
+ }
const remoteActionUrl = getNormalizedRemoteActionUrl(remoteOrigin);
const callbackKey = JSON.stringify({
- remoteAlias,
+ remoteAlias: normalizedRemoteAlias,
remoteActionUrl,
});
if (registeredCallbackKey === callbackKey) {
@@ -38,7 +44,7 @@ export function registerRemoteServerCallback(
}
setServerCallback(async (id, args) => {
- const hostActionId = getHostActionId(id, remoteAlias);
+ const hostActionId = getHostActionId(id, normalizedRemoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
const response = fetch(remoteActionUrl, {
method: 'POST',
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 53ae830f477c..e11e7bf1ad8d 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -618,6 +618,15 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
+ expect(runtimeRegisterSource).toContain(
+ 'const normalizedRemoteAlias = remoteAlias.trim()',
+ );
+ expect(runtimeRegisterSource).toContain(
+ "!normalizedRemoteAlias || normalizedRemoteAlias.includes(':')",
+ );
+ expect(runtimeRegisterSource).toContain(
+ 'Remote alias must be a non-empty identifier without ":" delimiters',
+ );
expect(runtimeRegisterSource).toContain(
"if (rawActionId.startsWith('remote:'))",
);
@@ -630,7 +639,16 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain('getNormalizedRemoteActionUrl');
expect(runtimeRegisterSource).toContain("url.search = ''");
expect(runtimeRegisterSource).toContain("url.hash = ''");
+ expect(runtimeRegisterSource).toContain(
+ 'remoteAlias: normalizedRemoteAlias',
+ );
+ expect(runtimeRegisterSource).toContain(
+ 'getHostActionId(id, normalizedRemoteAlias)',
+ );
expect(runtimeRegisterSource).toContain('remoteActionUrl,');
+ expect(runtimeRegisterSource).not.toContain(
+ 'getHostActionId(id, remoteAlias)',
+ );
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
From 71afe3b5ad815f90ac6568dd6d0566782d20ecfa Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:22:41 +0000
Subject: [PATCH 162/324] refactor(rsc-mf): enforce http(s) callback action
URLs
---
.../rsc-mf/remote/src/runtime/registerServerCallback.ts | 5 +++++
tests/integration/rsc-mf/tests/index.test.ts | 6 ++++++
2 files changed, 11 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index dce97b6378c5..dd711123b21c 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -16,6 +16,11 @@ const getHostActionId = (rawActionId: string, remoteAlias: string) => {
};
const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
const url = new URL(remoteOrigin);
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
+ throw new Error(
+ `Remote action callback URL must use http or https. Received protocol: ${url.protocol}`,
+ );
+ }
url.search = '';
url.hash = '';
return url.toString();
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index e11e7bf1ad8d..7cd717c6f651 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -637,6 +637,12 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain("method: 'POST'");
expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
expect(runtimeRegisterSource).toContain('getNormalizedRemoteActionUrl');
+ expect(runtimeRegisterSource).toContain(
+ "url.protocol !== 'http:' && url.protocol !== 'https:'",
+ );
+ expect(runtimeRegisterSource).toContain(
+ 'Remote action callback URL must use http or https',
+ );
expect(runtimeRegisterSource).toContain("url.search = ''");
expect(runtimeRegisterSource).toContain("url.hash = ''");
expect(runtimeRegisterSource).toContain(
From d72f82c2f6b4b6ea7895b2165ce51eab756851ed Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:25:38 +0000
Subject: [PATCH 163/324] refactor(rsc-mf): reject callback URLs with embedded
credentials
---
.../remote/src/runtime/registerServerCallback.ts | 10 ++++++++--
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index dd711123b21c..de999e890b1e 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -21,6 +21,11 @@ const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
`Remote action callback URL must use http or https. Received protocol: ${url.protocol}`,
);
}
+ if (url.username || url.password) {
+ throw new Error(
+ 'Remote action callback URL must not include embedded credentials.',
+ );
+ }
url.search = '';
url.hash = '';
return url.toString();
@@ -30,7 +35,8 @@ export function registerRemoteServerCallback(
remoteOrigin: string,
remoteAlias = 'rscRemote',
) {
- if (!remoteOrigin) {
+ const normalizedRemoteOrigin = remoteOrigin.trim();
+ if (!normalizedRemoteOrigin) {
return;
}
const normalizedRemoteAlias = remoteAlias.trim();
@@ -39,7 +45,7 @@ export function registerRemoteServerCallback(
`Remote alias must be a non-empty identifier without ":" delimiters. Received: ${remoteAlias}`,
);
}
- const remoteActionUrl = getNormalizedRemoteActionUrl(remoteOrigin);
+ const remoteActionUrl = getNormalizedRemoteActionUrl(normalizedRemoteOrigin);
const callbackKey = JSON.stringify({
remoteAlias: normalizedRemoteAlias,
remoteActionUrl,
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 7cd717c6f651..f6673091f239 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -643,6 +643,9 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain(
'Remote action callback URL must use http or https',
);
+ expect(runtimeRegisterSource).toContain(
+ 'Remote action callback URL must not include embedded credentials.',
+ );
expect(runtimeRegisterSource).toContain("url.search = ''");
expect(runtimeRegisterSource).toContain("url.hash = ''");
expect(runtimeRegisterSource).toContain(
@@ -651,10 +654,17 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain(
'getHostActionId(id, normalizedRemoteAlias)',
);
+ expect(runtimeRegisterSource).toContain(
+ 'const normalizedRemoteOrigin = remoteOrigin.trim()',
+ );
+ expect(runtimeRegisterSource).toContain('if (!normalizedRemoteOrigin)');
expect(runtimeRegisterSource).toContain('remoteActionUrl,');
expect(runtimeRegisterSource).not.toContain(
'getHostActionId(id, remoteAlias)',
);
+ expect(runtimeRegisterSource).not.toContain(
+ 'getNormalizedRemoteActionUrl(remoteOrigin)',
+ );
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
From aa01c52e563102bd0d490d0c051bb6745a525272 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:29:28 +0000
Subject: [PATCH 164/324] refactor(rsc-mf): trim callback origin and block URL
credentials
---
.../remote/src/runtime/registerServerCallback.ts | 9 +++++++--
tests/integration/rsc-mf/tests/index.test.ts | 10 ++++++++--
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index de999e890b1e..d93084b38bf6 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -6,6 +6,7 @@ import {
} from 'rsc-mf-react-server-dom-client-browser';
let registeredCallbackKey = '';
+const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
const getHostActionId = (rawActionId: string, remoteAlias: string) => {
if (rawActionId.startsWith('remote:')) {
return rawActionId;
@@ -40,9 +41,13 @@ export function registerRemoteServerCallback(
return;
}
const normalizedRemoteAlias = remoteAlias.trim();
- if (!normalizedRemoteAlias || normalizedRemoteAlias.includes(':')) {
+ if (
+ !normalizedRemoteAlias ||
+ normalizedRemoteAlias.includes(':') ||
+ !ALIAS_TOKEN_PATTERN.test(normalizedRemoteAlias)
+ ) {
throw new Error(
- `Remote alias must be a non-empty identifier without ":" delimiters. Received: ${remoteAlias}`,
+ `Remote alias must be a non-empty token (letters, numbers, "-", "_", ".") without ":" delimiters. Received: ${remoteAlias}`,
);
}
const remoteActionUrl = getNormalizedRemoteActionUrl(normalizedRemoteOrigin);
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index f6673091f239..70dba3c77b0d 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -618,14 +618,20 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
+ expect(runtimeRegisterSource).toContain(
+ 'const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/',
+ );
expect(runtimeRegisterSource).toContain(
'const normalizedRemoteAlias = remoteAlias.trim()',
);
expect(runtimeRegisterSource).toContain(
- "!normalizedRemoteAlias || normalizedRemoteAlias.includes(':')",
+ "normalizedRemoteAlias.includes(':')",
+ );
+ expect(runtimeRegisterSource).toContain(
+ '!ALIAS_TOKEN_PATTERN.test(normalizedRemoteAlias)',
);
expect(runtimeRegisterSource).toContain(
- 'Remote alias must be a non-empty identifier without ":" delimiters',
+ 'Remote alias must be a non-empty token (letters, numbers, "-", "_", ".") without ":" delimiters',
);
expect(runtimeRegisterSource).toContain(
"if (rawActionId.startsWith('remote:'))",
From 916209cc81c0181b14caa82a4bd26781e26bde6b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:36:26 +0000
Subject: [PATCH 165/324] refactor(rsc-mf): normalize raw action ids before
bridge prefix
---
.../src/runtime/registerServerCallback.ts | 16 ++++++++++++---
tests/integration/rsc-mf/tests/index.test.ts | 20 ++-----------------
2 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index d93084b38bf6..a7c38f4dd2f5 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -7,13 +7,23 @@ import {
let registeredCallbackKey = '';
const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
+const getNormalizedRawActionId = (rawActionId: string) => {
+ const normalizedRawActionId = rawActionId.trim();
+ if (!normalizedRawActionId || /\s/.test(normalizedRawActionId)) {
+ throw new Error(
+ `Remote action id must be a non-empty token without whitespace. Received: ${rawActionId}`,
+ );
+ }
+ return normalizedRawActionId;
+};
const getHostActionId = (rawActionId: string, remoteAlias: string) => {
- if (rawActionId.startsWith('remote:')) {
- return rawActionId;
+ const normalizedRawActionId = getNormalizedRawActionId(rawActionId);
+ if (normalizedRawActionId.startsWith('remote:')) {
+ return normalizedRawActionId;
}
// Align with RSC bridge action-id format expected by host runtime plugin.
- return `remote:${remoteAlias}:${rawActionId}`;
+ return `remote:${remoteAlias}:${normalizedRawActionId}`;
};
const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
const url = new URL(remoteOrigin);
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 70dba3c77b0d..d67f02a3eed8 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -618,27 +618,11 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
- expect(runtimeRegisterSource).toContain(
- 'const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/',
- );
- expect(runtimeRegisterSource).toContain(
- 'const normalizedRemoteAlias = remoteAlias.trim()',
- );
- expect(runtimeRegisterSource).toContain(
- "normalizedRemoteAlias.includes(':')",
- );
- expect(runtimeRegisterSource).toContain(
- '!ALIAS_TOKEN_PATTERN.test(normalizedRemoteAlias)',
- );
expect(runtimeRegisterSource).toContain(
'Remote alias must be a non-empty token (letters, numbers, "-", "_", ".") without ":" delimiters',
);
- expect(runtimeRegisterSource).toContain(
- "if (rawActionId.startsWith('remote:'))",
- );
- expect(runtimeRegisterSource).toContain(
- 'return `remote:${remoteAlias}:${rawActionId}`',
- );
+ expect(runtimeRegisterSource).toContain("startsWith('remote:')");
+ expect(runtimeRegisterSource).toContain('return `remote:${remoteAlias}:');
expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
expect(runtimeRegisterSource).toContain("method: 'POST'");
expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
From 97084d6ab5184f8387aab344f9b4b21c79a459e6 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:38:57 +0000
Subject: [PATCH 166/324] test(rsc-mf): reduce brittle runtime source
assertions
---
tests/integration/rsc-mf/tests/index.test.ts | 22 --------------------
1 file changed, 22 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index d67f02a3eed8..56e45e8a83fe 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -618,18 +618,12 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
- expect(runtimeRegisterSource).toContain(
- 'Remote alias must be a non-empty token (letters, numbers, "-", "_", ".") without ":" delimiters',
- );
expect(runtimeRegisterSource).toContain("startsWith('remote:')");
expect(runtimeRegisterSource).toContain('return `remote:${remoteAlias}:');
expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
expect(runtimeRegisterSource).toContain("method: 'POST'");
expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
expect(runtimeRegisterSource).toContain('getNormalizedRemoteActionUrl');
- expect(runtimeRegisterSource).toContain(
- "url.protocol !== 'http:' && url.protocol !== 'https:'",
- );
expect(runtimeRegisterSource).toContain(
'Remote action callback URL must use http or https',
);
@@ -638,23 +632,7 @@ function runTests({ mode }: TestConfig) {
);
expect(runtimeRegisterSource).toContain("url.search = ''");
expect(runtimeRegisterSource).toContain("url.hash = ''");
- expect(runtimeRegisterSource).toContain(
- 'remoteAlias: normalizedRemoteAlias',
- );
- expect(runtimeRegisterSource).toContain(
- 'getHostActionId(id, normalizedRemoteAlias)',
- );
- expect(runtimeRegisterSource).toContain(
- 'const normalizedRemoteOrigin = remoteOrigin.trim()',
- );
- expect(runtimeRegisterSource).toContain('if (!normalizedRemoteOrigin)');
expect(runtimeRegisterSource).toContain('remoteActionUrl,');
- expect(runtimeRegisterSource).not.toContain(
- 'getHostActionId(id, remoteAlias)',
- );
- expect(runtimeRegisterSource).not.toContain(
- 'getNormalizedRemoteActionUrl(remoteOrigin)',
- );
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
From 102d1fdd1f5c0c7965abd8fce133ed1e3b0f385b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:42:11 +0000
Subject: [PATCH 167/324] test(rsc-mf): focus source guards on stable
integration contracts
---
tests/integration/rsc-mf/tests/index.test.ts | 26 --------------------
1 file changed, 26 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 56e45e8a83fe..ef785aa3de82 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -583,32 +583,12 @@ function runTests({ mode }: TestConfig) {
!source.includes('rsc-mf-react-server-dom-client-browser'),
),
).toBe(true);
- expect(runtimeInitSource).toContain('registerRemoteServerCallback');
- expect(runtimeInitSource).toContain('bootstrapServerCallback');
- expect(runtimeInitSource).toContain('callbackBootstrapPromise');
- expect(runtimeInitSource).toContain("if (typeof window !== 'undefined')");
expect(runtimeInitSource).toContain("import('./registerServerCallback')");
- expect(runtimeInitSource).toContain('void bootstrapServerCallback()');
expect(runtimeInitSource).toContain('window.location.origin');
expect(runtimeInitSource).toContain('window.location.pathname');
- expect(runtimeInitSource).toContain('callbackBootstrapPromise.catch');
- expect(runtimeInitSource).toContain(
- 'callbackBootstrapPromise = undefined',
- );
- expect(runtimeInitSource).not.toContain('setServerCallback(');
expect(runtimeInitSource).not.toContain('RSC_MF_REMOTE_PORT');
expect(runtimeInitSource).not.toContain('127.0.0.1:');
- expect(runtimeInitSource).not.toContain(
- "from './registerServerCallback'",
- );
expect(runtimeRegisterSource).toContain('setServerCallback');
- expect(runtimeRegisterSource).toContain('createTemporaryReferenceSet');
- expect(runtimeRegisterSource).toContain(
- 'encodeReply(args, { temporaryReferences })',
- );
- expect(runtimeRegisterSource).toContain(
- 'createFromFetch(response, { temporaryReferences })',
- );
expect(runtimeRegisterSource).toContain(
"from 'rsc-mf-react-server-dom-client-browser'",
);
@@ -617,9 +597,6 @@ function runTests({ mode }: TestConfig) {
);
expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
expect(runtimeRegisterSource).not.toContain('window.location');
- expect(runtimeRegisterSource).toContain("remoteAlias = 'rscRemote'");
- expect(runtimeRegisterSource).toContain("startsWith('remote:')");
- expect(runtimeRegisterSource).toContain('return `remote:${remoteAlias}:');
expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
expect(runtimeRegisterSource).toContain("method: 'POST'");
expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
@@ -630,9 +607,6 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).toContain(
'Remote action callback URL must not include embedded credentials.',
);
- expect(runtimeRegisterSource).toContain("url.search = ''");
- expect(runtimeRegisterSource).toContain("url.hash = ''");
- expect(runtimeRegisterSource).toContain('remoteActionUrl,');
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
From 9cd4ad0a46a61be5681536c0497aebd9bc49c414 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:48:10 +0000
Subject: [PATCH 168/324] test(rsc-mf): add runtime callback contract behavior
tests
---
.../src/runtime/registerServerCallback.ts | 2 +-
.../tests/registerServerCallback.test.ts | 132 ++++++++++++++++++
...sc-mf-react-server-dom-client-browser.d.ts | 17 +++
3 files changed, 150 insertions(+), 1 deletion(-)
create mode 100644 tests/integration/rsc-mf/tests/registerServerCallback.test.ts
create mode 100644 tests/integration/rsc-mf/tests/rsc-mf-react-server-dom-client-browser.d.ts
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index a7c38f4dd2f5..f0dd2c43482e 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -69,7 +69,7 @@ export function registerRemoteServerCallback(
return;
}
- setServerCallback(async (id, args) => {
+ setServerCallback(async (id: string, args: unknown[]) => {
const hostActionId = getHostActionId(id, normalizedRemoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
const response = fetch(remoteActionUrl, {
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
new file mode 100644
index 000000000000..32a84e853997
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -0,0 +1,132 @@
+type ServerCallback = (id: string, args: unknown[]) => Promise;
+
+const mockSetServerCallback = jest.fn();
+const mockCreateTemporaryReferenceSet = jest.fn(() => ({ ref: 'temp-ref' }));
+const mockEncodeReply = jest.fn(async (args: unknown[]) => ({
+ encodedArgs: args,
+}));
+const mockCreateFromFetch = jest.fn(() => ({ type: 'decoded-rsc-response' }));
+
+jest.mock(
+ 'rsc-mf-react-server-dom-client-browser',
+ () => ({
+ setServerCallback: mockSetServerCallback,
+ createTemporaryReferenceSet: mockCreateTemporaryReferenceSet,
+ encodeReply: mockEncodeReply,
+ createFromFetch: mockCreateFromFetch,
+ }),
+ { virtual: true },
+);
+
+const importRegisterHelper = async () =>
+ import('../remote/src/runtime/registerServerCallback');
+
+describe('registerRemoteServerCallback runtime behavior', () => {
+ const originalFetch = global.fetch;
+
+ beforeEach(() => {
+ jest.resetModules();
+ mockSetServerCallback.mockReset();
+ mockCreateTemporaryReferenceSet.mockClear();
+ mockEncodeReply.mockClear();
+ mockCreateFromFetch.mockClear();
+ global.fetch = jest.fn(async () => ({ ok: true }) as Response);
+ });
+
+ afterAll(() => {
+ global.fetch = originalFetch;
+ });
+
+ const getRegisteredCallback = () => {
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+ const callback = mockSetServerCallback.mock.calls[0]?.[0] as
+ | ServerCallback
+ | undefined;
+ expect(typeof callback).toBe('function');
+ return callback as ServerCallback;
+ };
+
+ it('registers callback and forwards raw action ids with bridge prefix', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root?debug=1#hash',
+ 'rscRemote',
+ );
+
+ const callback = getRegisteredCallback();
+ await callback('abc123', ['arg-1', { nested: true }]);
+
+ expect(global.fetch).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ method: 'POST',
+ headers: expect.objectContaining({
+ Accept: 'text/x-component',
+ 'x-rsc-action': 'remote:rscRemote:abc123',
+ }),
+ }),
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledWith(
+ ['arg-1', { nested: true }],
+ expect.objectContaining({
+ temporaryReferences: expect.any(Object),
+ }),
+ );
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
+ it('preserves already-prefixed action ids and dedupes normalized callback registrations', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root?first=1',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root#second',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('remote:rscRemote:already-prefixed', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:already-prefixed',
+ }),
+ }),
+ );
+ });
+
+ it('rejects invalid aliases and callback URLs', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+
+ expect(() =>
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'bad alias',
+ ),
+ ).toThrow('Remote alias must be a non-empty token');
+ expect(() =>
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'bad:alias',
+ ),
+ ).toThrow('Remote alias must be a non-empty token');
+ expect(() =>
+ registerRemoteServerCallback('javascript:alert(1)', 'rscRemote'),
+ ).toThrow('Remote action callback URL must use http or https');
+ expect(() =>
+ registerRemoteServerCallback(
+ 'http://user:secret@127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ ),
+ ).toThrow(
+ 'Remote action callback URL must not include embedded credentials',
+ );
+ });
+});
diff --git a/tests/integration/rsc-mf/tests/rsc-mf-react-server-dom-client-browser.d.ts b/tests/integration/rsc-mf/tests/rsc-mf-react-server-dom-client-browser.d.ts
new file mode 100644
index 000000000000..cd7c4bac56d4
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/rsc-mf-react-server-dom-client-browser.d.ts
@@ -0,0 +1,17 @@
+declare module 'rsc-mf-react-server-dom-client-browser' {
+ export function setServerCallback(
+ callback: (id: string, args: unknown[]) => Promise,
+ ): void;
+
+ export function createTemporaryReferenceSet(): unknown;
+
+ export function encodeReply(
+ value: unknown,
+ options: { temporaryReferences: unknown },
+ ): Promise;
+
+ export function createFromFetch(
+ response: Promise,
+ options: { temporaryReferences: unknown },
+ ): unknown;
+}
From 6638c755f666e8191f2d193f74baac599f801398 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:51:19 +0000
Subject: [PATCH 169/324] test(rsc-mf): cover action-id normalization and
empty-origin skip
---
.../tests/registerServerCallback.test.ts | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 32a84e853997..894357d3dcd9 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -77,6 +77,26 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('normalizes action ids and rejects whitespace-delimited ids', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+
+ const callback = getRegisteredCallback();
+ await callback(' abc123 ', []);
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:abc123',
+ }),
+ }),
+ );
+
+ await expect(callback('abc 123', [])).rejects.toThrow(
+ 'Remote action id must be a non-empty token without whitespace',
+ );
+ });
+
it('preserves already-prefixed action ids and dedupes normalized callback registrations', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
@@ -102,6 +122,12 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('ignores empty callback origins after trimming', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(' ');
+ expect(mockSetServerCallback).not.toHaveBeenCalled();
+ });
+
it('rejects invalid aliases and callback URLs', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
From 992d086b6f0f52dbac79511152cf666cf560370e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:54:15 +0000
Subject: [PATCH 170/324] test(rsc-mf): cover alias trim dedupe in callback
registration
---
.../tests/registerServerCallback.test.ts | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 894357d3dcd9..f681a1637cb7 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -122,6 +122,30 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('trims alias before callback keying and action prefixing', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ ' rscRemote ',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('trimmed-alias-action', []);
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:trimmed-alias-action',
+ }),
+ }),
+ );
+ });
+
it('ignores empty callback origins after trimming', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(' ');
From 423164b8d6a96db3048c0f3764bc3cc2ac29a4e2 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 05:57:19 +0000
Subject: [PATCH 171/324] test(rsc-mf): verify alias changes re-register
callback handler
---
.../tests/registerServerCallback.test.ts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index f681a1637cb7..75d4b66ba0cc 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -122,6 +122,34 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('re-registers callback when alias changes and uses new alias prefix', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemoteAlt',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(2);
+
+ const callback = mockSetServerCallback.mock.calls[1]?.[0] as
+ | ServerCallback
+ | undefined;
+ expect(typeof callback).toBe('function');
+ await (callback as ServerCallback)('alias-change-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemoteAlt:alias-change-action',
+ }),
+ }),
+ );
+ });
+
it('trims alias before callback keying and action prefixing', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
From 34dc4420fa22077316589c30fccd65e2b51e5cfb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:00:30 +0000
Subject: [PATCH 172/324] test(rsc-mf): cover callback rebind on normalized URL
changes
---
.../tests/registerServerCallback.test.ts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 75d4b66ba0cc..9f4418d16ddc 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -150,6 +150,34 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('re-registers callback when normalized action URL changes', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/another-action-endpoint?cache=1#hash',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(2);
+
+ const callback = mockSetServerCallback.mock.calls[1]?.[0] as
+ | ServerCallback
+ | undefined;
+ expect(typeof callback).toBe('function');
+ await (callback as ServerCallback)('path-change-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/another-action-endpoint',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:path-change-action',
+ }),
+ }),
+ );
+ });
+
it('trims alias before callback keying and action prefixing', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
From 587ab2503a530aca2d6d0bde7e5bfd073017c913 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:03:26 +0000
Subject: [PATCH 173/324] test(rsc-mf): assert callback rebind when endpoint
path changes
---
.../tests/registerServerCallback.test.ts | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 9f4418d16ddc..87941b760af7 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -95,6 +95,9 @@ describe('registerRemoteServerCallback runtime behavior', () => {
await expect(callback('abc 123', [])).rejects.toThrow(
'Remote action id must be a non-empty token without whitespace',
);
+ await expect(callback(' ', [])).rejects.toThrow(
+ 'Remote action id must be a non-empty token without whitespace',
+ );
});
it('preserves already-prefixed action ids and dedupes normalized callback registrations', async () => {
@@ -202,6 +205,25 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('accepts token aliases with dot, underscore, and dash characters', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'remote.alias_v2-test',
+ );
+
+ const callback = getRegisteredCallback();
+ await callback('token-alias-action', []);
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:remote.alias_v2-test:token-alias-action',
+ }),
+ }),
+ );
+ });
+
it('ignores empty callback origins after trimming', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(' ');
From a0168c4225d714260c9d38fb28bbba834756f9cb Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:08:29 +0000
Subject: [PATCH 174/324] test(rsc-mf): add init callback bootstrap behavior
coverage
---
.../rsc-mf/tests/initServerCallback.test.ts | 106 ++++++++++++++++++
.../tests/registerServerCallback.test.ts | 18 +++
2 files changed, 124 insertions(+)
create mode 100644 tests/integration/rsc-mf/tests/initServerCallback.test.ts
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
new file mode 100644
index 000000000000..42bbc0111b78
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -0,0 +1,106 @@
+const INIT_SERVER_CALLBACK_MODULE = '../remote/src/runtime/initServerCallback';
+const REGISTER_SERVER_CALLBACK_MODULE =
+ '../remote/src/runtime/registerServerCallback';
+
+const flushMicrotasks = async () => {
+ await Promise.resolve();
+ await Promise.resolve();
+};
+
+describe('initServerCallback runtime bootstrap behavior', () => {
+ const originalWindow = (globalThis as { window?: unknown }).window;
+
+ afterEach(() => {
+ if (typeof originalWindow === 'undefined') {
+ delete (globalThis as { window?: unknown }).window;
+ return;
+ }
+
+ (globalThis as { window?: unknown }).window = originalWindow;
+ });
+
+ it('does not bootstrap callback registration on server import', async () => {
+ jest.resetModules();
+ delete (globalThis as { window?: unknown }).window;
+
+ const mockRegisterRemoteServerCallback = jest.fn();
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ }));
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).not.toHaveBeenCalled();
+ });
+
+ it('registers callback once with browser origin and pathname', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:3900',
+ pathname: '/server-component-root',
+ },
+ };
+
+ const mockRegisterRemoteServerCallback = jest.fn();
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ }));
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3900/server-component-root',
+ 'rscRemote',
+ );
+ });
+
+ it('falls back to root action pathname when location pathname is empty', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4100',
+ pathname: '',
+ },
+ };
+
+ const mockRegisterRemoteServerCallback = jest.fn();
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ }));
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
+ 'http://127.0.0.1:4100/',
+ 'rscRemote',
+ );
+ });
+
+ it('keeps bootstrap side effect memoized across repeated imports', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4300',
+ pathname: '/server-component-root',
+ },
+ };
+
+ const mockRegisterRemoteServerCallback = jest.fn();
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ }));
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 87941b760af7..9d474aeb2a04 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -233,6 +233,12 @@ describe('registerRemoteServerCallback runtime behavior', () => {
it('rejects invalid aliases and callback URLs', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
+ expect(() =>
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ ' ',
+ ),
+ ).toThrow('Remote alias must be a non-empty token');
expect(() =>
registerRemoteServerCallback(
'http://127.0.0.1:3008/server-component-root',
@@ -245,9 +251,21 @@ describe('registerRemoteServerCallback runtime behavior', () => {
'bad:alias',
),
).toThrow('Remote alias must be a non-empty token');
+ expect(() =>
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'bad/alias',
+ ),
+ ).toThrow('Remote alias must be a non-empty token');
expect(() =>
registerRemoteServerCallback('javascript:alert(1)', 'rscRemote'),
).toThrow('Remote action callback URL must use http or https');
+ expect(() =>
+ registerRemoteServerCallback(
+ 'ftp://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ ),
+ ).toThrow('Remote action callback URL must use http or https');
expect(() =>
registerRemoteServerCallback(
'http://user:secret@127.0.0.1:3008/server-component-root',
From 18cdc2e069d02074b939f8619212923f9ceb6ee8 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:13:44 +0000
Subject: [PATCH 175/324] test(rsc-mf): move mf config guardrails into behavior
tests
---
tests/integration/rsc-mf/tests/index.test.ts | 151 ----------------
.../tests/moduleFederationConfig.test.ts | 166 ++++++++++++++++++
2 files changed, 166 insertions(+), 151 deletions(-)
create mode 100644 tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index ef785aa3de82..0b7366f50a36 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -35,8 +35,6 @@ const EXPECTED_REMOTE_EXPOSE_PATHS = [
'./actionBundle',
'./infoBundle',
].sort();
-const REMOTE_EXPOSE_ENTRY_PATTERN =
- /'(\.\/[^']+)':\s*'(\.\/src\/components\/[^']+)'/g;
type Mode = 'dev' | 'build';
@@ -95,15 +93,6 @@ function createHostEnv(remotePort: number) {
};
}
-function getRemoteExposeEntries(configSource: string) {
- return Array.from(configSource.matchAll(REMOTE_EXPOSE_ENTRY_PATTERN)).map(
- ([, exposeKey, importPath]) => ({
- exposeKey,
- importPath,
- }),
- );
-}
-
async function renderRemoteRscIntoHost({ hostPort, page }: TestContext) {
const response = await fetch(`http://127.0.0.1:${hostPort}${HOST_RSC_URL}`);
const html = await response.text();
@@ -512,22 +501,6 @@ function runTests({ mode }: TestConfig) {
path.join(remoteDir, 'src/runtime/registerServerCallback.ts'),
'utf-8',
);
- const moduleFederationConfigSource = fs.readFileSync(
- path.join(remoteDir, 'module-federation.config.ts'),
- 'utf-8',
- );
- const hostModuleFederationConfigSource = fs.readFileSync(
- path.join(hostDir, 'module-federation.config.ts'),
- 'utf-8',
- );
- const hostModernConfigSource = fs.readFileSync(
- path.join(hostDir, 'modern.config.ts'),
- 'utf-8',
- );
- const remoteModernConfigSource = fs.readFileSync(
- path.join(remoteDir, 'modern.config.ts'),
- 'utf-8',
- );
const remoteRuntimeExposesDir = path.join(
remoteDir,
'src/runtime/exposes',
@@ -544,17 +517,6 @@ function runTests({ mode }: TestConfig) {
const remoteRuntimeEntriesWithoutExposeDir = remoteRuntimeEntries.filter(
entryName => entryName !== 'exposes',
);
- const remoteExposeEntries = getRemoteExposeEntries(
- moduleFederationConfigSource,
- );
- const remoteExposeKeys = remoteExposeEntries
- .map(({ exposeKey }) => exposeKey)
- .sort();
- const clientBrowserSharedScopeEntryCount = (
- moduleFederationConfigSource.match(
- /'react-server-dom-rspack\/client\.browser':\s*\{/g,
- ) || []
- ).length;
expect(
componentSources.every(
@@ -610,124 +572,11 @@ function runTests({ mode }: TestConfig) {
expect(runtimeRegisterSource).not.toContain(
'remoteActionIdToHostProxyActionId',
);
- expect(moduleFederationConfigSource).toContain(
- 'CALLBACK_BOOTSTRAP_IMPORT',
- );
- expect(moduleFederationConfigSource).toContain(
- 'CALLBACK_BOOTSTRAP_PREFIX',
- );
- expect(moduleFederationConfigSource).toContain(
- 'Callback bootstrap import must stay in runtime namespace',
- );
- expect(moduleFederationConfigSource).toContain(
- 'Callback bootstrap import must use explicit source extension',
- );
- expect(moduleFederationConfigSource).toContain(
- 'Callback bootstrap import must not contain traversal or Windows separators',
- );
- expect(
- moduleFederationConfigSource.includes(
- '[CALLBACK_BOOTSTRAP_IMPORT, importPath]',
- ),
- ).toBe(true);
- expect(moduleFederationConfigSource).not.toContain(
- 'callbackBootstrappedExposes',
- );
- expect(moduleFederationConfigSource).not.toContain(
- 'missingCallbackExposeEntries',
- );
- expect(moduleFederationConfigSource).not.toContain(
- './src/runtime/exposes/',
- );
expect(remoteRuntimeExposeEntries).toEqual([]);
expect(remoteRuntimeEntriesWithoutExposeDir).toEqual([
'initServerCallback.ts',
'registerServerCallback.ts',
]);
- expect(moduleFederationConfigSource).toContain('COMPONENT_EXPOSE_PREFIX');
- expect(moduleFederationConfigSource).toContain(
- 'nonComponentExposeEntries',
- );
- expect(moduleFederationConfigSource).toContain(
- 'nonTypeScriptExposeEntries',
- );
- expect(moduleFederationConfigSource).toContain(
- 'parentTraversalExposeEntries',
- );
- expect(moduleFederationConfigSource).toContain('nonPosixExposeEntries');
- expect(moduleFederationConfigSource).toContain('invalidExposeKeys');
- expect(moduleFederationConfigSource).toContain('callbackExposeEntries');
- expect(moduleFederationConfigSource).toContain("shareScope: 'default'");
- expect(moduleFederationConfigSource).toContain("shareScope: 'ssr'");
- expect(moduleFederationConfigSource).toContain("shareScope: 'rsc'");
- expect(moduleFederationConfigSource).toContain('experiments:');
- expect(moduleFederationConfigSource).toContain('asyncStartup: true');
- expect(moduleFederationConfigSource).toContain('rsc: true');
- expect(clientBrowserSharedScopeEntryCount).toBe(3);
- expect(remoteExposeKeys).toEqual(EXPECTED_REMOTE_EXPOSE_PATHS);
- expect(
- remoteExposeEntries.every(({ importPath }) =>
- importPath.startsWith('./src/components/'),
- ),
- ).toBe(true);
- expect(
- remoteExposeEntries.every(({ importPath }) =>
- /\.[tj]sx?$/.test(importPath),
- ),
- ).toBe(true);
- expect(
- remoteExposeEntries.every(
- ({ importPath }) =>
- !importPath.includes('..') && !importPath.includes('\\'),
- ),
- ).toBe(true);
- expect(
- remoteExposeEntries.every(({ importPath }) =>
- fs.existsSync(path.resolve(remoteDir, importPath)),
- ),
- ).toBe(true);
- expect(hostModuleFederationConfigSource).toContain('runtimePlugins');
- expect(hostModuleFederationConfigSource).toContain(
- './runtime/forceRemotePublicPath.ts',
- );
- expect(hostModuleFederationConfigSource).toContain(
- "process.env.NODE_ENV === 'production'",
- );
- expect(hostModuleFederationConfigSource).toContain(': []');
- expect(hostModuleFederationConfigSource).toContain(
- '/static/mf-manifest.json',
- );
- expect(hostModuleFederationConfigSource).toContain('RSC_MF_REMOTE_PORT');
- expect(hostModuleFederationConfigSource).toContain('rscRemote:');
- expect(hostModuleFederationConfigSource).toContain('asyncStartup: true');
- expect(hostModuleFederationConfigSource).toContain('rsc: true');
- expect(hostModuleFederationConfigSource).not.toContain(
- 'registerServerCallbackRuntime',
- );
- expect(hostModuleFederationConfigSource).not.toContain(
- 'initServerCallback',
- );
- expect(hostModernConfigSource).not.toContain('preEntry');
- expect(hostModernConfigSource).not.toContain('registerServerCallback');
- expect(hostModernConfigSource).toContain('enableAsyncEntry: false');
- expect(hostModernConfigSource).toContain("chain.target('async-node')");
- expect(hostModernConfigSource).toContain("'server-only$'");
- expect(hostModernConfigSource).toContain(
- 'moduleFederationPlugin({ ssr: true })',
- );
- expect(remoteModernConfigSource).not.toContain('chunkLoadingGlobal');
- expect(remoteModernConfigSource).toContain(
- 'rsc-mf-react-server-dom-client-browser$',
- );
- expect(remoteModernConfigSource).toContain(
- 'react-server-dom-rspack/client.browser',
- );
- expect(remoteModernConfigSource).toContain('enableAsyncEntry: false');
- expect(remoteModernConfigSource).toContain("chain.target('async-node')");
- expect(remoteModernConfigSource).toContain('splitChunks(false)');
- expect(remoteModernConfigSource).toContain(
- 'moduleFederationPlugin({ ssr: true })',
- );
});
it('should not load callback helper expose chunk', () => {
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
new file mode 100644
index 000000000000..76e63c11f6f4
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -0,0 +1,166 @@
+const HOST_MODULE_FEDERATION_CONFIG_MODULE = '../host/module-federation.config';
+const REMOTE_MODULE_FEDERATION_CONFIG_MODULE =
+ '../remote/module-federation.config';
+
+const EXPECTED_REMOTE_EXPOSE_KEYS = [
+ './RemoteClientCounter',
+ './RemoteClientBadge',
+ './RemoteServerCard',
+ './RemoteServerDefault',
+ './AsyncRemoteServerInfo',
+ './remoteServerOnly',
+ './remoteServerOnlyDefault',
+ './remoteMeta',
+ './actions',
+ './nestedActions',
+ './defaultAction',
+ './actionBundle',
+ './infoBundle',
+].sort();
+
+const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
+
+const withEnv = (
+ env: Partial>,
+ run: () => T,
+): T => {
+ const previousNodeEnv = process.env.NODE_ENV;
+ const previousRemotePort = process.env.RSC_MF_REMOTE_PORT;
+
+ if (typeof env.NODE_ENV === 'undefined') {
+ delete process.env.NODE_ENV;
+ } else {
+ process.env.NODE_ENV = env.NODE_ENV as NodeJS.ProcessEnv['NODE_ENV'];
+ }
+
+ if (typeof env.RSC_MF_REMOTE_PORT === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = env.RSC_MF_REMOTE_PORT;
+ }
+
+ try {
+ return run();
+ } finally {
+ if (typeof previousNodeEnv === 'undefined') {
+ delete process.env.NODE_ENV;
+ } else {
+ process.env.NODE_ENV = previousNodeEnv;
+ }
+ if (typeof previousRemotePort === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = previousRemotePort;
+ }
+ }
+};
+
+const loadRemoteConfig = () =>
+ withEnv({}, () => {
+ let config: any;
+ jest.isolateModules(() => {
+ config = require(REMOTE_MODULE_FEDERATION_CONFIG_MODULE).default;
+ });
+ return config;
+ });
+
+const loadHostConfig = ({
+ nodeEnv,
+ remotePort,
+}: {
+ nodeEnv: string;
+ remotePort?: string;
+}) =>
+ withEnv(
+ {
+ NODE_ENV: nodeEnv,
+ RSC_MF_REMOTE_PORT: remotePort,
+ },
+ () => {
+ let config: any;
+ jest.isolateModules(() => {
+ config = require(HOST_MODULE_FEDERATION_CONFIG_MODULE).default;
+ });
+ return config;
+ },
+ );
+
+describe('rsc-mf module federation config contracts', () => {
+ it('declares expected remote exposes with callback bootstrap imports', () => {
+ const remoteConfig = loadRemoteConfig();
+ const exposeEntries = Object.entries(remoteConfig.exposes || {});
+ const exposeKeys = exposeEntries
+ .map(([exposeKey]) => exposeKey)
+ .sort() as string[];
+ expect(exposeKeys).toEqual(EXPECTED_REMOTE_EXPOSE_KEYS);
+
+ for (const [exposeKey, exposeDefinition] of exposeEntries) {
+ const definition = exposeDefinition as {
+ import?: string[];
+ layer?: string;
+ };
+ expect(definition.layer).toBe('react-server-components');
+ expect(definition.import).toBeDefined();
+ expect(Array.isArray(definition.import)).toBe(true);
+ expect(definition.import).toHaveLength(2);
+ expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
+ expect(definition.import?.[1]).toMatch(/^\.\/src\/components\//);
+ expect(definition.import?.[1]).toMatch(/\.[tj]sx?$/);
+ expect(definition.import?.[1]).not.toContain('..');
+ expect(definition.import?.[1]).not.toContain('\\');
+ expect(exposeKey).toMatch(/^\.\//);
+ }
+ });
+
+ it('keeps remote shared scopes and experiments aligned for rsc', () => {
+ const remoteConfig = loadRemoteConfig();
+ const sharedScopes = remoteConfig.shared as Array<
+ Record
+ >;
+
+ expect(sharedScopes).toHaveLength(3);
+ expect(sharedScopes[0]?.react?.shareScope).toBe('default');
+ expect(sharedScopes[1]?.react?.shareScope).toBe('ssr');
+ expect(sharedScopes[2]?.react?.shareScope).toBe('rsc');
+ expect(
+ sharedScopes.map(
+ scope => scope['react-server-dom-rspack/client.browser']?.shareScope,
+ ),
+ ).toEqual(['default', 'ssr', 'rsc']);
+ expect(remoteConfig.experiments).toEqual(
+ expect.objectContaining({
+ asyncStartup: true,
+ rsc: true,
+ }),
+ );
+ });
+
+ it('uses remote port env var in host manifest remote URL', () => {
+ const hostConfig = loadHostConfig({
+ nodeEnv: 'test',
+ remotePort: '3999',
+ });
+ expect(hostConfig.remotes).toEqual(
+ expect.objectContaining({
+ rscRemote: 'rscRemote@http://127.0.0.1:3999/static/mf-manifest.json',
+ }),
+ );
+ });
+
+ it('enables host runtime plugin only in production', () => {
+ const productionHostConfig = loadHostConfig({
+ nodeEnv: 'production',
+ remotePort: '3008',
+ });
+ expect(productionHostConfig.runtimePlugins).toHaveLength(1);
+ expect(productionHostConfig.runtimePlugins[0]).toContain(
+ 'runtime/forceRemotePublicPath.ts',
+ );
+
+ const developmentHostConfig = loadHostConfig({
+ nodeEnv: 'development',
+ remotePort: '3008',
+ });
+ expect(developmentHostConfig.runtimePlugins).toEqual([]);
+ });
+});
From 2ff9d9ef815846a1a8f08d60d227c6753a236756 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:17:45 +0000
Subject: [PATCH 176/324] test(rsc-mf): replace runtime source checks with
behavior guards
---
tests/integration/rsc-mf/tests/index.test.ts | 35 --------------
.../rsc-mf/tests/initServerCallback.test.ts | 48 +++++++++++--------
.../tests/registerServerCallback.test.ts | 9 ++++
3 files changed, 37 insertions(+), 55 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 0b7366f50a36..c3963bcadc3f 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -493,14 +493,6 @@ function runTests({ mode }: TestConfig) {
const hostSourceTexts = hostSourceFilePaths.map(filePath =>
fs.readFileSync(filePath, 'utf-8'),
);
- const runtimeInitSource = fs.readFileSync(
- path.join(remoteDir, 'src/runtime/initServerCallback.ts'),
- 'utf-8',
- );
- const runtimeRegisterSource = fs.readFileSync(
- path.join(remoteDir, 'src/runtime/registerServerCallback.ts'),
- 'utf-8',
- );
const remoteRuntimeExposesDir = path.join(
remoteDir,
'src/runtime/exposes',
@@ -545,33 +537,6 @@ function runTests({ mode }: TestConfig) {
!source.includes('rsc-mf-react-server-dom-client-browser'),
),
).toBe(true);
- expect(runtimeInitSource).toContain("import('./registerServerCallback')");
- expect(runtimeInitSource).toContain('window.location.origin');
- expect(runtimeInitSource).toContain('window.location.pathname');
- expect(runtimeInitSource).not.toContain('RSC_MF_REMOTE_PORT');
- expect(runtimeInitSource).not.toContain('127.0.0.1:');
- expect(runtimeRegisterSource).toContain('setServerCallback');
- expect(runtimeRegisterSource).toContain(
- "from 'rsc-mf-react-server-dom-client-browser'",
- );
- expect(runtimeRegisterSource).not.toContain(
- "from 'react-server-dom-rspack/client.browser'",
- );
- expect(runtimeRegisterSource).not.toContain('127.0.0.1:');
- expect(runtimeRegisterSource).not.toContain('window.location');
- expect(runtimeRegisterSource).toContain("'x-rsc-action': hostActionId");
- expect(runtimeRegisterSource).toContain("method: 'POST'");
- expect(runtimeRegisterSource).toContain("Accept: 'text/x-component'");
- expect(runtimeRegisterSource).toContain('getNormalizedRemoteActionUrl');
- expect(runtimeRegisterSource).toContain(
- 'Remote action callback URL must use http or https',
- );
- expect(runtimeRegisterSource).toContain(
- 'Remote action callback URL must not include embedded credentials.',
- );
- expect(runtimeRegisterSource).not.toContain(
- 'remoteActionIdToHostProxyActionId',
- );
expect(remoteRuntimeExposeEntries).toEqual([]);
expect(remoteRuntimeEntriesWithoutExposeDir).toEqual([
'initServerCallback.ts',
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
index 42bbc0111b78..d0a89d120fd4 100644
--- a/tests/integration/rsc-mf/tests/initServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -9,6 +9,22 @@ const flushMicrotasks = async () => {
describe('initServerCallback runtime bootstrap behavior', () => {
const originalWindow = (globalThis as { window?: unknown }).window;
+ const setupRegisterCallbackMock = () => {
+ const mockRegisterRemoteServerCallback = jest.fn();
+ let registerModuleLoadCount = 0;
+
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => {
+ registerModuleLoadCount += 1;
+ return {
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ };
+ });
+
+ return {
+ mockRegisterRemoteServerCallback,
+ getRegisterModuleLoadCount: () => registerModuleLoadCount,
+ };
+ };
afterEach(() => {
if (typeof originalWindow === 'undefined') {
@@ -22,15 +38,13 @@ describe('initServerCallback runtime bootstrap behavior', () => {
it('does not bootstrap callback registration on server import', async () => {
jest.resetModules();
delete (globalThis as { window?: unknown }).window;
-
- const mockRegisterRemoteServerCallback = jest.fn();
- jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
- registerRemoteServerCallback: mockRegisterRemoteServerCallback,
- }));
+ const { mockRegisterRemoteServerCallback, getRegisterModuleLoadCount } =
+ setupRegisterCallbackMock();
await import(INIT_SERVER_CALLBACK_MODULE);
await flushMicrotasks();
+ expect(getRegisterModuleLoadCount()).toBe(0);
expect(mockRegisterRemoteServerCallback).not.toHaveBeenCalled();
});
@@ -42,15 +56,13 @@ describe('initServerCallback runtime bootstrap behavior', () => {
pathname: '/server-component-root',
},
};
-
- const mockRegisterRemoteServerCallback = jest.fn();
- jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
- registerRemoteServerCallback: mockRegisterRemoteServerCallback,
- }));
+ const { mockRegisterRemoteServerCallback, getRegisterModuleLoadCount } =
+ setupRegisterCallbackMock();
await import(INIT_SERVER_CALLBACK_MODULE);
await flushMicrotasks();
+ expect(getRegisterModuleLoadCount()).toBe(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
'http://127.0.0.1:3900/server-component-root',
@@ -66,15 +78,13 @@ describe('initServerCallback runtime bootstrap behavior', () => {
pathname: '',
},
};
-
- const mockRegisterRemoteServerCallback = jest.fn();
- jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
- registerRemoteServerCallback: mockRegisterRemoteServerCallback,
- }));
+ const { mockRegisterRemoteServerCallback, getRegisterModuleLoadCount } =
+ setupRegisterCallbackMock();
await import(INIT_SERVER_CALLBACK_MODULE);
await flushMicrotasks();
+ expect(getRegisterModuleLoadCount()).toBe(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
'http://127.0.0.1:4100/',
@@ -90,17 +100,15 @@ describe('initServerCallback runtime bootstrap behavior', () => {
pathname: '/server-component-root',
},
};
-
- const mockRegisterRemoteServerCallback = jest.fn();
- jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
- registerRemoteServerCallback: mockRegisterRemoteServerCallback,
- }));
+ const { mockRegisterRemoteServerCallback, getRegisterModuleLoadCount } =
+ setupRegisterCallbackMock();
await import(INIT_SERVER_CALLBACK_MODULE);
await flushMicrotasks();
await import(INIT_SERVER_CALLBACK_MODULE);
await flushMicrotasks();
+ expect(getRegisterModuleLoadCount()).toBe(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
});
});
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 9d474aeb2a04..aac0f0041c5c 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -17,6 +17,15 @@ jest.mock(
}),
{ virtual: true },
);
+jest.mock(
+ 'react-server-dom-rspack/client.browser',
+ () => {
+ throw new Error(
+ 'registerServerCallback must import rsc-mf-react-server-dom-client-browser alias',
+ );
+ },
+ { virtual: true },
+);
const importRegisterHelper = async () =>
import('../remote/src/runtime/registerServerCallback');
From c429e030091ad37f8ea03638eff5e2540bfeab99 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:21:03 +0000
Subject: [PATCH 177/324] test(rsc-mf): trim remaining source-content guardrail
assertions
---
tests/integration/rsc-mf/tests/index.test.ts | 51 +-------------------
1 file changed, 1 insertion(+), 50 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index c3963bcadc3f..45e795c207db 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -470,29 +470,7 @@ function runTests({ mode }: TestConfig) {
).toBe(true);
});
- it('should keep callback runtime wiring out of component sources', () => {
- const getFilesRecursively = (directory: string): string[] =>
- fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
- const entryPath = path.join(directory, entry.name);
- if (entry.isDirectory()) {
- return getFilesRecursively(entryPath);
- }
- return [entryPath];
- });
-
- const componentFilePaths = getFilesRecursively(
- path.join(remoteDir, 'src/components'),
- );
- const hostSourceFilePaths = getFilesRecursively(
- path.join(hostDir, 'src'),
- ).filter(filePath => /\.(ts|tsx)$/.test(filePath));
-
- const componentSources = componentFilePaths.map(filePath =>
- fs.readFileSync(filePath, 'utf-8'),
- );
- const hostSourceTexts = hostSourceFilePaths.map(filePath =>
- fs.readFileSync(filePath, 'utf-8'),
- );
+ it('should keep callback helper surface constrained to runtime files', () => {
const remoteRuntimeExposesDir = path.join(
remoteDir,
'src/runtime/exposes',
@@ -510,33 +488,6 @@ function runTests({ mode }: TestConfig) {
entryName => entryName !== 'exposes',
);
- expect(
- componentSources.every(
- source => !source.includes('initServerCallback'),
- ),
- ).toBe(true);
- expect(
- componentSources.every(
- source => !source.includes('registerRemoteServerCallback'),
- ),
- ).toBe(true);
- expect(
- componentSources.every(
- source =>
- !source.includes('setServerCallback') &&
- !source.includes('rsc-mf-react-server-dom-client-browser'),
- ),
- ).toBe(true);
- expect(
- hostSourceTexts.every(
- source =>
- !source.includes('registerRemoteServerCallback') &&
- !source.includes('initServerCallback') &&
- !source.includes('registerServerCallback') &&
- !source.includes('setServerCallback') &&
- !source.includes('rsc-mf-react-server-dom-client-browser'),
- ),
- ).toBe(true);
expect(remoteRuntimeExposeEntries).toEqual([]);
expect(remoteRuntimeEntriesWithoutExposeDir).toEqual([
'initServerCallback.ts',
From 29137b84bd34adc398ac56313212ae908d29b56a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:24:58 +0000
Subject: [PATCH 178/324] test(rsc-mf): drop remaining filesystem source guard
checks
---
tests/integration/rsc-mf/tests/index.test.ts | 26 --------------------
1 file changed, 26 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 45e795c207db..40b43a4c6f01 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -1,4 +1,3 @@
-import fs from 'fs';
import path from 'path';
import { isVersionAtLeast18 } from '@modern-js/utils';
import type { Browser, Page } from 'puppeteer';
@@ -470,31 +469,6 @@ function runTests({ mode }: TestConfig) {
).toBe(true);
});
- it('should keep callback helper surface constrained to runtime files', () => {
- const remoteRuntimeExposesDir = path.join(
- remoteDir,
- 'src/runtime/exposes',
- );
- const remoteRuntimeExposeEntries = fs.existsSync(remoteRuntimeExposesDir)
- ? fs
- .readdirSync(remoteRuntimeExposesDir)
- .filter(entryName => !entryName.startsWith('.'))
- : [];
- const remoteRuntimeEntries = fs
- .readdirSync(path.join(remoteDir, 'src/runtime'))
- .filter(entryName => !entryName.startsWith('.'))
- .sort();
- const remoteRuntimeEntriesWithoutExposeDir = remoteRuntimeEntries.filter(
- entryName => entryName !== 'exposes',
- );
-
- expect(remoteRuntimeExposeEntries).toEqual([]);
- expect(remoteRuntimeEntriesWithoutExposeDir).toEqual([
- 'initServerCallback.ts',
- 'registerServerCallback.ts',
- ]);
- });
-
it('should not load callback helper expose chunk', () => {
expect(registerCallbackExposeRequestUrls).toEqual([]);
});
From b7dbdc6b68ccec866206f8b1b2bfda372adb3b1a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:26:15 +0000
Subject: [PATCH 179/324] test(rsc-mf): expand host config behavior coverage
---
.../tests/moduleFederationConfig.test.ts | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 76e63c11f6f4..af391020e395 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -147,6 +147,17 @@ describe('rsc-mf module federation config contracts', () => {
);
});
+ it('falls back to default remote manifest port when env var is unset', () => {
+ const hostConfig = loadHostConfig({
+ nodeEnv: 'test',
+ });
+ expect(hostConfig.remotes).toEqual(
+ expect.objectContaining({
+ rscRemote: 'rscRemote@http://127.0.0.1:3008/static/mf-manifest.json',
+ }),
+ );
+ });
+
it('enables host runtime plugin only in production', () => {
const productionHostConfig = loadHostConfig({
nodeEnv: 'production',
@@ -163,4 +174,17 @@ describe('rsc-mf module federation config contracts', () => {
});
expect(developmentHostConfig.runtimePlugins).toEqual([]);
});
+
+ it('keeps host experiments aligned for async startup and rsc', () => {
+ const hostConfig = loadHostConfig({
+ nodeEnv: 'test',
+ remotePort: '3008',
+ });
+ expect(hostConfig.experiments).toEqual(
+ expect.objectContaining({
+ asyncStartup: true,
+ rsc: true,
+ }),
+ );
+ });
});
From 396e7093a6caefcec4acd379214afb4d7a85d1a1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:30:12 +0000
Subject: [PATCH 180/324] test(rsc-mf): add modern config behavior contract
tests
---
.../rsc-mf/tests/modernConfig.test.ts | 301 ++++++++++++++++++
1 file changed, 301 insertions(+)
create mode 100644 tests/integration/rsc-mf/tests/modernConfig.test.ts
diff --git a/tests/integration/rsc-mf/tests/modernConfig.test.ts b/tests/integration/rsc-mf/tests/modernConfig.test.ts
new file mode 100644
index 000000000000..d56046dbe714
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/modernConfig.test.ts
@@ -0,0 +1,301 @@
+import path from 'path';
+
+const HOST_MODERN_CONFIG_MODULE = '../host/modern.config';
+const REMOTE_MODERN_CONFIG_MODULE = '../remote/modern.config';
+
+const withEnv = (
+ env: Partial>,
+ run: () => T,
+): T => {
+ const previousPort = process.env.PORT;
+ const previousRemotePort = process.env.RSC_MF_REMOTE_PORT;
+
+ if (typeof env.PORT === 'undefined') {
+ delete process.env.PORT;
+ } else {
+ process.env.PORT = env.PORT;
+ }
+ if (typeof env.RSC_MF_REMOTE_PORT === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = env.RSC_MF_REMOTE_PORT;
+ }
+
+ try {
+ return run();
+ } finally {
+ if (typeof previousPort === 'undefined') {
+ delete process.env.PORT;
+ } else {
+ process.env.PORT = previousPort;
+ }
+ if (typeof previousRemotePort === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = previousRemotePort;
+ }
+ }
+};
+
+const loadHostConfig = () =>
+ withEnv({}, () => {
+ jest.resetModules();
+ jest.doMock('@modern-js/app-tools', () => ({
+ appTools: () => ({ name: 'app-tools-mock' }),
+ defineConfig: (config: unknown) => config,
+ }));
+ jest.doMock('@module-federation/modern-js-v3', () => ({
+ moduleFederationPlugin: () => ({ name: 'mf-plugin-mock' }),
+ }));
+
+ let config: any;
+ jest.isolateModules(() => {
+ config = require(HOST_MODERN_CONFIG_MODULE).default;
+ });
+ return config;
+ });
+
+const loadRemoteConfig = ({
+ port,
+ remotePort,
+}: {
+ port?: string;
+ remotePort?: string;
+}) =>
+ withEnv(
+ {
+ PORT: port,
+ RSC_MF_REMOTE_PORT: remotePort,
+ },
+ () => {
+ jest.resetModules();
+ jest.doMock('@modern-js/app-tools', () => ({
+ appTools: () => ({ name: 'app-tools-mock' }),
+ defineConfig: (config: unknown) => config,
+ }));
+ jest.doMock('@module-federation/modern-js-v3', () => ({
+ moduleFederationPlugin: () => ({ name: 'mf-plugin-mock' }),
+ }));
+
+ let config: any;
+ jest.isolateModules(() => {
+ config = require(REMOTE_MODERN_CONFIG_MODULE).default;
+ });
+ return config;
+ },
+ );
+
+const createChainHarness = (target: string | string[]) => {
+ const aliasMap = new Map();
+ const conditionNames: string[] = [];
+ const moduleDirectories: string[] = [];
+ const publicPathCalls: string[] = [];
+ const splitChunksCalls: unknown[] = [];
+ const targetCalls: string[] = [];
+ const rules: Array<{ name: string; test?: RegExp; layer?: string }> = [];
+
+ const aliasApi = {
+ set: (key: string, value: string) => {
+ aliasMap.set(key, value);
+ return aliasApi;
+ },
+ };
+ const conditionNamesApi = {
+ clear: () => {
+ conditionNames.length = 0;
+ return conditionNamesApi;
+ },
+ add: (value: string) => {
+ conditionNames.push(value);
+ return conditionNamesApi;
+ },
+ };
+ const modulesApi = {
+ clear: () => {
+ moduleDirectories.length = 0;
+ return modulesApi;
+ },
+ add: (value: string) => {
+ moduleDirectories.push(value);
+ return modulesApi;
+ },
+ };
+
+ const chain = {
+ get: (key: string) => (key === 'target' ? target : undefined),
+ target: (value: string) => {
+ targetCalls.push(value);
+ return chain;
+ },
+ resolve: {
+ alias: aliasApi,
+ conditionNames: conditionNamesApi,
+ modules: modulesApi,
+ },
+ output: {
+ publicPath: (value: string) => {
+ publicPathCalls.push(value);
+ return chain.output;
+ },
+ },
+ optimization: {
+ splitChunks: (value: unknown) => {
+ splitChunksCalls.push(value);
+ return chain.optimization;
+ },
+ },
+ module: {
+ rule: (name: string) => {
+ const rule = { name } as {
+ name: string;
+ test?: RegExp;
+ layer?: string;
+ };
+ rules.push(rule);
+ return {
+ test: (value: RegExp) => {
+ rule.test = value;
+ return {
+ layer: (layerValue: string) => {
+ rule.layer = layerValue;
+ return chain.module;
+ },
+ };
+ },
+ };
+ },
+ },
+ };
+
+ return {
+ chain,
+ aliasMap,
+ conditionNames,
+ moduleDirectories,
+ publicPathCalls,
+ splitChunksCalls,
+ targetCalls,
+ rules,
+ };
+};
+
+describe('rsc-mf modern config contracts', () => {
+ it('keeps host modern server and source contracts', () => {
+ const hostConfig = loadHostConfig();
+ expect(hostConfig.server).toEqual(
+ expect.objectContaining({
+ rsc: true,
+ port: 3007,
+ }),
+ );
+ expect(hostConfig.source).toEqual(
+ expect.objectContaining({
+ enableAsyncEntry: false,
+ }),
+ );
+ expect(hostConfig.plugins).toHaveLength(2);
+ });
+
+ it('applies host async-node bundler behavior for node targets', () => {
+ const hostConfig = loadHostConfig();
+ const harness = createChainHarness('node');
+ hostConfig.tools?.bundlerChain?.(harness.chain as any);
+
+ expect(harness.targetCalls).toContain('async-node');
+ expect(harness.conditionNames).toEqual(['require', 'import', 'default']);
+ expect(harness.aliasMap.get('server-only$')).toMatch(
+ /server-only[\\/]empty\.js$/,
+ );
+ expect(harness.moduleDirectories).toEqual([
+ path.resolve(__dirname, '../host/node_modules'),
+ 'node_modules',
+ ]);
+ });
+
+ it('configures remote port-driven server and asset settings', () => {
+ const remoteConfig = loadRemoteConfig({
+ remotePort: '3991',
+ });
+
+ expect(remoteConfig.server).toEqual(
+ expect.objectContaining({
+ rsc: true,
+ ssr: false,
+ port: 3991,
+ }),
+ );
+ expect(remoteConfig.output).toEqual(
+ expect.objectContaining({
+ assetPrefix: 'http://127.0.0.1:3991',
+ }),
+ );
+ expect(remoteConfig.source).toEqual(
+ expect.objectContaining({
+ enableAsyncEntry: false,
+ }),
+ );
+ });
+
+ it('enables remote ssr mode when explicit PORT is set', () => {
+ const remoteConfig = loadRemoteConfig({
+ port: '4550',
+ });
+ expect(remoteConfig.server).toEqual(
+ expect.objectContaining({
+ ssr: true,
+ port: 4550,
+ }),
+ );
+ });
+
+ it('applies remote async-node + layer settings for node targets', () => {
+ const remoteConfig = loadRemoteConfig({
+ remotePort: '3777',
+ });
+ const harness = createChainHarness('node');
+ remoteConfig.tools?.bundlerChain?.(harness.chain as any);
+
+ expect(harness.targetCalls).toContain('async-node');
+ expect(harness.conditionNames).toEqual(['require', 'import', 'default']);
+ expect(harness.aliasMap.get('server-only$')).toMatch(
+ /server-only[\\/]empty\.js$/,
+ );
+ expect(harness.aliasMap.get('react/jsx-runtime$')).toMatch(
+ /react[\\/]jsx-runtime\.react-server\.js$/,
+ );
+ expect(harness.aliasMap.get('react/jsx-dev-runtime$')).toMatch(
+ /react[\\/]jsx-dev-runtime\.react-server\.js$/,
+ );
+ expect(
+ harness.aliasMap.get('rsc-mf-react-server-dom-client-browser$'),
+ ).toContain('react-server-dom-rspack');
+ expect(harness.publicPathCalls).toContain('http://127.0.0.1:3777/bundles/');
+ expect(harness.rules).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ name: 'rsc-mf-remote-components-layer',
+ layer: 'react-server-components',
+ }),
+ ]),
+ );
+ expect(harness.moduleDirectories).toEqual([
+ path.resolve(__dirname, '../remote/node_modules'),
+ 'node_modules',
+ ]);
+ });
+
+ it('applies remote client split-chunk + publicPath settings for web targets', () => {
+ const remoteConfig = loadRemoteConfig({
+ remotePort: '3888',
+ });
+ const harness = createChainHarness('web');
+ remoteConfig.tools?.bundlerChain?.(harness.chain as any);
+
+ expect(harness.targetCalls).toEqual([]);
+ expect(harness.splitChunksCalls).toEqual([false]);
+ expect(harness.publicPathCalls).toContain('http://127.0.0.1:3888/');
+ expect(
+ harness.aliasMap.get('rsc-mf-react-server-dom-client-browser$'),
+ ).toContain('react-server-dom-rspack');
+ });
+});
From 23831f78e3b7b2b8efe182a3493b30dde59bd21d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:33:02 +0000
Subject: [PATCH 181/324] test(rsc-mf): verify host shared scope alignment
---
.../tests/moduleFederationConfig.test.ts | 31 ++++++++++++++++---
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index af391020e395..95f362177c1d 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -19,6 +19,7 @@ const EXPECTED_REMOTE_EXPOSE_KEYS = [
].sort();
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
+const EXPECTED_SHARED_SCOPES = ['default', 'ssr', 'rsc'];
const withEnv = (
env: Partial>,
@@ -118,15 +119,15 @@ describe('rsc-mf module federation config contracts', () => {
Record
>;
- expect(sharedScopes).toHaveLength(3);
- expect(sharedScopes[0]?.react?.shareScope).toBe('default');
- expect(sharedScopes[1]?.react?.shareScope).toBe('ssr');
- expect(sharedScopes[2]?.react?.shareScope).toBe('rsc');
+ expect(sharedScopes).toHaveLength(EXPECTED_SHARED_SCOPES.length);
+ expect(sharedScopes.map(scope => scope.react?.shareScope)).toEqual(
+ EXPECTED_SHARED_SCOPES,
+ );
expect(
sharedScopes.map(
scope => scope['react-server-dom-rspack/client.browser']?.shareScope,
),
- ).toEqual(['default', 'ssr', 'rsc']);
+ ).toEqual(EXPECTED_SHARED_SCOPES);
expect(remoteConfig.experiments).toEqual(
expect.objectContaining({
asyncStartup: true,
@@ -187,4 +188,24 @@ describe('rsc-mf module federation config contracts', () => {
}),
);
});
+
+ it('keeps host shared scopes aligned for rsc runtime compatibility', () => {
+ const hostConfig = loadHostConfig({
+ nodeEnv: 'test',
+ remotePort: '3008',
+ });
+ const sharedScopes = hostConfig.shared as Array<
+ Record
+ >;
+
+ expect(sharedScopes).toHaveLength(EXPECTED_SHARED_SCOPES.length);
+ expect(sharedScopes.map(scope => scope.react?.shareScope)).toEqual(
+ EXPECTED_SHARED_SCOPES,
+ );
+ expect(
+ sharedScopes.map(
+ scope => scope['react-server-dom-rspack/client.browser']?.shareScope,
+ ),
+ ).toEqual(EXPECTED_SHARED_SCOPES);
+ });
});
From c535de5bfae45cbb261be395f866e38f2b01a80f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:36:18 +0000
Subject: [PATCH 182/324] refactor(rsc-mf): validate callback URL parse before
protocol checks
---
.../rsc-mf/remote/src/runtime/registerServerCallback.ts | 9 ++++++++-
.../rsc-mf/tests/registerServerCallback.test.ts | 3 +++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index f0dd2c43482e..e00a2a984828 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -26,7 +26,14 @@ const getHostActionId = (rawActionId: string, remoteAlias: string) => {
return `remote:${remoteAlias}:${normalizedRawActionId}`;
};
const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
- const url = new URL(remoteOrigin);
+ let url: URL;
+ try {
+ url = new URL(remoteOrigin);
+ } catch {
+ throw new Error(
+ `Remote action callback URL must be an absolute http(s) URL. Received: ${remoteOrigin}`,
+ );
+ }
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
throw new Error(
`Remote action callback URL must use http or https. Received protocol: ${url.protocol}`,
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index aac0f0041c5c..497bd11cbe07 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -269,6 +269,9 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(() =>
registerRemoteServerCallback('javascript:alert(1)', 'rscRemote'),
).toThrow('Remote action callback URL must use http or https');
+ expect(() =>
+ registerRemoteServerCallback('not-a-url', 'rscRemote'),
+ ).toThrow('Remote action callback URL must be an absolute http(s) URL');
expect(() =>
registerRemoteServerCallback(
'ftp://127.0.0.1:3008/server-component-root',
From a38a1d3407774fd7c3afe29a76ad9d115467ca33 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:39:10 +0000
Subject: [PATCH 183/324] refactor(rsc-mf): remove redundant remote bridge
import anchor
---
.../host/src/server-component-root/HostRemoteActionRunner.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
index a3d6047f21df..45ba50d30272 100644
--- a/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
+++ b/tests/integration/rsc-mf/host/src/server-component-root/HostRemoteActionRunner.tsx
@@ -9,9 +9,6 @@ import { defaultRemoteAction } from 'rscRemote/defaultAction';
import { nestedRemoteAction } from 'rscRemote/nestedActions';
export default function HostRemoteActionRunner() {
- // Keep this import in the client graph so federated RSC bridge IDs
- // can map back to a concrete remote module factory at runtime.
- void RemoteClientCounterBridge;
const [defaultResult, setDefaultResult] = useState('');
const [echoResult, setEchoResult] = useState('');
const [nestedResult, setNestedResult] = useState('');
From 7e0c483551b894d8efd3f9066f63d940401a5d96 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:40:38 +0000
Subject: [PATCH 184/324] refactor(rsc-mf): rely on default remote alias in
bootstrap
---
.../integration/rsc-mf/remote/src/runtime/initServerCallback.ts | 1 -
tests/integration/rsc-mf/tests/initServerCallback.test.ts | 2 --
2 files changed, 3 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index d8b383dc7695..a711a34c4f19 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -7,7 +7,6 @@ const bootstrapServerCallback = () => {
const actionPathname = window.location.pathname || '/';
registerRemoteServerCallback(
`${window.location.origin}${actionPathname}`,
- 'rscRemote',
);
},
);
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
index d0a89d120fd4..b6e5740b2a27 100644
--- a/tests/integration/rsc-mf/tests/initServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -66,7 +66,6 @@ describe('initServerCallback runtime bootstrap behavior', () => {
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
'http://127.0.0.1:3900/server-component-root',
- 'rscRemote',
);
});
@@ -88,7 +87,6 @@ describe('initServerCallback runtime bootstrap behavior', () => {
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
'http://127.0.0.1:4100/',
- 'rscRemote',
);
});
From d30b0e2b63dfd72d057076fd9711ca20a5ee5a04 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:44:10 +0000
Subject: [PATCH 185/324] test(rsc-mf): assert no chunkLoadingGlobal modern
config coupling
---
tests/integration/rsc-mf/tests/modernConfig.test.ts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernConfig.test.ts b/tests/integration/rsc-mf/tests/modernConfig.test.ts
index d56046dbe714..8fb549a09b33 100644
--- a/tests/integration/rsc-mf/tests/modernConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernConfig.test.ts
@@ -90,6 +90,7 @@ const createChainHarness = (target: string | string[]) => {
const conditionNames: string[] = [];
const moduleDirectories: string[] = [];
const publicPathCalls: string[] = [];
+ const chunkLoadingGlobalCalls: string[] = [];
const splitChunksCalls: unknown[] = [];
const targetCalls: string[] = [];
const rules: Array<{ name: string; test?: RegExp; layer?: string }> = [];
@@ -137,6 +138,10 @@ const createChainHarness = (target: string | string[]) => {
publicPathCalls.push(value);
return chain.output;
},
+ chunkLoadingGlobal: (value: string) => {
+ chunkLoadingGlobalCalls.push(value);
+ return chain.output;
+ },
},
optimization: {
splitChunks: (value: unknown) => {
@@ -173,6 +178,7 @@ const createChainHarness = (target: string | string[]) => {
conditionNames,
moduleDirectories,
publicPathCalls,
+ chunkLoadingGlobalCalls,
splitChunksCalls,
targetCalls,
rules,
@@ -193,6 +199,7 @@ describe('rsc-mf modern config contracts', () => {
enableAsyncEntry: false,
}),
);
+ expect(hostConfig.source).not.toHaveProperty('preEntry');
expect(hostConfig.plugins).toHaveLength(2);
});
@@ -270,6 +277,7 @@ describe('rsc-mf modern config contracts', () => {
harness.aliasMap.get('rsc-mf-react-server-dom-client-browser$'),
).toContain('react-server-dom-rspack');
expect(harness.publicPathCalls).toContain('http://127.0.0.1:3777/bundles/');
+ expect(harness.chunkLoadingGlobalCalls).toEqual([]);
expect(harness.rules).toEqual(
expect.arrayContaining([
expect.objectContaining({
@@ -294,6 +302,7 @@ describe('rsc-mf modern config contracts', () => {
expect(harness.targetCalls).toEqual([]);
expect(harness.splitChunksCalls).toEqual([false]);
expect(harness.publicPathCalls).toContain('http://127.0.0.1:3888/');
+ expect(harness.chunkLoadingGlobalCalls).toEqual([]);
expect(
harness.aliasMap.get('rsc-mf-react-server-dom-client-browser$'),
).toContain('react-server-dom-rspack');
From eab45df266905dde808c2be0cf4c500e44771d7a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:47:07 +0000
Subject: [PATCH 186/324] test(rsc-mf): assert modern plugin options and
preEntry absence
---
.../rsc-mf/tests/modernConfig.test.ts | 28 +++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/modernConfig.test.ts b/tests/integration/rsc-mf/tests/modernConfig.test.ts
index 8fb549a09b33..faf581c7e20b 100644
--- a/tests/integration/rsc-mf/tests/modernConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernConfig.test.ts
@@ -45,7 +45,10 @@ const loadHostConfig = () =>
defineConfig: (config: unknown) => config,
}));
jest.doMock('@module-federation/modern-js-v3', () => ({
- moduleFederationPlugin: () => ({ name: 'mf-plugin-mock' }),
+ moduleFederationPlugin: (options: unknown) => ({
+ name: 'mf-plugin-mock',
+ options,
+ }),
}));
let config: any;
@@ -74,7 +77,10 @@ const loadRemoteConfig = ({
defineConfig: (config: unknown) => config,
}));
jest.doMock('@module-federation/modern-js-v3', () => ({
- moduleFederationPlugin: () => ({ name: 'mf-plugin-mock' }),
+ moduleFederationPlugin: (options: unknown) => ({
+ name: 'mf-plugin-mock',
+ options,
+ }),
}));
let config: any;
@@ -201,6 +207,15 @@ describe('rsc-mf modern config contracts', () => {
);
expect(hostConfig.source).not.toHaveProperty('preEntry');
expect(hostConfig.plugins).toHaveLength(2);
+ expect(hostConfig.plugins).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({ name: 'app-tools-mock' }),
+ expect.objectContaining({
+ name: 'mf-plugin-mock',
+ options: expect.objectContaining({ ssr: true }),
+ }),
+ ]),
+ );
});
it('applies host async-node bundler behavior for node targets', () => {
@@ -241,6 +256,15 @@ describe('rsc-mf modern config contracts', () => {
enableAsyncEntry: false,
}),
);
+ expect(remoteConfig.plugins).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({ name: 'app-tools-mock' }),
+ expect.objectContaining({
+ name: 'mf-plugin-mock',
+ options: expect.objectContaining({ ssr: true }),
+ }),
+ ]),
+ );
});
it('enables remote ssr mode when explicit PORT is set', () => {
From 7dc783c16c92b39d74f22cd2d285380319b26889 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:51:46 +0000
Subject: [PATCH 187/324] refactor(rsc-mf): retry callback bootstrap on
transient failures
---
.../remote/src/runtime/initServerCallback.ts | 10 +++
.../rsc-mf/tests/initServerCallback.test.ts | 71 +++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index a711a34c4f19..baa4888dac17 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,4 +1,6 @@
let callbackBootstrapPromise: Promise | undefined;
+const MAX_CALLBACK_BOOTSTRAP_RETRIES = 2;
+let callbackBootstrapRetryCount = 0;
const bootstrapServerCallback = () => {
if (!callbackBootstrapPromise) {
@@ -8,10 +10,18 @@ const bootstrapServerCallback = () => {
registerRemoteServerCallback(
`${window.location.origin}${actionPathname}`,
);
+ callbackBootstrapRetryCount = 0;
},
);
callbackBootstrapPromise.catch(() => {
callbackBootstrapPromise = undefined;
+ if (callbackBootstrapRetryCount >= MAX_CALLBACK_BOOTSTRAP_RETRIES) {
+ return;
+ }
+ callbackBootstrapRetryCount += 1;
+ queueMicrotask(() => {
+ void bootstrapServerCallback();
+ });
});
}
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
index b6e5740b2a27..9da71165ea7a 100644
--- a/tests/integration/rsc-mf/tests/initServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -6,6 +6,11 @@ const flushMicrotasks = async () => {
await Promise.resolve();
await Promise.resolve();
};
+const flushRepeatedMicrotasks = async (count: number) => {
+ for (let index = 0; index < count; index += 1) {
+ await Promise.resolve();
+ }
+};
describe('initServerCallback runtime bootstrap behavior', () => {
const originalWindow = (globalThis as { window?: unknown }).window;
@@ -109,4 +114,70 @@ describe('initServerCallback runtime bootstrap behavior', () => {
expect(getRegisterModuleLoadCount()).toBe(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
});
+
+ it('retries callback bootstrap after transient registration failure', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4500',
+ pathname: '/server-component-root',
+ },
+ };
+
+ const transientError = new Error('transient-bootstrap-failure');
+ const mockRegisterRemoteServerCallback = jest
+ .fn()
+ .mockImplementationOnce(() => {
+ throw transientError;
+ })
+ .mockImplementation(() => undefined);
+ let registerModuleLoadCount = 0;
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => {
+ registerModuleLoadCount += 1;
+ return {
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ };
+ });
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushRepeatedMicrotasks(20);
+
+ expect(registerModuleLoadCount).toBe(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(2);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:4500/server-component-root',
+ );
+ expect(mockRegisterRemoteServerCallback).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:4500/server-component-root',
+ );
+ });
+
+ it('caps callback bootstrap retries after repeated failures', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4700',
+ pathname: '/server-component-root',
+ },
+ };
+
+ const mockRegisterRemoteServerCallback = jest.fn(() => {
+ throw new Error('persistent-bootstrap-failure');
+ });
+ let registerModuleLoadCount = 0;
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => {
+ registerModuleLoadCount += 1;
+ return {
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ };
+ });
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushRepeatedMicrotasks(40);
+
+ expect(registerModuleLoadCount).toBe(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(3);
+ });
});
From 8830523bdce66fef49897a022b4b18abdcb48633 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:54:40 +0000
Subject: [PATCH 188/324] refactor(rsc-mf): simplify callback keying and cover
default alias
---
.../src/runtime/registerServerCallback.ts | 10 +++++-----
.../tests/registerServerCallback.test.ts | 20 +++++++++++++++++++
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index e00a2a984828..83e6c1ea9baf 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -7,6 +7,7 @@ import {
let registeredCallbackKey = '';
const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
+const DEFAULT_REMOTE_ALIAS = 'rscRemote';
const getNormalizedRawActionId = (rawActionId: string) => {
const normalizedRawActionId = rawActionId.trim();
if (!normalizedRawActionId || /\s/.test(normalizedRawActionId)) {
@@ -48,10 +49,12 @@ const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
url.hash = '';
return url.toString();
};
+const getCallbackKey = (remoteAlias: string, remoteActionUrl: string) =>
+ `${remoteAlias}::${remoteActionUrl}`;
export function registerRemoteServerCallback(
remoteOrigin: string,
- remoteAlias = 'rscRemote',
+ remoteAlias = DEFAULT_REMOTE_ALIAS,
) {
const normalizedRemoteOrigin = remoteOrigin.trim();
if (!normalizedRemoteOrigin) {
@@ -68,10 +71,7 @@ export function registerRemoteServerCallback(
);
}
const remoteActionUrl = getNormalizedRemoteActionUrl(normalizedRemoteOrigin);
- const callbackKey = JSON.stringify({
- remoteAlias: normalizedRemoteAlias,
- remoteActionUrl,
- });
+ const callbackKey = getCallbackKey(normalizedRemoteAlias, remoteActionUrl);
if (registeredCallbackKey === callbackKey) {
return;
}
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 497bd11cbe07..d2868b863fcb 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -86,6 +86,23 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('uses default alias when remote alias is omitted', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+
+ const callback = getRegisteredCallback();
+ await callback('default-alias-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:default-alias-action',
+ }),
+ }),
+ );
+ });
+
it('normalizes action ids and rejects whitespace-delimited ids', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
@@ -272,6 +289,9 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(() =>
registerRemoteServerCallback('not-a-url', 'rscRemote'),
).toThrow('Remote action callback URL must be an absolute http(s) URL');
+ expect(() =>
+ registerRemoteServerCallback('/server-component-root', 'rscRemote'),
+ ).toThrow('Remote action callback URL must be an absolute http(s) URL');
expect(() =>
registerRemoteServerCallback(
'ftp://127.0.0.1:3008/server-component-root',
From 0e4dd7af1ebf084b317ae51af66f9e9e0dadebae Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 06:57:43 +0000
Subject: [PATCH 189/324] test(rsc-mf): cover host web chain and remote port
precedence
---
.../rsc-mf/tests/modernConfig.test.ts | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernConfig.test.ts b/tests/integration/rsc-mf/tests/modernConfig.test.ts
index faf581c7e20b..c79faab47621 100644
--- a/tests/integration/rsc-mf/tests/modernConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernConfig.test.ts
@@ -234,6 +234,20 @@ describe('rsc-mf modern config contracts', () => {
]);
});
+ it('keeps host web-target bundler chain free of node-only aliases', () => {
+ const hostConfig = loadHostConfig();
+ const harness = createChainHarness('web');
+ hostConfig.tools?.bundlerChain?.(harness.chain as any);
+
+ expect(harness.targetCalls).toEqual([]);
+ expect(harness.aliasMap.has('server-only$')).toBe(false);
+ expect(harness.conditionNames).toEqual([]);
+ expect(harness.moduleDirectories).toEqual([
+ path.resolve(__dirname, '../host/node_modules'),
+ 'node_modules',
+ ]);
+ });
+
it('configures remote port-driven server and asset settings', () => {
const remoteConfig = loadRemoteConfig({
remotePort: '3991',
@@ -279,6 +293,24 @@ describe('rsc-mf modern config contracts', () => {
);
});
+ it('keeps remote port precedence deterministic when PORT and remote port are both set', () => {
+ const remoteConfig = loadRemoteConfig({
+ port: '4550',
+ remotePort: '3881',
+ });
+ expect(remoteConfig.server).toEqual(
+ expect.objectContaining({
+ ssr: true,
+ port: 3881,
+ }),
+ );
+ expect(remoteConfig.output).toEqual(
+ expect.objectContaining({
+ assetPrefix: 'http://127.0.0.1:3881',
+ }),
+ );
+ });
+
it('applies remote async-node + layer settings for node targets', () => {
const remoteConfig = loadRemoteConfig({
remotePort: '3777',
From c6dc28553166ac7ff58966c333d160b58b1b6939 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:00:54 +0000
Subject: [PATCH 190/324] refactor(rsc-mf): fallback bootstrap retries without
queueMicrotask
---
.../remote/src/runtime/initServerCallback.ts | 10 ++++-
.../rsc-mf/tests/initServerCallback.test.ts | 44 +++++++++++++++++++
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index baa4888dac17..34f1a889aa00 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,6 +1,14 @@
let callbackBootstrapPromise: Promise | undefined;
const MAX_CALLBACK_BOOTSTRAP_RETRIES = 2;
let callbackBootstrapRetryCount = 0;
+const scheduleRetryTask = (task: () => void) => {
+ if (typeof queueMicrotask === 'function') {
+ queueMicrotask(task);
+ return;
+ }
+
+ void Promise.resolve().then(task);
+};
const bootstrapServerCallback = () => {
if (!callbackBootstrapPromise) {
@@ -19,7 +27,7 @@ const bootstrapServerCallback = () => {
return;
}
callbackBootstrapRetryCount += 1;
- queueMicrotask(() => {
+ scheduleRetryTask(() => {
void bootstrapServerCallback();
});
});
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
index 9da71165ea7a..9bab9c18e84c 100644
--- a/tests/integration/rsc-mf/tests/initServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -14,6 +14,14 @@ const flushRepeatedMicrotasks = async (count: number) => {
describe('initServerCallback runtime bootstrap behavior', () => {
const originalWindow = (globalThis as { window?: unknown }).window;
+ const originalQueueMicrotask = globalThis.queueMicrotask;
+ const overrideQueueMicrotask = (value: typeof queueMicrotask | undefined) => {
+ Object.defineProperty(globalThis, 'queueMicrotask', {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ };
const setupRegisterCallbackMock = () => {
const mockRegisterRemoteServerCallback = jest.fn();
let registerModuleLoadCount = 0;
@@ -32,6 +40,7 @@ describe('initServerCallback runtime bootstrap behavior', () => {
};
afterEach(() => {
+ overrideQueueMicrotask(originalQueueMicrotask);
if (typeof originalWindow === 'undefined') {
delete (globalThis as { window?: unknown }).window;
return;
@@ -180,4 +189,39 @@ describe('initServerCallback runtime bootstrap behavior', () => {
expect(registerModuleLoadCount).toBe(1);
expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(3);
});
+
+ it('falls back to promise microtask retry when queueMicrotask is unavailable', async () => {
+ jest.resetModules();
+ overrideQueueMicrotask(undefined);
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4800',
+ pathname: '/server-component-root',
+ },
+ };
+
+ const mockRegisterRemoteServerCallback = jest
+ .fn()
+ .mockImplementationOnce(() => {
+ throw new Error('bootstrap-failure-without-queueMicrotask');
+ })
+ .mockImplementation(() => undefined);
+
+ jest.doMock(REGISTER_SERVER_CALLBACK_MODULE, () => ({
+ registerRemoteServerCallback: mockRegisterRemoteServerCallback,
+ }));
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushRepeatedMicrotasks(30);
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(2);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:4800/server-component-root',
+ );
+ expect(mockRegisterRemoteServerCallback).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:4800/server-component-root',
+ );
+ });
});
From cfbc77e19cf5263877023f9c0cc5eb97a00f2689 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:03:58 +0000
Subject: [PATCH 191/324] test(rsc-mf): assert no failed host or remote
responses
---
tests/integration/rsc-mf/tests/index.test.ts | 29 ++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index 40b43a4c6f01..dabef18b887b 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -46,6 +46,11 @@ interface TestContext {
page: Page;
actionRequestIds?: string[];
}
+interface FailedRequestRecord {
+ url: string;
+ method: string;
+ status: number;
+}
async function waitForActionRequestCount({
actionRequestIds,
@@ -357,6 +362,7 @@ function runTests({ mode }: TestConfig) {
const actionRequestIds: string[] = [];
const actionRequestAcceptHeaders: string[] = [];
const registerCallbackExposeRequestUrls: string[] = [];
+ const failedNetworkRequests: FailedRequestRecord[] = [];
if (skipForLowerNodeVersion()) {
return;
@@ -421,6 +427,25 @@ function runTests({ mode }: TestConfig) {
actionRequestIds.push(headers['x-rsc-action']);
actionRequestAcceptHeaders.push(headers.accept || '');
});
+
+ page.on('response', response => {
+ const status = response.status();
+ if (status < 400) {
+ return;
+ }
+ const url = response.url();
+ const request = response.request();
+ const hostOrigin = `http://127.0.0.1:${hostPort}`;
+ const remoteOrigin = `http://127.0.0.1:${remotePort}`;
+ if (!url.startsWith(hostOrigin) && !url.startsWith(remoteOrigin)) {
+ return;
+ }
+ failedNetworkRequests.push({
+ url,
+ method: request.method(),
+ status,
+ });
+ });
});
afterAll(async () => {
@@ -536,6 +561,10 @@ function runTests({ mode }: TestConfig) {
it('should have no browser runtime errors', () => {
expect(runtimeErrors).toEqual([]);
});
+
+ it('should have no failed host or remote network responses', () => {
+ expect(failedNetworkRequests).toEqual([]);
+ });
});
}
From e9ca0b6522247017814ecf97c8d3bddb5ef7ec3a Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:07:07 +0000
Subject: [PATCH 192/324] refactor(rsc-mf): normalize callback action pathname
before registration
---
.../remote/src/runtime/initServerCallback.ts | 11 +++++-
.../rsc-mf/tests/initServerCallback.test.ts | 38 +++++++++++++++++++
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
index 34f1a889aa00..8fde3f9bd640 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/initServerCallback.ts
@@ -1,6 +1,13 @@
let callbackBootstrapPromise: Promise | undefined;
const MAX_CALLBACK_BOOTSTRAP_RETRIES = 2;
let callbackBootstrapRetryCount = 0;
+const getNormalizedActionPathname = (pathname?: string) => {
+ const trimmedPathname = pathname?.trim() || '/';
+ if (trimmedPathname.startsWith('/')) {
+ return trimmedPathname;
+ }
+ return `/${trimmedPathname}`;
+};
const scheduleRetryTask = (task: () => void) => {
if (typeof queueMicrotask === 'function') {
queueMicrotask(task);
@@ -14,7 +21,9 @@ const bootstrapServerCallback = () => {
if (!callbackBootstrapPromise) {
callbackBootstrapPromise = import('./registerServerCallback').then(
({ registerRemoteServerCallback }) => {
- const actionPathname = window.location.pathname || '/';
+ const actionPathname = getNormalizedActionPathname(
+ window.location.pathname,
+ );
registerRemoteServerCallback(
`${window.location.origin}${actionPathname}`,
);
diff --git a/tests/integration/rsc-mf/tests/initServerCallback.test.ts b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
index 9bab9c18e84c..28ef7bab28e4 100644
--- a/tests/integration/rsc-mf/tests/initServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/initServerCallback.test.ts
@@ -104,6 +104,44 @@ describe('initServerCallback runtime bootstrap behavior', () => {
);
});
+ it('normalizes non-slash pathnames before callback registration', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4200',
+ pathname: 'server-component-root',
+ },
+ };
+ const { mockRegisterRemoteServerCallback } = setupRegisterCallbackMock();
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
+ 'http://127.0.0.1:4200/server-component-root',
+ );
+ });
+
+ it('normalizes whitespace-only pathnames to root', async () => {
+ jest.resetModules();
+ (globalThis as { window?: unknown }).window = {
+ location: {
+ origin: 'http://127.0.0.1:4250',
+ pathname: ' ',
+ },
+ };
+ const { mockRegisterRemoteServerCallback } = setupRegisterCallbackMock();
+
+ await import(INIT_SERVER_CALLBACK_MODULE);
+ await flushMicrotasks();
+
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledTimes(1);
+ expect(mockRegisterRemoteServerCallback).toHaveBeenCalledWith(
+ 'http://127.0.0.1:4250/',
+ );
+ });
+
it('keeps bootstrap side effect memoized across repeated imports', async () => {
jest.resetModules();
(globalThis as { window?: unknown }).window = {
From 396a96d5ce58eb3a00b648da4b69642d5bf9c396 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:10:12 +0000
Subject: [PATCH 193/324] test(rsc-mf): assert no failed browser requests in
dev and build
---
tests/integration/rsc-mf/tests/index.test.ts | 24 ++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index dabef18b887b..f98704cfe6f5 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -51,6 +51,11 @@ interface FailedRequestRecord {
method: string;
status: number;
}
+interface FailedBrowserRequestRecord {
+ url: string;
+ method: string;
+ failureText: string;
+}
async function waitForActionRequestCount({
actionRequestIds,
@@ -363,6 +368,7 @@ function runTests({ mode }: TestConfig) {
const actionRequestAcceptHeaders: string[] = [];
const registerCallbackExposeRequestUrls: string[] = [];
const failedNetworkRequests: FailedRequestRecord[] = [];
+ const failedBrowserRequests: FailedBrowserRequestRecord[] = [];
if (skipForLowerNodeVersion()) {
return;
@@ -446,6 +452,20 @@ function runTests({ mode }: TestConfig) {
status,
});
});
+
+ page.on('requestfailed', request => {
+ const url = request.url();
+ const hostOrigin = `http://127.0.0.1:${hostPort}`;
+ const remoteOrigin = `http://127.0.0.1:${remotePort}`;
+ if (!url.startsWith(hostOrigin) && !url.startsWith(remoteOrigin)) {
+ return;
+ }
+ failedBrowserRequests.push({
+ url,
+ method: request.method(),
+ failureText: request.failure()?.errorText || 'unknown',
+ });
+ });
});
afterAll(async () => {
@@ -565,6 +585,10 @@ function runTests({ mode }: TestConfig) {
it('should have no failed host or remote network responses', () => {
expect(failedNetworkRequests).toEqual([]);
});
+
+ it('should have no failed host or remote browser requests', () => {
+ expect(failedBrowserRequests).toEqual([]);
+ });
});
}
From 4af5b4ee3369fe48b1de42ced208145859a0177b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:13:17 +0000
Subject: [PATCH 194/324] refactor(rsc-mf): fail fast on non-ok callback
responses
---
.../src/runtime/registerServerCallback.ts | 9 +++++++--
.../tests/registerServerCallback.test.ts | 18 ++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index 83e6c1ea9baf..25880465a777 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -79,7 +79,7 @@ export function registerRemoteServerCallback(
setServerCallback(async (id: string, args: unknown[]) => {
const hostActionId = getHostActionId(id, normalizedRemoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
- const response = fetch(remoteActionUrl, {
+ const response = await fetch(remoteActionUrl, {
method: 'POST',
headers: {
Accept: 'text/x-component',
@@ -87,7 +87,12 @@ export function registerRemoteServerCallback(
},
body: await encodeReply(args, { temporaryReferences }),
});
- return createFromFetch(response, { temporaryReferences });
+ if (!response.ok) {
+ throw new Error(
+ `Remote action callback request failed with status ${response.status} ${response.statusText} (${remoteActionUrl}).`,
+ );
+ }
+ return createFromFetch(Promise.resolve(response), { temporaryReferences });
});
registeredCallbackKey = callbackKey;
}
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index d2868b863fcb..4e1af81c2286 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -86,6 +86,24 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('throws when callback fetch returns non-ok response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest.fn(async () => {
+ return {
+ ok: false,
+ status: 503,
+ statusText: 'Service Unavailable',
+ } as Response;
+ });
+
+ const callback = getRegisteredCallback();
+ await expect(callback('fetch-failure-action', ['arg-1'])).rejects.toThrow(
+ 'Remote action callback request failed with status 503 Service Unavailable (http://127.0.0.1:3008/server-component-root).',
+ );
+ expect(mockCreateFromFetch).not.toHaveBeenCalled();
+ });
+
it('uses default alias when remote alias is omitted', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From 9fd29b5b777d2d6bc8fdd1abbe68f206fceb4633 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:19:42 +0000
Subject: [PATCH 195/324] refactor(rsc-mf): retry callback fetch once before
failing
---
.../src/runtime/registerServerCallback.ts | 53 +++++++++++++++----
.../tests/registerServerCallback.test.ts | 25 +++++++++
2 files changed, 68 insertions(+), 10 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index 25880465a777..04d02cf41e0a 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -8,6 +8,7 @@ import {
let registeredCallbackKey = '';
const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
const DEFAULT_REMOTE_ALIAS = 'rscRemote';
+const MAX_CALLBACK_FETCH_RETRIES = 1;
const getNormalizedRawActionId = (rawActionId: string) => {
const normalizedRawActionId = rawActionId.trim();
if (!normalizedRawActionId || /\s/.test(normalizedRawActionId)) {
@@ -79,20 +80,52 @@ export function registerRemoteServerCallback(
setServerCallback(async (id: string, args: unknown[]) => {
const hostActionId = getHostActionId(id, normalizedRemoteAlias);
const temporaryReferences = createTemporaryReferenceSet();
- const response = await fetch(remoteActionUrl, {
- method: 'POST',
- headers: {
- Accept: 'text/x-component',
- 'x-rsc-action': hostActionId,
- },
- body: await encodeReply(args, { temporaryReferences }),
- });
- if (!response.ok) {
+ const requestBody = await encodeReply(args, { temporaryReferences });
+ let response: Response | undefined;
+ let lastFetchError: unknown;
+
+ for (let attempt = 0; attempt <= MAX_CALLBACK_FETCH_RETRIES; attempt += 1) {
+ try {
+ response = await fetch(remoteActionUrl, {
+ method: 'POST',
+ headers: {
+ Accept: 'text/x-component',
+ 'x-rsc-action': hostActionId,
+ },
+ body: requestBody,
+ });
+ } catch (error) {
+ lastFetchError = error;
+ if (attempt < MAX_CALLBACK_FETCH_RETRIES) {
+ continue;
+ }
+ }
+
+ if (!response) {
+ continue;
+ }
+
+ if (response.ok) {
+ return createFromFetch(Promise.resolve(response), {
+ temporaryReferences,
+ });
+ }
+
+ const shouldRetry =
+ response.status >= 500 && attempt < MAX_CALLBACK_FETCH_RETRIES;
+ if (shouldRetry) {
+ response = undefined;
+ continue;
+ }
+
throw new Error(
`Remote action callback request failed with status ${response.status} ${response.statusText} (${remoteActionUrl}).`,
);
}
- return createFromFetch(Promise.resolve(response), { temporaryReferences });
+
+ throw new Error(
+ `Remote action callback request failed due to network error (${remoteActionUrl}): ${String(lastFetchError)}`,
+ );
});
registeredCallbackKey = callbackKey;
}
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 4e1af81c2286..65dda7a16415 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -101,9 +101,34 @@ describe('registerRemoteServerCallback runtime behavior', () => {
await expect(callback('fetch-failure-action', ['arg-1'])).rejects.toThrow(
'Remote action callback request failed with status 503 Service Unavailable (http://127.0.0.1:3008/server-component-root).',
);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
expect(mockCreateFromFetch).not.toHaveBeenCalled();
});
+ it('retries once when callback fetch throws and succeeds on retry', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+
+ const transientNetworkError = new Error('network-down-on-first-attempt');
+ global.fetch = jest
+ .fn()
+ .mockRejectedValueOnce(transientNetworkError)
+ .mockResolvedValue({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ } as Response);
+
+ const callback = getRegisteredCallback();
+ await expect(callback('fetch-retry-action', ['arg-1'])).resolves.toEqual(
+ expect.objectContaining({
+ type: 'decoded-rsc-response',
+ }),
+ );
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
it('uses default alias when remote alias is omitted', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From 269e5a419c279e2e22ff03b2ab48b377e46835f3 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:23:13 +0000
Subject: [PATCH 196/324] test(rsc-mf): verify retry policy for callback 5xx
and 4xx
---
.../tests/registerServerCallback.test.ts | 49 +++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 65dda7a16415..f6647a584068 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -105,6 +105,55 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).not.toHaveBeenCalled();
});
+ it('retries once when callback fetch returns retryable 5xx response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest
+ .fn()
+ .mockResolvedValueOnce({
+ ok: false,
+ status: 503,
+ statusText: 'Service Unavailable',
+ } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ } as Response);
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-retry-5xx-action', ['arg-1']),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ type: 'decoded-rsc-response',
+ }),
+ );
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
+ it('does not retry callback fetch for non-retryable 4xx response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest.fn(async () => {
+ return {
+ ok: false,
+ status: 400,
+ statusText: 'Bad Request',
+ } as Response;
+ });
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-non-retryable-action', ['arg-1']),
+ ).rejects.toThrow(
+ 'Remote action callback request failed with status 400 Bad Request (http://127.0.0.1:3008/server-component-root).',
+ );
+ expect(global.fetch).toHaveBeenCalledTimes(1);
+ expect(mockCreateFromFetch).not.toHaveBeenCalled();
+ });
+
it('retries once when callback fetch throws and succeeds on retry', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From c734397867e7e9e5ef8e4a2c72695e4d82fb149f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:26:22 +0000
Subject: [PATCH 197/324] test(rsc-mf): assert callback retry request body
reuse
---
.../rsc-mf/tests/registerServerCallback.test.ts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index f6647a584068..668523857130 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -129,7 +129,13 @@ describe('registerRemoteServerCallback runtime behavior', () => {
type: 'decoded-rsc-response',
}),
);
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
@@ -150,6 +156,8 @@ describe('registerRemoteServerCallback runtime behavior', () => {
).rejects.toThrow(
'Remote action callback request failed with status 400 Bad Request (http://127.0.0.1:3008/server-component-root).',
);
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
expect(global.fetch).toHaveBeenCalledTimes(1);
expect(mockCreateFromFetch).not.toHaveBeenCalled();
});
@@ -174,7 +182,13 @@ describe('registerRemoteServerCallback runtime behavior', () => {
type: 'decoded-rsc-response',
}),
);
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
From 0f92cc2dc17b1cb2658af9b4c1795da9995e6e8b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:45:08 +0000
Subject: [PATCH 198/324] refactor(rsc-mf): extract callback expose wiring
helper
---
.../rsc-mf/remote/module-federation.config.ts | 92 +--------------
.../src/runtime/createRscExposeDefinitions.ts | 111 ++++++++++++++++++
.../tests/createRscExposeDefinitions.test.ts | 105 +++++++++++++++++
3 files changed, 218 insertions(+), 90 deletions(-)
create mode 100644 tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
create mode 100644 tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index c28fbb37f8a8..a35e782553f7 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -1,5 +1,6 @@
import path from 'path';
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
+import { createRscExposeDefinitions } from './src/runtime/createRscExposeDefinitions';
const LAYERS = {
ssr: 'server-side-rendering',
@@ -14,31 +15,6 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
-const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
-const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
-if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
- throw new Error(
- `Callback bootstrap import must stay in runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
- );
-}
-if (!/\.[tj]sx?$/.test(CALLBACK_BOOTSTRAP_IMPORT)) {
- throw new Error(
- `Callback bootstrap import must use explicit source extension for deterministic resolution. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
- );
-}
-if (
- CALLBACK_BOOTSTRAP_IMPORT.includes('..') ||
- CALLBACK_BOOTSTRAP_IMPORT.includes('\\')
-) {
- throw new Error(
- `Callback bootstrap import must not contain traversal or Windows separators. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
- );
-}
-const createRscExpose = (importPath: string) =>
- ({
- import: [CALLBACK_BOOTSTRAP_IMPORT, importPath],
- layer: LAYERS.rsc,
- }) as any;
const remoteExposeImports: Record = {
'./RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
'./RemoteClientBadge': './src/components/RemoteClientBadge.tsx',
@@ -54,65 +30,6 @@ const remoteExposeImports: Record = {
'./actionBundle': './src/components/actionBundle.ts',
'./infoBundle': './src/components/infoBundle.ts',
};
-const invalidExposeKeys = Object.keys(remoteExposeImports).filter(
- exposeKey => !exposeKey.startsWith('./'),
-);
-if (invalidExposeKeys.length > 0) {
- throw new Error(
- `Remote expose keys must be module-federation paths starting with "./". Invalid keys: ${invalidExposeKeys.join(', ')}`,
- );
-}
-const COMPONENT_EXPOSE_PREFIX = './src/components/';
-const nonComponentExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !importPath.startsWith(COMPONENT_EXPOSE_PREFIX),
-);
-if (nonComponentExposeEntries.length > 0) {
- throw new Error(
- `Remote exposes must point to component userland modules (${COMPONENT_EXPOSE_PREFIX}). Invalid entries: ${nonComponentExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
- );
-}
-const nonTypeScriptExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !/\.[tj]sx?$/.test(importPath),
-);
-if (nonTypeScriptExposeEntries.length > 0) {
- throw new Error(
- `Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution. Invalid entries: ${nonTypeScriptExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
- );
-}
-const parentTraversalExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => importPath.includes('..'),
-);
-if (parentTraversalExposeEntries.length > 0) {
- throw new Error(
- `Remote expose imports must not contain parent directory traversal segments. Invalid entries: ${parentTraversalExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
- );
-}
-const nonPosixExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => importPath.includes('\\'),
-);
-if (nonPosixExposeEntries.length > 0) {
- throw new Error(
- `Remote expose imports must use POSIX separators for deterministic module ids. Invalid entries: ${nonPosixExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
- );
-}
-const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
-);
-if (callbackExposeEntries.length > 0) {
- throw new Error(
- `Callback bootstrap module (${CALLBACK_BOOTSTRAP_IMPORT}) must remain internal-only and cannot be exposed. Invalid entries: ${callbackExposeEntries
- .map(([exposeKey]) => exposeKey)
- .join(', ')}`,
- );
-}
const sharedByScope = [
{
@@ -205,12 +122,7 @@ export default createModuleFederationConfig({
filePath: 'static',
},
filename: 'static/remoteEntry.js',
- exposes: Object.fromEntries(
- Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
- exposeKey,
- createRscExpose(importPath),
- ]),
- ) as any,
+ exposes: createRscExposeDefinitions(remoteExposeImports) as any,
shared: sharedByScope as any,
dts: false,
experiments: {
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
new file mode 100644
index 000000000000..06931d78bf30
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -0,0 +1,111 @@
+const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
+const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
+const COMPONENT_EXPOSE_PREFIX = './src/components/';
+
+if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
+ throw new Error(
+ `Callback bootstrap import must stay in runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
+if (!/\.[tj]sx?$/.test(CALLBACK_BOOTSTRAP_IMPORT)) {
+ throw new Error(
+ `Callback bootstrap import must use explicit source extension for deterministic resolution. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
+if (
+ CALLBACK_BOOTSTRAP_IMPORT.includes('..') ||
+ CALLBACK_BOOTSTRAP_IMPORT.includes('\\')
+) {
+ throw new Error(
+ `Callback bootstrap import must not contain traversal or Windows separators. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ );
+}
+
+const createRscExpose = (importPath: string) =>
+ ({
+ import: [CALLBACK_BOOTSTRAP_IMPORT, importPath],
+ layer: 'react-server-components',
+ }) as const;
+
+const assertValidExposeConfig = (
+ remoteExposeImports: Record,
+) => {
+ const invalidExposeKeys = Object.keys(remoteExposeImports).filter(
+ exposeKey => !exposeKey.startsWith('./'),
+ );
+ if (invalidExposeKeys.length > 0) {
+ throw new Error(
+ `Remote expose keys must be module-federation paths starting with "./". Invalid keys: ${invalidExposeKeys.join(', ')}`,
+ );
+ }
+
+ const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
+ );
+ if (callbackExposeEntries.length > 0) {
+ throw new Error(
+ `Callback bootstrap module (${CALLBACK_BOOTSTRAP_IMPORT}) must remain internal-only and cannot be exposed. Invalid entries: ${callbackExposeEntries
+ .map(([exposeKey]) => exposeKey)
+ .join(', ')}`,
+ );
+ }
+
+ const nonPosixExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => importPath.includes('\\'),
+ );
+ if (nonPosixExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must use POSIX separators for deterministic module ids. Invalid entries: ${nonPosixExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+ }
+
+ const nonComponentExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !importPath.startsWith(COMPONENT_EXPOSE_PREFIX),
+ );
+ if (nonComponentExposeEntries.length > 0) {
+ throw new Error(
+ `Remote exposes must point to component userland modules (${COMPONENT_EXPOSE_PREFIX}). Invalid entries: ${nonComponentExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+ }
+
+ const nonTypeScriptExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !/\.[tj]sx?$/.test(importPath),
+ );
+ if (nonTypeScriptExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution. Invalid entries: ${nonTypeScriptExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+ }
+
+ const parentTraversalExposeEntries = Object.entries(
+ remoteExposeImports,
+ ).filter(([, importPath]) => importPath.includes('..'));
+ if (parentTraversalExposeEntries.length > 0) {
+ throw new Error(
+ `Remote expose imports must not contain parent directory traversal segments. Invalid entries: ${parentTraversalExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+ }
+};
+
+export const createRscExposeDefinitions = (
+ remoteExposeImports: Record,
+) => {
+ assertValidExposeConfig(remoteExposeImports);
+
+ return Object.fromEntries(
+ Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
+ exposeKey,
+ createRscExpose(importPath),
+ ]),
+ );
+};
+
+export const CALLBACK_BOOTSTRAP_MODULE = CALLBACK_BOOTSTRAP_IMPORT;
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
new file mode 100644
index 000000000000..9e20301d20eb
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -0,0 +1,105 @@
+const CREATE_RSC_EXPOSE_DEFINITIONS_MODULE =
+ '../remote/src/runtime/createRscExposeDefinitions';
+
+const loadCreateRscExposeDefinitions = () => {
+ let moduleExports: any;
+ jest.isolateModules(() => {
+ moduleExports = require(CREATE_RSC_EXPOSE_DEFINITIONS_MODULE);
+ });
+ return moduleExports as {
+ createRscExposeDefinitions: (
+ remoteExposeImports: Record,
+ ) => Record;
+ CALLBACK_BOOTSTRAP_MODULE: string;
+ };
+};
+
+describe('createRscExposeDefinitions', () => {
+ it('creates callback-bootstrapped rsc expose definitions', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ const exposeDefinitions = createRscExposeDefinitions({
+ './RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
+ './actions': './src/components/actions.ts',
+ });
+
+ expect(exposeDefinitions).toEqual({
+ './RemoteClientCounter': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/RemoteClientCounter.tsx',
+ ],
+ layer: 'react-server-components',
+ },
+ './actions': {
+ import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/actions.ts'],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
+ it('rejects expose keys that do not start with module-federation prefix', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ RemoteClientCounter: './src/components/RemoteClientCounter.tsx',
+ }),
+ ).toThrow(
+ 'Remote expose keys must be module-federation paths starting with "./"',
+ );
+ });
+
+ it('rejects expose imports outside component userland namespace', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './src/runtime/helper.ts',
+ }),
+ ).toThrow(
+ 'Remote exposes must point to component userland modules (./src/components/)',
+ );
+ });
+
+ it('rejects expose imports without explicit source extension', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './src/components/RemoteClientCounter',
+ }),
+ ).toThrow(
+ 'Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution.',
+ );
+ });
+
+ it('rejects expose imports with parent traversal segments', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './src/components/../runtime/helper.ts',
+ }),
+ ).toThrow(
+ 'Remote expose imports must not contain parent directory traversal segments.',
+ );
+ });
+
+ it('rejects expose imports with windows separators', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './src/components\\RemoteClientCounter.tsx',
+ }),
+ ).toThrow(
+ 'Remote expose imports must use POSIX separators for deterministic module ids.',
+ );
+ });
+
+ it('rejects exposing callback bootstrap module directly', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './callback': CALLBACK_BOOTSTRAP_MODULE,
+ }),
+ ).toThrow('must remain internal-only and cannot be exposed');
+ });
+});
From 3a8376e251df73001046eaa91932480796cae8c4 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:48:50 +0000
Subject: [PATCH 199/324] refactor(rsc-mf): allow broader userland expose
module paths
---
.../src/runtime/createRscExposeDefinitions.ts | 22 ++++++++++++++-----
.../tests/createRscExposeDefinitions.test.ts | 13 +++++++++--
.../tests/moduleFederationConfig.test.ts | 3 ++-
3 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index 06931d78bf30..cf41dbb5e352 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -1,6 +1,6 @@
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
-const COMPONENT_EXPOSE_PREFIX = './src/components/';
+const USERLAND_EXPOSE_PREFIX = './src/';
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
@@ -61,12 +61,24 @@ const assertValidExposeConfig = (
);
}
- const nonComponentExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !importPath.startsWith(COMPONENT_EXPOSE_PREFIX),
+ const nonUserlandExposeEntries = Object.entries(remoteExposeImports).filter(
+ ([, importPath]) => !importPath.startsWith(USERLAND_EXPOSE_PREFIX),
);
- if (nonComponentExposeEntries.length > 0) {
+ if (nonUserlandExposeEntries.length > 0) {
throw new Error(
- `Remote exposes must point to component userland modules (${COMPONENT_EXPOSE_PREFIX}). Invalid entries: ${nonComponentExposeEntries
+ `Remote exposes must point to userland source modules (${USERLAND_EXPOSE_PREFIX}). Invalid entries: ${nonUserlandExposeEntries
+ .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
+ .join(', ')}`,
+ );
+ }
+ const runtimeNamespaceExposeEntries = Object.entries(
+ remoteExposeImports,
+ ).filter(([, importPath]) =>
+ importPath.startsWith(CALLBACK_BOOTSTRAP_PREFIX),
+ );
+ if (runtimeNamespaceExposeEntries.length > 0) {
+ throw new Error(
+ `Remote exposes must not target internal runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Invalid entries: ${runtimeNamespaceExposeEntries
.map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
.join(', ')}`,
);
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 9e20301d20eb..08212d2b41f1 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -49,14 +49,23 @@ describe('createRscExposeDefinitions', () => {
);
});
- it('rejects expose imports outside component userland namespace', () => {
+ it('rejects expose imports outside source userland namespace', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './app/components/RemoteClientCounter.tsx',
+ }),
+ ).toThrow('Remote exposes must point to userland source modules (./src/)');
+ });
+
+ it('rejects expose imports targeting internal runtime namespace', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
createRscExposeDefinitions({
'./RemoteClientCounter': './src/runtime/helper.ts',
}),
).toThrow(
- 'Remote exposes must point to component userland modules (./src/components/)',
+ 'Remote exposes must not target internal runtime namespace (./src/runtime/)',
);
});
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 95f362177c1d..1c7af44b414c 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -105,7 +105,8 @@ describe('rsc-mf module federation config contracts', () => {
expect(Array.isArray(definition.import)).toBe(true);
expect(definition.import).toHaveLength(2);
expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
- expect(definition.import?.[1]).toMatch(/^\.\/src\/components\//);
+ expect(definition.import?.[1]).toMatch(/^\.\/src\//);
+ expect(definition.import?.[1]).not.toMatch(/^\.\/src\/runtime\//);
expect(definition.import?.[1]).toMatch(/\.[tj]sx?$/);
expect(definition.import?.[1]).not.toContain('..');
expect(definition.import?.[1]).not.toContain('\\');
From 48c15ebb16e0411213748f2e6d5bbe315c0fa029 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:52:57 +0000
Subject: [PATCH 200/324] refactor(rsc-mf): support relative expose import
paths
---
.../src/runtime/createRscExposeDefinitions.ts | 4 ++--
.../tests/createRscExposeDefinitions.test.ts | 24 ++++++++++++++++---
.../tests/moduleFederationConfig.test.ts | 2 +-
3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index cf41dbb5e352..a24b9bc4b46b 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -1,6 +1,6 @@
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
-const USERLAND_EXPOSE_PREFIX = './src/';
+const USERLAND_EXPOSE_PREFIX = './';
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
@@ -66,7 +66,7 @@ const assertValidExposeConfig = (
);
if (nonUserlandExposeEntries.length > 0) {
throw new Error(
- `Remote exposes must point to userland source modules (${USERLAND_EXPOSE_PREFIX}). Invalid entries: ${nonUserlandExposeEntries
+ `Remote exposes must point to userland relative modules (${USERLAND_EXPOSE_PREFIX}). Invalid entries: ${nonUserlandExposeEntries
.map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
.join(', ')}`,
);
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 08212d2b41f1..71264fd04bd4 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -49,13 +49,31 @@ describe('createRscExposeDefinitions', () => {
);
});
- it('rejects expose imports outside source userland namespace', () => {
+ it('allows expose imports outside src root when path is relative', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ expect(
+ createRscExposeDefinitions({
+ './RemoteClientCounter': './app/components/RemoteClientCounter.tsx',
+ }),
+ ).toEqual({
+ './RemoteClientCounter': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './app/components/RemoteClientCounter.tsx',
+ ],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
+ it('rejects non-relative expose imports', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
createRscExposeDefinitions({
- './RemoteClientCounter': './app/components/RemoteClientCounter.tsx',
+ './RemoteClientCounter': '/abs/components/RemoteClientCounter.tsx',
}),
- ).toThrow('Remote exposes must point to userland source modules (./src/)');
+ ).toThrow('Remote exposes must point to userland relative modules (./).');
});
it('rejects expose imports targeting internal runtime namespace', () => {
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 1c7af44b414c..f1ae190dbc80 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -105,7 +105,7 @@ describe('rsc-mf module federation config contracts', () => {
expect(Array.isArray(definition.import)).toBe(true);
expect(definition.import).toHaveLength(2);
expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
- expect(definition.import?.[1]).toMatch(/^\.\/src\//);
+ expect(definition.import?.[1]).toMatch(/^\.\//);
expect(definition.import?.[1]).not.toMatch(/^\.\/src\/runtime\//);
expect(definition.import?.[1]).toMatch(/\.[tj]sx?$/);
expect(definition.import?.[1]).not.toContain('..');
From cfb69fc081e7c0f213cc7fe4a40717e13869a81b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 07:56:50 +0000
Subject: [PATCH 201/324] refactor(rsc-mf): accept cjs/mjs/cts/mts expose
entries
---
.../src/runtime/createRscExposeDefinitions.ts | 15 ++++++++-----
.../tests/createRscExposeDefinitions.test.ts | 22 ++++++++++++++++++-
.../tests/moduleFederationConfig.test.ts | 2 +-
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index a24b9bc4b46b..7e0ea6d79689 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -1,15 +1,16 @@
const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
const USERLAND_EXPOSE_PREFIX = './';
+const SOURCE_ENTRY_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
`Callback bootstrap import must stay in runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
);
}
-if (!/\.[tj]sx?$/.test(CALLBACK_BOOTSTRAP_IMPORT)) {
+if (!SOURCE_ENTRY_EXTENSION_PATTERN.test(CALLBACK_BOOTSTRAP_IMPORT)) {
throw new Error(
- `Callback bootstrap import must use explicit source extension for deterministic resolution. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
+ `Callback bootstrap import must use an explicit source entry extension for deterministic resolution. Received: ${CALLBACK_BOOTSTRAP_IMPORT}`,
);
}
if (
@@ -84,12 +85,14 @@ const assertValidExposeConfig = (
);
}
- const nonTypeScriptExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !/\.[tj]sx?$/.test(importPath),
+ const nonSourceEntryExposeEntries = Object.entries(
+ remoteExposeImports,
+ ).filter(
+ ([, importPath]) => !SOURCE_ENTRY_EXTENSION_PATTERN.test(importPath),
);
- if (nonTypeScriptExposeEntries.length > 0) {
+ if (nonSourceEntryExposeEntries.length > 0) {
throw new Error(
- `Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution. Invalid entries: ${nonTypeScriptExposeEntries
+ `Remote expose imports must use explicit source entry extensions (.js/.jsx/.ts/.tsx/.cjs/.mjs/.cts/.mts) for deterministic resolution. Invalid entries: ${nonSourceEntryExposeEntries
.map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
.join(', ')}`,
);
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 71264fd04bd4..b7aa4220ba50 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -94,10 +94,30 @@ describe('createRscExposeDefinitions', () => {
'./RemoteClientCounter': './src/components/RemoteClientCounter',
}),
).toThrow(
- 'Remote expose imports must use explicit TypeScript entry extensions for deterministic resolution.',
+ 'Remote expose imports must use explicit source entry extensions (.js/.jsx/.ts/.tsx/.cjs/.mjs/.cts/.mts) for deterministic resolution.',
);
});
+ it('allows cts and mts expose entry extensions', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ expect(
+ createRscExposeDefinitions({
+ './serverOnlyHelper': './src/lib/serverOnlyHelper.cts',
+ './rscBridgeUtil': './src/lib/rscBridgeUtil.mts',
+ }),
+ ).toEqual({
+ './serverOnlyHelper': {
+ import: [CALLBACK_BOOTSTRAP_MODULE, './src/lib/serverOnlyHelper.cts'],
+ layer: 'react-server-components',
+ },
+ './rscBridgeUtil': {
+ import: [CALLBACK_BOOTSTRAP_MODULE, './src/lib/rscBridgeUtil.mts'],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
it('rejects expose imports with parent traversal segments', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index f1ae190dbc80..66b7531f28f4 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -107,7 +107,7 @@ describe('rsc-mf module federation config contracts', () => {
expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
expect(definition.import?.[1]).toMatch(/^\.\//);
expect(definition.import?.[1]).not.toMatch(/^\.\/src\/runtime\//);
- expect(definition.import?.[1]).toMatch(/\.[tj]sx?$/);
+ expect(definition.import?.[1]).toMatch(/\.[cm]?[jt]sx?$/i);
expect(definition.import?.[1]).not.toContain('..');
expect(definition.import?.[1]).not.toContain('\\');
expect(exposeKey).toMatch(/^\.\//);
From f6beeb97c92189933b22084428e2f978e3f887d1 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:01:25 +0000
Subject: [PATCH 202/324] refactor(rsc-mf): support object expose definitions
with import arrays
---
.../src/runtime/createRscExposeDefinitions.ts | 164 ++++++++++++++----
.../tests/createRscExposeDefinitions.test.ts | 86 ++++++++-
2 files changed, 208 insertions(+), 42 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index 7e0ea6d79689..b633c680c38c 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -2,6 +2,19 @@ const CALLBACK_BOOTSTRAP_IMPORT = './src/runtime/initServerCallback.ts';
const CALLBACK_BOOTSTRAP_PREFIX = './src/runtime/';
const USERLAND_EXPOSE_PREFIX = './';
const SOURCE_ENTRY_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
+const RSC_LAYER = 'react-server-components';
+
+type ExposeImportInput = string | string[];
+type ExposeDefinitionInput =
+ | string
+ | ({
+ import: ExposeImportInput;
+ } & Record);
+type NormalizedExposeImportPaths = Record;
+interface NormalizedExposeDefinition {
+ importPaths: string[];
+ exposeOverrides: Record;
+}
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
@@ -22,16 +35,59 @@ if (
);
}
-const createRscExpose = (importPath: string) =>
+const normalizeExposeImportPaths = (
+ exposeKey: string,
+ exposeDefinition: ExposeDefinitionInput,
+) => {
+ if (typeof exposeDefinition === 'string') {
+ return {
+ importPaths: [exposeDefinition],
+ exposeOverrides: {},
+ } satisfies NormalizedExposeDefinition;
+ }
+
+ if (!exposeDefinition || typeof exposeDefinition !== 'object') {
+ throw new Error(
+ `Remote expose definition must be a string path or an object with an import field. Invalid entry: ${exposeKey} -> ${String(exposeDefinition)}`,
+ );
+ }
+
+ const { import: exposeImport, ...exposeOverrides } = exposeDefinition;
+ if (typeof exposeImport === 'string') {
+ return {
+ importPaths: [exposeImport],
+ exposeOverrides,
+ } satisfies NormalizedExposeDefinition;
+ }
+ if (
+ Array.isArray(exposeImport) &&
+ exposeImport.length > 0 &&
+ exposeImport.every(item => typeof item === 'string')
+ ) {
+ return {
+ importPaths: exposeImport,
+ exposeOverrides,
+ } satisfies NormalizedExposeDefinition;
+ }
+ throw new Error(
+ `Remote expose import must be a non-empty string or string array. Invalid entry: ${exposeKey}`,
+ );
+};
+
+const createRscExpose = (
+ importPaths: string[],
+ exposeOverrides: Record,
+) =>
({
- import: [CALLBACK_BOOTSTRAP_IMPORT, importPath],
- layer: 'react-server-components',
+ ...exposeOverrides,
+ import: [CALLBACK_BOOTSTRAP_IMPORT, ...importPaths],
+ layer: RSC_LAYER,
}) as const;
const assertValidExposeConfig = (
- remoteExposeImports: Record,
+ normalizedExposeImportPaths: NormalizedExposeImportPaths,
) => {
- const invalidExposeKeys = Object.keys(remoteExposeImports).filter(
+ const invalidExposeKeys = Object.keys(normalizedExposeImportPaths).filter(
exposeKey => !exposeKey.startsWith('./'),
);
if (invalidExposeKeys.length > 0) {
@@ -40,8 +96,10 @@ const assertValidExposeConfig = (
);
}
- const callbackExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => importPath === CALLBACK_BOOTSTRAP_IMPORT,
+ const callbackExposeEntries = Object.entries(
+ normalizedExposeImportPaths,
+ ).filter(([, importPaths]) =>
+ importPaths.includes(CALLBACK_BOOTSTRAP_IMPORT),
);
if (callbackExposeEntries.length > 0) {
throw new Error(
@@ -51,74 +109,104 @@ const assertValidExposeConfig = (
);
}
- const nonPosixExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => importPath.includes('\\'),
+ const nonPosixExposeEntries = Object.entries(
+ normalizedExposeImportPaths,
+ ).flatMap(([exposeKey, importPaths]) =>
+ importPaths
+ .filter(importPath => importPath.includes('\\'))
+ .map(importPath => `${exposeKey} -> ${importPath}`),
);
if (nonPosixExposeEntries.length > 0) {
throw new Error(
- `Remote expose imports must use POSIX separators for deterministic module ids. Invalid entries: ${nonPosixExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Remote expose imports must use POSIX separators for deterministic module ids. Invalid entries: ${nonPosixExposeEntries.join(
+ ', ',
+ )}`,
);
}
- const nonUserlandExposeEntries = Object.entries(remoteExposeImports).filter(
- ([, importPath]) => !importPath.startsWith(USERLAND_EXPOSE_PREFIX),
+ const nonUserlandExposeEntries = Object.entries(
+ normalizedExposeImportPaths,
+ ).flatMap(([exposeKey, importPaths]) =>
+ importPaths
+ .filter(importPath => !importPath.startsWith(USERLAND_EXPOSE_PREFIX))
+ .map(importPath => `${exposeKey} -> ${importPath}`),
);
if (nonUserlandExposeEntries.length > 0) {
throw new Error(
- `Remote exposes must point to userland relative modules (${USERLAND_EXPOSE_PREFIX}). Invalid entries: ${nonUserlandExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Remote exposes must point to userland relative modules (${USERLAND_EXPOSE_PREFIX}). Invalid entries: ${nonUserlandExposeEntries.join(
+ ', ',
+ )}`,
);
}
const runtimeNamespaceExposeEntries = Object.entries(
- remoteExposeImports,
- ).filter(([, importPath]) =>
- importPath.startsWith(CALLBACK_BOOTSTRAP_PREFIX),
+ normalizedExposeImportPaths,
+ ).flatMap(([exposeKey, importPaths]) =>
+ importPaths
+ .filter(importPath => importPath.startsWith(CALLBACK_BOOTSTRAP_PREFIX))
+ .map(importPath => `${exposeKey} -> ${importPath}`),
);
if (runtimeNamespaceExposeEntries.length > 0) {
throw new Error(
- `Remote exposes must not target internal runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Invalid entries: ${runtimeNamespaceExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Remote exposes must not target internal runtime namespace (${CALLBACK_BOOTSTRAP_PREFIX}). Invalid entries: ${runtimeNamespaceExposeEntries.join(
+ ', ',
+ )}`,
);
}
const nonSourceEntryExposeEntries = Object.entries(
- remoteExposeImports,
- ).filter(
- ([, importPath]) => !SOURCE_ENTRY_EXTENSION_PATTERN.test(importPath),
+ normalizedExposeImportPaths,
+ ).flatMap(([exposeKey, importPaths]) =>
+ importPaths
+ .filter(importPath => !SOURCE_ENTRY_EXTENSION_PATTERN.test(importPath))
+ .map(importPath => `${exposeKey} -> ${importPath}`),
);
if (nonSourceEntryExposeEntries.length > 0) {
throw new Error(
- `Remote expose imports must use explicit source entry extensions (.js/.jsx/.ts/.tsx/.cjs/.mjs/.cts/.mts) for deterministic resolution. Invalid entries: ${nonSourceEntryExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Remote expose imports must use explicit source entry extensions (.js/.jsx/.ts/.tsx/.cjs/.mjs/.cts/.mts) for deterministic resolution. Invalid entries: ${nonSourceEntryExposeEntries.join(
+ ', ',
+ )}`,
);
}
const parentTraversalExposeEntries = Object.entries(
- remoteExposeImports,
- ).filter(([, importPath]) => importPath.includes('..'));
+ normalizedExposeImportPaths,
+ ).flatMap(([exposeKey, importPaths]) =>
+ importPaths
+ .filter(importPath => importPath.includes('..'))
+ .map(importPath => `${exposeKey} -> ${importPath}`),
+ );
if (parentTraversalExposeEntries.length > 0) {
throw new Error(
- `Remote expose imports must not contain parent directory traversal segments. Invalid entries: ${parentTraversalExposeEntries
- .map(([exposeKey, importPath]) => `${exposeKey} -> ${importPath}`)
- .join(', ')}`,
+ `Remote expose imports must not contain parent directory traversal segments. Invalid entries: ${parentTraversalExposeEntries.join(
+ ', ',
+ )}`,
);
}
};
export const createRscExposeDefinitions = (
- remoteExposeImports: Record,
+ remoteExposeImports: Record,
) => {
- assertValidExposeConfig(remoteExposeImports);
+ const normalizedExposeEntries: Array<[string, NormalizedExposeDefinition]> =
+ Object.entries(remoteExposeImports).map(([exposeKey, exposeDefinition]) => [
+ exposeKey,
+ normalizeExposeImportPaths(exposeKey, exposeDefinition),
+ ]);
+ const normalizedExposeImportPaths = Object.fromEntries(
+ normalizedExposeEntries.map(([exposeKey, normalizedDefinition]) => [
+ exposeKey,
+ normalizedDefinition.importPaths,
+ ]),
+ );
+ assertValidExposeConfig(normalizedExposeImportPaths);
return Object.fromEntries(
- Object.entries(remoteExposeImports).map(([exposeKey, importPath]) => [
+ normalizedExposeEntries.map(([exposeKey, normalizedDefinition]) => [
exposeKey,
- createRscExpose(importPath),
+ createRscExpose(
+ normalizedDefinition.importPaths,
+ normalizedDefinition.exposeOverrides,
+ ),
]),
);
};
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index b7aa4220ba50..716185606a63 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -3,12 +3,21 @@ const CREATE_RSC_EXPOSE_DEFINITIONS_MODULE =
const loadCreateRscExposeDefinitions = () => {
let moduleExports: any;
- jest.isolateModules(() => {
- moduleExports = require(CREATE_RSC_EXPOSE_DEFINITIONS_MODULE);
- });
+ try {
+ jest.isolateModules(() => {
+ moduleExports = require(CREATE_RSC_EXPOSE_DEFINITIONS_MODULE);
+ });
+ } catch (error) {
+ throw new Error(
+ `Failed to load createRscExposeDefinitions module: ${String(error)}`,
+ );
+ }
return moduleExports as {
createRscExposeDefinitions: (
- remoteExposeImports: Record,
+ remoteExposeImports: Record<
+ string,
+ string | { import: string | string[]; [key: string]: unknown }
+ >,
) => Record;
CALLBACK_BOOTSTRAP_MODULE: string;
};
@@ -118,6 +127,75 @@ describe('createRscExposeDefinitions', () => {
});
});
+ it('supports object expose definitions with custom fields', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ const exposeDefinitions = createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: './src/components/RemoteClientCounter.tsx',
+ shareScope: 'rsc',
+ },
+ });
+
+ expect(exposeDefinitions).toEqual({
+ './RemoteClientCounter': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/RemoteClientCounter.tsx',
+ ],
+ shareScope: 'rsc',
+ layer: 'react-server-components',
+ },
+ });
+ });
+
+ it('supports object expose definitions with import arrays', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ const exposeDefinitions = createRscExposeDefinitions({
+ './infoBundle': {
+ import: [
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ },
+ });
+
+ expect(exposeDefinitions).toEqual({
+ './infoBundle': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
+ it('rejects object expose definitions with invalid import payloads', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: [] as string[],
+ },
+ }),
+ ).toThrow(
+ 'Remote expose import must be a non-empty string or string array.',
+ );
+
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: [42] as unknown as string[],
+ },
+ }),
+ ).toThrow(
+ 'Remote expose import must be a non-empty string or string array.',
+ );
+ });
+
it('rejects expose imports with parent traversal segments', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
From 5d399659bb9a9635d6111cc493b2ca1be4434646 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:05:42 +0000
Subject: [PATCH 203/324] refactor(rsc-mf): normalize mixed expose definition
shapes
---
.../rsc-mf/remote/module-federation.config.ts | 11 ++++++++---
.../remote/src/runtime/createRscExposeDefinitions.ts | 2 +-
.../rsc-mf/tests/createRscExposeDefinitions.test.ts | 12 +++---------
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index a35e782553f7..442ebdd974f3 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -1,6 +1,9 @@
import path from 'path';
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
-import { createRscExposeDefinitions } from './src/runtime/createRscExposeDefinitions';
+import {
+ type ExposeDefinitionInput,
+ createRscExposeDefinitions,
+} from './src/runtime/createRscExposeDefinitions';
const LAYERS = {
ssr: 'server-side-rendering',
@@ -15,7 +18,7 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
-const remoteExposeImports: Record = {
+const remoteExposeImports: Record = {
'./RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
'./RemoteClientBadge': './src/components/RemoteClientBadge.tsx',
'./RemoteServerCard': './src/components/RemoteServerCard.tsx',
@@ -28,7 +31,9 @@ const remoteExposeImports: Record = {
'./nestedActions': './src/components/nestedActions.ts',
'./defaultAction': './src/components/defaultAction.ts',
'./actionBundle': './src/components/actionBundle.ts',
- './infoBundle': './src/components/infoBundle.ts',
+ './infoBundle': {
+ import: './src/components/infoBundle.ts',
+ },
};
const sharedByScope = [
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index b633c680c38c..c84a7c5869bc 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -5,7 +5,7 @@ const SOURCE_ENTRY_EXTENSION_PATTERN = /\.[cm]?[jt]sx?$/i;
const RSC_LAYER = 'react-server-components';
type ExposeImportInput = string | string[];
-type ExposeDefinitionInput =
+export type ExposeDefinitionInput =
| string
| ({
import: ExposeImportInput;
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 716185606a63..7868e8d7f2d2 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -3,15 +3,9 @@ const CREATE_RSC_EXPOSE_DEFINITIONS_MODULE =
const loadCreateRscExposeDefinitions = () => {
let moduleExports: any;
- try {
- jest.isolateModules(() => {
- moduleExports = require(CREATE_RSC_EXPOSE_DEFINITIONS_MODULE);
- });
- } catch (error) {
- throw new Error(
- `Failed to load createRscExposeDefinitions module: ${String(error)}`,
- );
- }
+ jest.isolateModules(() => {
+ moduleExports = require(CREATE_RSC_EXPOSE_DEFINITIONS_MODULE);
+ });
return moduleExports as {
createRscExposeDefinitions: (
remoteExposeImports: Record<
From 73814a0f9e27e87bd341eaf10c9ea91f28eb329c Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:07:19 +0000
Subject: [PATCH 204/324] test(rsc-mf): lock mixed expose-definition guardrails
---
.../tests/createRscExposeDefinitions.test.ts | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 7868e8d7f2d2..dbc171e10878 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -128,6 +128,7 @@ describe('createRscExposeDefinitions', () => {
'./RemoteClientCounter': {
import: './src/components/RemoteClientCounter.tsx',
shareScope: 'rsc',
+ flag: true,
},
});
@@ -138,6 +139,7 @@ describe('createRscExposeDefinitions', () => {
'./src/components/RemoteClientCounter.tsx',
],
shareScope: 'rsc',
+ flag: true,
layer: 'react-server-components',
},
});
@@ -188,6 +190,61 @@ describe('createRscExposeDefinitions', () => {
).toThrow(
'Remote expose import must be a non-empty string or string array.',
);
+
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {} as { import: string },
+ }),
+ ).toThrow(
+ 'Remote expose import must be a non-empty string or string array.',
+ );
+ });
+
+ it('rejects non-string and non-object expose definitions', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': 7 as unknown as string,
+ }),
+ ).toThrow(
+ 'Remote expose definition must be a string path or an object with an import field.',
+ );
+ });
+
+ it('forces rsc layer even if expose object provides a different layer', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ expect(
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: './src/components/RemoteClientCounter.tsx',
+ layer: 'server-side-rendering',
+ },
+ }),
+ ).toEqual({
+ './RemoteClientCounter': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/RemoteClientCounter.tsx',
+ ],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
+ it('rejects import arrays that include callback bootstrap module', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: [
+ './src/components/RemoteClientCounter.tsx',
+ CALLBACK_BOOTSTRAP_MODULE,
+ ],
+ },
+ }),
+ ).toThrow('must remain internal-only and cannot be exposed');
});
it('rejects expose imports with parent traversal segments', () => {
From 0d5ec921f92054c12e0d991cf03b30a2d548a4f0 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:09:23 +0000
Subject: [PATCH 205/324] refactor(rsc-mf): retry callback fetch on 429
responses
---
.../src/runtime/registerServerCallback.ts | 6 +++-
.../tests/registerServerCallback.test.ts | 34 +++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index 04d02cf41e0a..99117b8dc91c 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -9,6 +9,7 @@ let registeredCallbackKey = '';
const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
const DEFAULT_REMOTE_ALIAS = 'rscRemote';
const MAX_CALLBACK_FETCH_RETRIES = 1;
+const RETRYABLE_CALLBACK_STATUSES = new Set([429]);
const getNormalizedRawActionId = (rawActionId: string) => {
const normalizedRawActionId = rawActionId.trim();
if (!normalizedRawActionId || /\s/.test(normalizedRawActionId)) {
@@ -52,6 +53,8 @@ const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
};
const getCallbackKey = (remoteAlias: string, remoteActionUrl: string) =>
`${remoteAlias}::${remoteActionUrl}`;
+const isRetryableCallbackStatus = (status: number) =>
+ status >= 500 || RETRYABLE_CALLBACK_STATUSES.has(status);
export function registerRemoteServerCallback(
remoteOrigin: string,
@@ -112,7 +115,8 @@ export function registerRemoteServerCallback(
}
const shouldRetry =
- response.status >= 500 && attempt < MAX_CALLBACK_FETCH_RETRIES;
+ isRetryableCallbackStatus(response.status) &&
+ attempt < MAX_CALLBACK_FETCH_RETRIES;
if (shouldRetry) {
response = undefined;
continue;
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 668523857130..2e0ec625f881 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -139,6 +139,40 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('retries once when callback fetch returns retryable 429 response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest
+ .fn()
+ .mockResolvedValueOnce({
+ ok: false,
+ status: 429,
+ statusText: 'Too Many Requests',
+ } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ } as Response);
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-retry-429-action', ['arg-1']),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ type: 'decoded-rsc-response',
+ }),
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
it('does not retry callback fetch for non-retryable 4xx response', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From ae03f8f62ee69db00964c9da08b394c073d406fe Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:13:24 +0000
Subject: [PATCH 206/324] test(rsc-mf): allow multi-import expose definitions
in config contract
---
.../rsc-mf/tests/moduleFederationConfig.test.ts | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 66b7531f28f4..ee54fe3207ea 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -103,13 +103,15 @@ describe('rsc-mf module federation config contracts', () => {
expect(definition.layer).toBe('react-server-components');
expect(definition.import).toBeDefined();
expect(Array.isArray(definition.import)).toBe(true);
- expect(definition.import).toHaveLength(2);
expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
- expect(definition.import?.[1]).toMatch(/^\.\//);
- expect(definition.import?.[1]).not.toMatch(/^\.\/src\/runtime\//);
- expect(definition.import?.[1]).toMatch(/\.[cm]?[jt]sx?$/i);
- expect(definition.import?.[1]).not.toContain('..');
- expect(definition.import?.[1]).not.toContain('\\');
+ expect(definition.import!.length).toBeGreaterThanOrEqual(2);
+ for (const importPath of definition.import!.slice(1)) {
+ expect(importPath).toMatch(/^\.\//);
+ expect(importPath).not.toMatch(/^\.\/src\/runtime\//);
+ expect(importPath).toMatch(/\.[cm]?[jt]sx?$/i);
+ expect(importPath).not.toContain('..');
+ expect(importPath).not.toContain('\\');
+ }
expect(exposeKey).toMatch(/^\.\//);
}
});
From 4a92133d1ce64e3ffa17c0d669e070dddf78450d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:14:58 +0000
Subject: [PATCH 207/324] refactor(rsc-mf): dedupe repeated expose import
entries
---
.../src/runtime/createRscExposeDefinitions.ts | 5 +++-
.../tests/createRscExposeDefinitions.test.ts | 25 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index c84a7c5869bc..034fcc4d9640 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -15,6 +15,9 @@ interface NormalizedExposeDefinition {
importPaths: string[];
exposeOverrides: Record;
}
+const getUniqueImportPaths = (importPaths: string[]) => [
+ ...new Set(importPaths),
+];
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
@@ -65,7 +68,7 @@ const normalizeExposeImportPaths = (
exposeImport.every(item => typeof item === 'string')
) {
return {
- importPaths: exposeImport,
+ importPaths: getUniqueImportPaths(exposeImport),
exposeOverrides,
} satisfies NormalizedExposeDefinition;
}
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index dbc171e10878..5e4d97bff549 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -169,6 +169,31 @@ describe('createRscExposeDefinitions', () => {
});
});
+ it('deduplicates repeated entries in object expose import arrays', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ const exposeDefinitions = createRscExposeDefinitions({
+ './infoBundle': {
+ import: [
+ './src/components/infoBundle.ts',
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ },
+ });
+
+ expect(exposeDefinitions).toEqual({
+ './infoBundle': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
it('rejects object expose definitions with invalid import payloads', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
From 962d1e8f842fe737df4ea636b6c460d5a64c9262 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:16:20 +0000
Subject: [PATCH 208/324] refactor(rsc-mf): retry callback fetch on timeout
status codes
---
.../src/runtime/registerServerCallback.ts | 2 +-
.../tests/registerServerCallback.test.ts | 34 +++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index 99117b8dc91c..fac458c4c2e1 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -9,7 +9,7 @@ let registeredCallbackKey = '';
const ALIAS_TOKEN_PATTERN = /^[A-Za-z0-9_.-]+$/;
const DEFAULT_REMOTE_ALIAS = 'rscRemote';
const MAX_CALLBACK_FETCH_RETRIES = 1;
-const RETRYABLE_CALLBACK_STATUSES = new Set([429]);
+const RETRYABLE_CALLBACK_STATUSES = new Set([408, 425, 429]);
const getNormalizedRawActionId = (rawActionId: string) => {
const normalizedRawActionId = rawActionId.trim();
if (!normalizedRawActionId || /\s/.test(normalizedRawActionId)) {
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 2e0ec625f881..2dabec9c4089 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -173,6 +173,40 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('retries once when callback fetch returns retryable 408 response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest
+ .fn()
+ .mockResolvedValueOnce({
+ ok: false,
+ status: 408,
+ statusText: 'Request Timeout',
+ } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ } as Response);
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-retry-408-action', ['arg-1']),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ type: 'decoded-rsc-response',
+ }),
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
it('does not retry callback fetch for non-retryable 4xx response', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From 04bea873e5e4938f8bff828aadaabc55d4763d30 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:18:55 +0000
Subject: [PATCH 209/324] test(rsc-mf): verify callback retry for 425 responses
---
.../tests/registerServerCallback.test.ts | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 2dabec9c4089..baf68270ed8f 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -207,6 +207,40 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('retries once when callback fetch returns retryable 425 response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest
+ .fn()
+ .mockResolvedValueOnce({
+ ok: false,
+ status: 425,
+ statusText: 'Too Early',
+ } as Response)
+ .mockResolvedValueOnce({
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ } as Response);
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-retry-425-action', ['arg-1']),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ type: 'decoded-rsc-response',
+ }),
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
+ expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
+ });
+
it('does not retry callback fetch for non-retryable 4xx response', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From a2898096ac15c72569491b92491f62c4e055270d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:22:05 +0000
Subject: [PATCH 210/324] refactor(rsc-mf): trim expose import paths before
validation
---
.../src/runtime/createRscExposeDefinitions.ts | 23 +++++++++---
.../tests/createRscExposeDefinitions.test.ts | 37 ++++++++++++++++++-
2 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index 034fcc4d9640..319cf5cb510d 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -15,9 +15,20 @@ interface NormalizedExposeDefinition {
importPaths: string[];
exposeOverrides: Record;
}
-const getUniqueImportPaths = (importPaths: string[]) => [
- ...new Set(importPaths),
-];
+const normalizeImportPaths = (exposeKey: string, importPaths: string[]) => {
+ const normalizedImportPaths = importPaths.map(importPath =>
+ importPath.trim(),
+ );
+ const hasEmptyImportPath = normalizedImportPaths.some(
+ importPath => importPath.length === 0,
+ );
+ if (hasEmptyImportPath) {
+ throw new Error(
+ `Remote expose import paths must be non-empty tokens after trimming. Invalid entry: ${exposeKey}`,
+ );
+ }
+ return [...new Set(normalizedImportPaths)];
+};
if (!CALLBACK_BOOTSTRAP_IMPORT.startsWith(CALLBACK_BOOTSTRAP_PREFIX)) {
throw new Error(
@@ -44,7 +55,7 @@ const normalizeExposeImportPaths = (
) => {
if (typeof exposeDefinition === 'string') {
return {
- importPaths: [exposeDefinition],
+ importPaths: normalizeImportPaths(exposeKey, [exposeDefinition]),
exposeOverrides: {},
} satisfies NormalizedExposeDefinition;
}
@@ -58,7 +69,7 @@ const normalizeExposeImportPaths = (
const { import: exposeImport, ...exposeOverrides } = exposeDefinition;
if (typeof exposeImport === 'string') {
return {
- importPaths: [exposeImport],
+ importPaths: normalizeImportPaths(exposeKey, [exposeImport]),
exposeOverrides,
} satisfies NormalizedExposeDefinition;
}
@@ -68,7 +79,7 @@ const normalizeExposeImportPaths = (
exposeImport.every(item => typeof item === 'string')
) {
return {
- importPaths: getUniqueImportPaths(exposeImport),
+ importPaths: normalizeImportPaths(exposeKey, exposeImport),
exposeOverrides,
} satisfies NormalizedExposeDefinition;
}
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 5e4d97bff549..1ffc032ff909 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -22,7 +22,7 @@ describe('createRscExposeDefinitions', () => {
const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
loadCreateRscExposeDefinitions();
const exposeDefinitions = createRscExposeDefinitions({
- './RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
+ './RemoteClientCounter': ' ./src/components/RemoteClientCounter.tsx ',
'./actions': './src/components/actions.ts',
});
@@ -194,6 +194,31 @@ describe('createRscExposeDefinitions', () => {
});
});
+ it('trims expose import path entries before deduping', () => {
+ const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
+ loadCreateRscExposeDefinitions();
+ const exposeDefinitions = createRscExposeDefinitions({
+ './infoBundle': {
+ import: [
+ ' ./src/components/infoBundle.ts ',
+ './src/components/infoBundle.ts',
+ ' ./src/components/remoteMeta.ts ',
+ ],
+ },
+ });
+
+ expect(exposeDefinitions).toEqual({
+ './infoBundle': {
+ import: [
+ CALLBACK_BOOTSTRAP_MODULE,
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ layer: 'react-server-components',
+ },
+ });
+ });
+
it('rejects object expose definitions with invalid import payloads', () => {
const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
expect(() =>
@@ -223,6 +248,16 @@ describe('createRscExposeDefinitions', () => {
).toThrow(
'Remote expose import must be a non-empty string or string array.',
);
+
+ expect(() =>
+ createRscExposeDefinitions({
+ './RemoteClientCounter': {
+ import: ' ',
+ },
+ }),
+ ).toThrow(
+ 'Remote expose import paths must be non-empty tokens after trimming.',
+ );
});
it('rejects non-string and non-object expose definitions', () => {
From a689f5bbfb8b230a5fc59cfc20c2c26c467a1284 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:23:54 +0000
Subject: [PATCH 211/324] test(rsc-mf): assert callback network failure after
retries
---
.../tests/registerServerCallback.test.ts | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index baf68270ed8f..bd50dcdd53b9 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -294,6 +294,31 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('throws network error after retry budget is exhausted', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+
+ global.fetch = jest
+ .fn()
+ .mockRejectedValueOnce(new Error('network-down-first-attempt'))
+ .mockRejectedValueOnce(new Error('network-down-second-attempt'));
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-network-failure-action', ['arg-1']),
+ ).rejects.toThrow(
+ 'Remote action callback request failed due to network error (http://127.0.0.1:3008/server-component-root): Error: network-down-second-attempt',
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
+ expect(mockCreateFromFetch).not.toHaveBeenCalled();
+ });
+
it('uses default alias when remote alias is omitted', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From 8f9e303e5ef671a570b754fc8439b815b3ac94cf Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:25:51 +0000
Subject: [PATCH 212/324] test(rsc-mf): assert dedupe behavior in remote expose
config
---
.../rsc-mf/remote/module-federation.config.ts | 5 ++++-
.../rsc-mf/tests/moduleFederationConfig.test.ts | 13 +++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 442ebdd974f3..33f06c5c81aa 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -32,7 +32,10 @@ const remoteExposeImports: Record = {
'./defaultAction': './src/components/defaultAction.ts',
'./actionBundle': './src/components/actionBundle.ts',
'./infoBundle': {
- import: './src/components/infoBundle.ts',
+ import: [
+ './src/components/infoBundle.ts',
+ './src/components/infoBundle.ts',
+ ],
},
};
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index ee54fe3207ea..9778d9c8ae46 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -139,6 +139,19 @@ describe('rsc-mf module federation config contracts', () => {
);
});
+ it('deduplicates repeated imports in object expose definitions', () => {
+ const remoteConfig = loadRemoteConfig();
+ const infoBundleExpose = remoteConfig.exposes?.['./infoBundle'] as
+ | {
+ import?: string[];
+ }
+ | undefined;
+ expect(infoBundleExpose?.import).toEqual([
+ CALLBACK_BOOTSTRAP_IMPORT,
+ './src/components/infoBundle.ts',
+ ]);
+ });
+
it('uses remote port env var in host manifest remote URL', () => {
const hostConfig = loadHostConfig({
nodeEnv: 'test',
From ba39928a6ab86a02c3f22cb043bbd5c7c772274e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:27:27 +0000
Subject: [PATCH 213/324] refactor(rsc-mf): normalize callback URLs with
trailing slashes
---
.../src/runtime/registerServerCallback.ts | 2 ++
.../tests/registerServerCallback.test.ts | 25 +++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
index fac458c4c2e1..bf092f89ee27 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/registerServerCallback.ts
@@ -47,6 +47,8 @@ const getNormalizedRemoteActionUrl = (remoteOrigin: string) => {
'Remote action callback URL must not include embedded credentials.',
);
}
+ const normalizedPathname = url.pathname.replace(/\/+$/, '') || '/';
+ url.pathname = normalizedPathname;
url.search = '';
url.hash = '';
return url.toString();
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index bd50dcdd53b9..15689d6942da 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -384,6 +384,31 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes callback registrations when only trailing slash differs', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root/',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('slash-normalized-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:slash-normalized-action',
+ }),
+ }),
+ );
+ });
+
it('re-registers callback when alias changes and uses new alias prefix', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
From 442271ff45cd15f60441f51cfe0d8afbf93b89de Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:29:15 +0000
Subject: [PATCH 214/324] test(rsc-mf): assert terminal 429 callback failure
after retry
---
.../tests/registerServerCallback.test.ts | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 15689d6942da..450d7a289082 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -173,6 +173,33 @@ describe('registerRemoteServerCallback runtime behavior', () => {
expect(mockCreateFromFetch).toHaveBeenCalledTimes(1);
});
+ it('throws after retry when callback fetch stays at retryable 429 response', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
+ global.fetch = jest.fn(async () => {
+ return {
+ ok: false,
+ status: 429,
+ statusText: 'Too Many Requests',
+ } as Response;
+ });
+
+ const callback = getRegisteredCallback();
+ await expect(
+ callback('fetch-retry-429-fail-action', ['arg-1']),
+ ).rejects.toThrow(
+ 'Remote action callback request failed with status 429 Too Many Requests (http://127.0.0.1:3008/server-component-root).',
+ );
+ expect(mockCreateTemporaryReferenceSet).toHaveBeenCalledTimes(1);
+ expect(mockEncodeReply).toHaveBeenCalledTimes(1);
+ expect(global.fetch).toHaveBeenCalledTimes(2);
+ const firstFetchBody = (global.fetch as jest.Mock).mock.calls[0]?.[1]?.body;
+ const secondFetchBody = (global.fetch as jest.Mock).mock.calls[1]?.[1]
+ ?.body;
+ expect(firstFetchBody).toBe(secondFetchBody);
+ expect(mockCreateFromFetch).not.toHaveBeenCalled();
+ });
+
it('retries once when callback fetch returns retryable 408 response', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008/server-component-root');
From 7ae305c52cce240119c5ce88228a9b90bd5a1a4e Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:35:31 +0000
Subject: [PATCH 215/324] refactor(rsc-mf): enforce single-module object import
arrays
---
.../src/runtime/createRscExposeDefinitions.ts | 13 ++++-
.../tests/createRscExposeDefinitions.test.ts | 52 +++++++------------
2 files changed, 30 insertions(+), 35 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
index 319cf5cb510d..742b483e4086 100644
--- a/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
+++ b/tests/integration/rsc-mf/remote/src/runtime/createRscExposeDefinitions.ts
@@ -78,8 +78,19 @@ const normalizeExposeImportPaths = (
exposeImport.length > 0 &&
exposeImport.every(item => typeof item === 'string')
) {
+ const normalizedImportPaths = normalizeImportPaths(exposeKey, exposeImport);
+ if (normalizedImportPaths.includes(CALLBACK_BOOTSTRAP_IMPORT)) {
+ throw new Error(
+ `Callback bootstrap module (${CALLBACK_BOOTSTRAP_IMPORT}) must remain internal-only and cannot be exposed. Invalid entries: ${exposeKey}`,
+ );
+ }
+ if (normalizedImportPaths.length > 1) {
+ throw new Error(
+ `Remote expose import arrays must normalize to a single userland module path. Invalid entry: ${exposeKey}`,
+ );
+ }
return {
- importPaths: normalizeImportPaths(exposeKey, exposeImport),
+ importPaths: normalizedImportPaths,
exposeOverrides,
} satisfies NormalizedExposeDefinition;
}
diff --git a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
index 1ffc032ff909..4b1befc4038a 100644
--- a/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
+++ b/tests/integration/rsc-mf/tests/createRscExposeDefinitions.test.ts
@@ -145,28 +145,20 @@ describe('createRscExposeDefinitions', () => {
});
});
- it('supports object expose definitions with import arrays', () => {
- const { createRscExposeDefinitions, CALLBACK_BOOTSTRAP_MODULE } =
- loadCreateRscExposeDefinitions();
- const exposeDefinitions = createRscExposeDefinitions({
- './infoBundle': {
- import: [
- './src/components/infoBundle.ts',
- './src/components/remoteMeta.ts',
- ],
- },
- });
-
- expect(exposeDefinitions).toEqual({
- './infoBundle': {
- import: [
- CALLBACK_BOOTSTRAP_MODULE,
- './src/components/infoBundle.ts',
- './src/components/remoteMeta.ts',
- ],
- layer: 'react-server-components',
- },
- });
+ it('rejects multi-module import arrays in object expose definitions', () => {
+ const { createRscExposeDefinitions } = loadCreateRscExposeDefinitions();
+ expect(() =>
+ createRscExposeDefinitions({
+ './infoBundle': {
+ import: [
+ './src/components/infoBundle.ts',
+ './src/components/remoteMeta.ts',
+ ],
+ },
+ }),
+ ).toThrow(
+ 'Remote expose import arrays must normalize to a single userland module path.',
+ );
});
it('deduplicates repeated entries in object expose import arrays', () => {
@@ -177,18 +169,14 @@ describe('createRscExposeDefinitions', () => {
import: [
'./src/components/infoBundle.ts',
'./src/components/infoBundle.ts',
- './src/components/remoteMeta.ts',
+ './src/components/infoBundle.ts',
],
},
});
expect(exposeDefinitions).toEqual({
'./infoBundle': {
- import: [
- CALLBACK_BOOTSTRAP_MODULE,
- './src/components/infoBundle.ts',
- './src/components/remoteMeta.ts',
- ],
+ import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/infoBundle.ts'],
layer: 'react-server-components',
},
});
@@ -202,18 +190,14 @@ describe('createRscExposeDefinitions', () => {
import: [
' ./src/components/infoBundle.ts ',
'./src/components/infoBundle.ts',
- ' ./src/components/remoteMeta.ts ',
+ ' ./src/components/infoBundle.ts ',
],
},
});
expect(exposeDefinitions).toEqual({
'./infoBundle': {
- import: [
- CALLBACK_BOOTSTRAP_MODULE,
- './src/components/infoBundle.ts',
- './src/components/remoteMeta.ts',
- ],
+ import: [CALLBACK_BOOTSTRAP_MODULE, './src/components/infoBundle.ts'],
layer: 'react-server-components',
},
});
From 4ec8948e91c0c74dd84f5ae85a1679915594350d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:37:08 +0000
Subject: [PATCH 216/324] test(rsc-mf): cover root callback URL slash dedupe
---
.../tests/registerServerCallback.test.ts | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 450d7a289082..b8495c93aa28 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -436,6 +436,25 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes root callback registrations for origin with and without slash', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback('http://127.0.0.1:3008', 'rscRemote');
+ registerRemoteServerCallback('http://127.0.0.1:3008/', 'rscRemote');
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('root-endpoint-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:root-endpoint-action',
+ }),
+ }),
+ );
+ });
+
it('re-registers callback when alias changes and uses new alias prefix', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
From 2c4a7f1f24fb907384b65212f5f4165b31cfdf0b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:38:38 +0000
Subject: [PATCH 217/324] test(rsc-mf): cover slash+fragment callback URL
dedupe
---
.../tests/registerServerCallback.test.ts | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index b8495c93aa28..da309d141081 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -436,6 +436,31 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes callback registrations when trailing slash and URL fragments differ', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root/?cache=1#first',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root#second',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('slash-fragment-normalized-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:slash-fragment-normalized-action',
+ }),
+ }),
+ );
+ });
+
it('dedupes root callback registrations for origin with and without slash', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008', 'rscRemote');
From 3b75a5c896f9e3986452cb5295fad0e692ff5309 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:42:46 +0000
Subject: [PATCH 218/324] test(rsc-mf): cover default-port callback URL
normalization
---
.../tests/registerServerCallback.test.ts | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index da309d141081..c5e6285d1a76 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -461,6 +461,32 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes callback registrations when only default http port differs', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:80/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('default-http-port-normalized-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action':
+ 'remote:rscRemote:default-http-port-normalized-action',
+ }),
+ }),
+ );
+ });
+
it('dedupes root callback registrations for origin with and without slash', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008', 'rscRemote');
From e2ab44d60fe32b378102439894453da094641bd7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:46:09 +0000
Subject: [PATCH 219/324] refactor(rsc-mf): keep remote exposes as plain
userland strings
---
.../rsc-mf/remote/module-federation.config.ts | 14 +++-----------
.../rsc-mf/tests/moduleFederationConfig.test.ts | 2 +-
2 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/tests/integration/rsc-mf/remote/module-federation.config.ts b/tests/integration/rsc-mf/remote/module-federation.config.ts
index 33f06c5c81aa..a35e782553f7 100644
--- a/tests/integration/rsc-mf/remote/module-federation.config.ts
+++ b/tests/integration/rsc-mf/remote/module-federation.config.ts
@@ -1,9 +1,6 @@
import path from 'path';
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
-import {
- type ExposeDefinitionInput,
- createRscExposeDefinitions,
-} from './src/runtime/createRscExposeDefinitions';
+import { createRscExposeDefinitions } from './src/runtime/createRscExposeDefinitions';
const LAYERS = {
ssr: 'server-side-rendering',
@@ -18,7 +15,7 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
-const remoteExposeImports: Record = {
+const remoteExposeImports: Record = {
'./RemoteClientCounter': './src/components/RemoteClientCounter.tsx',
'./RemoteClientBadge': './src/components/RemoteClientBadge.tsx',
'./RemoteServerCard': './src/components/RemoteServerCard.tsx',
@@ -31,12 +28,7 @@ const remoteExposeImports: Record = {
'./nestedActions': './src/components/nestedActions.ts',
'./defaultAction': './src/components/defaultAction.ts',
'./actionBundle': './src/components/actionBundle.ts',
- './infoBundle': {
- import: [
- './src/components/infoBundle.ts',
- './src/components/infoBundle.ts',
- ],
- },
+ './infoBundle': './src/components/infoBundle.ts',
};
const sharedByScope = [
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 9778d9c8ae46..d5a0ebdf484a 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -139,7 +139,7 @@ describe('rsc-mf module federation config contracts', () => {
);
});
- it('deduplicates repeated imports in object expose definitions', () => {
+ it('normalizes string expose definitions into callback-bootstrapped imports', () => {
const remoteConfig = loadRemoteConfig();
const infoBundleExpose = remoteConfig.exposes?.['./infoBundle'] as
| {
From 21f7ed4024ce89d15980cf074ba2e1895ee4e7d5 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:51:41 +0000
Subject: [PATCH 220/324] test(rsc-mf): relax expose-contract checks to
behavior-level
---
.../tests/moduleFederationConfig.test.ts | 32 +++++++++++++------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index d5a0ebdf484a..89b541417e96 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -87,7 +87,7 @@ const loadHostConfig = ({
);
describe('rsc-mf module federation config contracts', () => {
- it('declares expected remote exposes with callback bootstrap imports', () => {
+ it('declares expected remote exposes with normalized userland imports', () => {
const remoteConfig = loadRemoteConfig();
const exposeEntries = Object.entries(remoteConfig.exposes || {});
const exposeKeys = exposeEntries
@@ -103,11 +103,14 @@ describe('rsc-mf module federation config contracts', () => {
expect(definition.layer).toBe('react-server-components');
expect(definition.import).toBeDefined();
expect(Array.isArray(definition.import)).toBe(true);
- expect(definition.import?.[0]).toBe(CALLBACK_BOOTSTRAP_IMPORT);
- expect(definition.import!.length).toBeGreaterThanOrEqual(2);
- for (const importPath of definition.import!.slice(1)) {
+ expect(definition.import!.length).toBeGreaterThanOrEqual(1);
+ const userlandImports = definition.import!.filter(
+ importPath => importPath !== CALLBACK_BOOTSTRAP_IMPORT,
+ );
+ expect(userlandImports.length).toBeGreaterThanOrEqual(1);
+ for (const importPath of userlandImports) {
expect(importPath).toMatch(/^\.\//);
- expect(importPath).not.toMatch(/^\.\/src\/runtime\//);
+ expect(importPath).toMatch(/^\.\/src\/components\//);
expect(importPath).toMatch(/\.[cm]?[jt]sx?$/i);
expect(importPath).not.toContain('..');
expect(importPath).not.toContain('\\');
@@ -139,17 +142,26 @@ describe('rsc-mf module federation config contracts', () => {
);
});
- it('normalizes string expose definitions into callback-bootstrapped imports', () => {
+ it('normalizes string expose definitions into deterministic userland imports', () => {
const remoteConfig = loadRemoteConfig();
const infoBundleExpose = remoteConfig.exposes?.['./infoBundle'] as
| {
import?: string[];
}
| undefined;
- expect(infoBundleExpose?.import).toEqual([
- CALLBACK_BOOTSTRAP_IMPORT,
- './src/components/infoBundle.ts',
- ]);
+ const imports = infoBundleExpose?.import || [];
+ expect(
+ imports.filter(
+ importPath => importPath === './src/components/infoBundle.ts',
+ ),
+ ).toEqual(['./src/components/infoBundle.ts']);
+ expect(
+ imports.every(
+ importPath =>
+ importPath === './src/components/infoBundle.ts' ||
+ importPath === CALLBACK_BOOTSTRAP_IMPORT,
+ ),
+ ).toBe(true);
});
it('uses remote port env var in host manifest remote URL', () => {
From 51d9f5975aef95530d768b01ef0ece0420158a45 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:52:59 +0000
Subject: [PATCH 221/324] test(rsc-mf): cover default https-port callback
normalization
---
.../tests/registerServerCallback.test.ts | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index c5e6285d1a76..2b225ceb05e8 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -487,6 +487,32 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes callback registrations when only default https port differs', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'https://example.com:443/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'https://example.com/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('default-https-port-normalized-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'https://example.com/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action':
+ 'remote:rscRemote:default-https-port-normalized-action',
+ }),
+ }),
+ );
+ });
+
it('dedupes root callback registrations for origin with and without slash', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008', 'rscRemote');
From de556c1aebd8244666c121af741e6e2790a7b789 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 08:59:48 +0000
Subject: [PATCH 222/324] test(rsc-mf): assert callback rebind when endpoint
port changes
---
.../tests/registerServerCallback.test.ts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index 2b225ceb05e8..d93169deb6bb 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -588,6 +588,34 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('re-registers callback when callback port changes', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3008/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://127.0.0.1:3010/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(2);
+
+ const callback = mockSetServerCallback.mock.calls[1]?.[0] as
+ | ServerCallback
+ | undefined;
+ expect(typeof callback).toBe('function');
+ await (callback as ServerCallback)('port-change-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3010/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:port-change-action',
+ }),
+ }),
+ );
+ });
+
it('trims alias before callback keying and action prefixing', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback(
From 44f2ead62182298b24dd9e23e0bd01341dde521b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:03:15 +0000
Subject: [PATCH 223/324] refactor(rsc-mf): keep host remote public-path plugin
always on
---
tests/integration/rsc-mf/host/module-federation.config.ts | 7 +++----
.../rsc-mf/tests/moduleFederationConfig.test.ts | 7 +++++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/host/module-federation.config.ts b/tests/integration/rsc-mf/host/module-federation.config.ts
index 6c1f6e3eb7f2..c375f3fca69b 100644
--- a/tests/integration/rsc-mf/host/module-federation.config.ts
+++ b/tests/integration/rsc-mf/host/module-federation.config.ts
@@ -15,10 +15,9 @@ const reactDomServerImport = path.join(
'react-dom.react-server.js',
);
const reactServerDomClientImport = 'react-server-dom-rspack/client.browser';
-const runtimePlugins =
- process.env.NODE_ENV === 'production'
- ? [path.resolve(__dirname, './runtime/forceRemotePublicPath.ts')]
- : [];
+const runtimePlugins = [
+ path.resolve(__dirname, './runtime/forceRemotePublicPath.ts'),
+];
const sharedByScope = [
{
diff --git a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
index 89b541417e96..5f583f3b62a0 100644
--- a/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/moduleFederationConfig.test.ts
@@ -187,7 +187,7 @@ describe('rsc-mf module federation config contracts', () => {
);
});
- it('enables host runtime plugin only in production', () => {
+ it('keeps host remote-public-path runtime plugin enabled across modes', () => {
const productionHostConfig = loadHostConfig({
nodeEnv: 'production',
remotePort: '3008',
@@ -201,7 +201,10 @@ describe('rsc-mf module federation config contracts', () => {
nodeEnv: 'development',
remotePort: '3008',
});
- expect(developmentHostConfig.runtimePlugins).toEqual([]);
+ expect(developmentHostConfig.runtimePlugins).toHaveLength(1);
+ expect(developmentHostConfig.runtimePlugins[0]).toContain(
+ 'runtime/forceRemotePublicPath.ts',
+ );
});
it('keeps host experiments aligned for async startup and rsc', () => {
From 0b0942f9d411821c8a855a5f2b271ba852020b62 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:09:43 +0000
Subject: [PATCH 224/324] test(rsc-mf): assert browser expose-chunk coverage
---
tests/integration/rsc-mf/tests/index.test.ts | 30 ++++++++++++++++----
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/tests/integration/rsc-mf/tests/index.test.ts b/tests/integration/rsc-mf/tests/index.test.ts
index f98704cfe6f5..89151d6d5462 100644
--- a/tests/integration/rsc-mf/tests/index.test.ts
+++ b/tests/integration/rsc-mf/tests/index.test.ts
@@ -19,6 +19,15 @@ const HOST_RSC_URL = '/server-component-root';
const EXPECTED_ACTION_POSTS_PER_MODE = 24;
const EXPECTED_ACTION_POSTS_PER_FAMILY = 6;
const EXPECTED_UNIQUE_ACTION_IDS_PER_MODE = 4;
+const EXPECTED_BROWSER_EXPOSE_CHUNKS = [
+ '__federation_expose_RemoteClientCounter',
+ '__federation_expose_RemoteClientBadge',
+ '__federation_expose_actions',
+ '__federation_expose_nestedActions',
+ '__federation_expose_defaultAction',
+ '__federation_expose_actionBundle',
+ '__federation_expose_infoBundle',
+];
const EXPECTED_REMOTE_EXPOSE_PATHS = [
'./RemoteClientCounter',
'./RemoteClientBadge',
@@ -367,6 +376,7 @@ function runTests({ mode }: TestConfig) {
const actionRequestIds: string[] = [];
const actionRequestAcceptHeaders: string[] = [];
const registerCallbackExposeRequestUrls: string[] = [];
+ const browserExposeChunkRequests: string[] = [];
const failedNetworkRequests: FailedRequestRecord[] = [];
const failedBrowserRequests: FailedBrowserRequestRecord[] = [];
@@ -426,6 +436,10 @@ function runTests({ mode }: TestConfig) {
if (url.includes('__federation_expose_registerServerCallback')) {
registerCallbackExposeRequestUrls.push(url);
}
+ const exposeChunkMatch = url.match(/__federation_expose_[^./?#]+/);
+ if (exposeChunkMatch) {
+ browserExposeChunkRequests.push(exposeChunkMatch[0]);
+ }
if (request.method() !== 'POST' || !headers['x-rsc-action']) {
return;
}
@@ -499,13 +513,8 @@ function runTests({ mode }: TestConfig) {
expect(uniqueExposedPaths.length).toBeGreaterThan(0);
expect(uniqueExposedPaths).toContain('./RemoteClientCounter');
expect(
- uniqueExposedPaths.every(path =>
- EXPECTED_REMOTE_EXPOSE_PATHS.includes(path),
- ),
+ exposedPaths.every(path => EXPECTED_REMOTE_EXPOSE_PATHS.includes(path)),
).toBe(true);
- expect(uniqueExposedPaths.length).toBeLessThanOrEqual(
- EXPECTED_REMOTE_EXPOSE_PATHS.length,
- );
expect(
exposedPaths.every(path => !path.startsWith('./src/components/')),
).toBe(true);
@@ -525,6 +534,15 @@ function runTests({ mode }: TestConfig) {
actionRequestIds,
}));
+ it('should load expected federated expose chunks in browser', () => {
+ const uniqueExposeChunkRequests = Array.from(
+ new Set(browserExposeChunkRequests),
+ ).sort();
+ expect(uniqueExposeChunkRequests).toEqual(
+ expect.arrayContaining(EXPECTED_BROWSER_EXPOSE_CHUNKS),
+ );
+ });
+
it('should route remote actions through host endpoint', () => {
expect(actionRequestUrls.length).toBe(EXPECTED_ACTION_POSTS_PER_MODE);
expect(actionRequestUrls.length).toBe(actionRequestIds.length);
From 28690f1d3b0f22a987fb02b19c892225d0c549b8 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:16:41 +0000
Subject: [PATCH 225/324] test(rsc-mf): cover host federated asset proxy
middleware
---
.../rsc-mf/host/server/modern.server.ts | 2 +-
.../rsc-mf/tests/modernServerConfig.test.ts | 221 ++++++++++++++++++
.../tests/types/modern-js-server-runtime.d.ts | 8 +
3 files changed, 230 insertions(+), 1 deletion(-)
create mode 100644 tests/integration/rsc-mf/tests/modernServerConfig.test.ts
create mode 100644 tests/integration/rsc-mf/tests/types/modern-js-server-runtime.d.ts
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index 205dc82a6c87..c10cb09bf252 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -35,7 +35,7 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
}
const remoteUrl = `http://127.0.0.1:${remotePort}${pathname}${reqUrl.search}`;
- const upstream = await fetch(remoteUrl).catch(() => undefined);
+ const upstream = await fetch(remoteUrl).catch((): undefined => undefined);
if (!upstream || !upstream.ok) {
await next();
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
new file mode 100644
index 000000000000..7401ae77344f
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -0,0 +1,221 @@
+const HOST_SERVER_CONFIG_MODULE = '../host/server/modern.server';
+
+const withRemotePort = (remotePort: string | undefined, run: () => T): T => {
+ const previousRemotePort = process.env.RSC_MF_REMOTE_PORT;
+ if (typeof remotePort === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = remotePort;
+ }
+
+ try {
+ return run();
+ } finally {
+ if (typeof previousRemotePort === 'undefined') {
+ delete process.env.RSC_MF_REMOTE_PORT;
+ } else {
+ process.env.RSC_MF_REMOTE_PORT = previousRemotePort;
+ }
+ }
+};
+
+const loadHostServerConfig = () => {
+ jest.resetModules();
+ jest.doMock('@modern-js/server-runtime', () => ({
+ defineServerConfig: (config: unknown) => config,
+ }));
+
+ let config: any;
+ let loadError: unknown;
+ jest.isolateModules(() => {
+ try {
+ config = require(HOST_SERVER_CONFIG_MODULE).default;
+ } catch (error) {
+ loadError = error;
+ }
+ });
+ if (loadError) {
+ const message =
+ loadError instanceof Error
+ ? loadError.stack || loadError.message
+ : String(loadError);
+ throw new Error(`Failed to load host server config: ${message}`);
+ }
+ return config;
+};
+
+const getProxyMiddlewareHandler = () => {
+ const config = loadHostServerConfig();
+ if (!Array.isArray(config.middlewares)) {
+ throw new Error('Host server config did not provide a middlewares array');
+ }
+ const middleware = config.middlewares.find(
+ (entry: { name?: string }) =>
+ entry.name === 'proxy-remote-federation-asset',
+ );
+ if (!middleware) {
+ throw new Error('proxy-remote-federation-asset middleware not found');
+ }
+ expect(middleware.order).toBe('pre');
+ expect(middleware.before).toEqual(['server-static']);
+ expect(typeof middleware.handler).toBe('function');
+ return middleware.handler as (
+ c: { req: { url: string }; res?: Response },
+ next: () => Promise,
+ ) => Promise;
+};
+
+describe('rsc-mf host modern.server middleware contracts', () => {
+ const originalFetch = global.fetch;
+ const originalFetchDescriptor = Object.getOwnPropertyDescriptor(
+ global,
+ 'fetch',
+ );
+
+ const installFetchMock = (implementation: typeof fetch) => {
+ const fetchMock = jest.fn(implementation);
+ Object.defineProperty(global, 'fetch', {
+ value: fetchMock,
+ configurable: true,
+ writable: true,
+ });
+ return fetchMock;
+ };
+
+ afterAll(() => {
+ if (originalFetchDescriptor) {
+ Object.defineProperty(global, 'fetch', originalFetchDescriptor);
+ return;
+ }
+ global.fetch = originalFetch;
+ });
+
+ it('proxies federated async JS expose chunks to remote origin', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(async () => {
+ return new Response('proxied-js', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ });
+ });
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_infoBundle.11dea89e81.js?cache=1',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_infoBundle.11dea89e81.js?cache=1',
+ );
+ expect(next).not.toHaveBeenCalled();
+ expect(context.res).toBeInstanceOf(Response);
+ await expect(context.res?.text()).resolves.toBe('proxied-js');
+ });
+
+ it('proxies federated async CSS expose chunks to remote origin', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(async () => {
+ return new Response('.remote-style{}', {
+ status: 200,
+ headers: {
+ 'content-type': 'text/css',
+ },
+ });
+ });
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/css/async/__federation_expose_RemoteClientCounter.9f773de2aa.css',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3999/static/css/async/__federation_expose_RemoteClientCounter.9f773de2aa.css',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('.remote-style{}');
+ });
+
+ it('falls through when request path is outside federated asset patterns', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ async () => new Response('ignored', { status: 200 }),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/server-component-root.abc123.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).not.toHaveBeenCalled();
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
+
+ it('falls through when remote port is not configured', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ async () => new Response('ignored', { status: 200 }),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_actions.44d8f1d7ae.js',
+ },
+ };
+
+ await withRemotePort(undefined, () => handler(context, next));
+
+ expect(fetchMock).not.toHaveBeenCalled();
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
+
+ it('falls through when upstream returns non-ok response', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ async () => new Response('not-found', { status: 404 }),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_actions.44d8f1d7ae.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
+
+ it('falls through when upstream fetch throws', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(async () => {
+ throw new Error('upstream-unreachable');
+ });
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_actionBundle.c842b162f4.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
+});
diff --git a/tests/integration/rsc-mf/tests/types/modern-js-server-runtime.d.ts b/tests/integration/rsc-mf/tests/types/modern-js-server-runtime.d.ts
new file mode 100644
index 000000000000..cd6fce867d72
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/types/modern-js-server-runtime.d.ts
@@ -0,0 +1,8 @@
+declare module '@modern-js/server-runtime' {
+ export type MiddlewareHandler = (
+ c: { req: { url: string }; res?: Response },
+ next: () => Promise,
+ ) => Promise | void;
+
+ export function defineServerConfig(config: T): T;
+}
From 8d4cb534b208c1f095e534fa67e842f57a2ae117 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:18:57 +0000
Subject: [PATCH 226/324] test(rsc-mf): validate forceRemotePublicPath runtime
plugin behavior
---
.../tests/forceRemotePublicPath.test.ts | 103 ++++++++++++++++++
1 file changed, 103 insertions(+)
create mode 100644 tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
diff --git a/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
new file mode 100644
index 000000000000..aad8d617d0d1
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
@@ -0,0 +1,103 @@
+import forceRemotePublicPath from '../host/runtime/forceRemotePublicPath';
+
+describe('host forceRemotePublicPath runtime plugin', () => {
+ it('keeps plugin name stable', () => {
+ const plugin = forceRemotePublicPath();
+ expect(plugin.name).toBe('rsc-mf-force-remote-public-path');
+ expect(typeof plugin.loadRemoteSnapshot).toBe('function');
+ });
+
+ it('does not mutate non-target remotes', () => {
+ const plugin = forceRemotePublicPath();
+ const args = {
+ remoteInfo: {
+ alias: 'anotherRemote',
+ entry: 'http://127.0.0.1:3008/static/mf-manifest.json',
+ },
+ remoteSnapshot: {
+ publicPath: 'http://example.com/',
+ },
+ };
+
+ const result = plugin.loadRemoteSnapshot?.(args as any);
+ expect(result).toBe(args);
+ expect(args.remoteSnapshot.publicPath).toBe('http://example.com/');
+ });
+
+ it('does not mutate when entry is missing or non-string', () => {
+ const plugin = forceRemotePublicPath();
+ const argsWithoutEntry = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ },
+ remoteSnapshot: {
+ publicPath: 'http://example.com/',
+ },
+ };
+ const argsWithNonStringEntry = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ entry: 1234,
+ },
+ remoteSnapshot: {
+ publicPath: 'http://example.com/',
+ },
+ };
+
+ plugin.loadRemoteSnapshot?.(argsWithoutEntry as any);
+ plugin.loadRemoteSnapshot?.(argsWithNonStringEntry as any);
+
+ expect(argsWithoutEntry.remoteSnapshot.publicPath).toBe(
+ 'http://example.com/',
+ );
+ expect(argsWithNonStringEntry.remoteSnapshot.publicPath).toBe(
+ 'http://example.com/',
+ );
+ });
+
+ it('forces origin-based public paths for rscRemote snapshots', () => {
+ const plugin = forceRemotePublicPath();
+ const args = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ entry: 'http://127.0.0.1:3008/static/mf-manifest.json',
+ },
+ remoteSnapshot: {
+ publicPath: 'http://example.com/static/',
+ metaData: {
+ publicPath: 'http://example.com/static/',
+ ssrPublicPath: 'http://example.com/static/bundles/',
+ },
+ },
+ };
+
+ const result = plugin.loadRemoteSnapshot?.(args as any);
+
+ expect(result).toBe(args);
+ expect(args.remoteSnapshot.publicPath).toBe('http://127.0.0.1:3008/');
+ expect(args.remoteSnapshot.metaData.publicPath).toBe(
+ 'http://127.0.0.1:3008/',
+ );
+ expect(args.remoteSnapshot.metaData.ssrPublicPath).toBe(
+ 'http://127.0.0.1:3008/bundles/',
+ );
+ });
+
+ it('only updates snapshot fields that exist', () => {
+ const plugin = forceRemotePublicPath();
+ const args = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ entry: 'https://remote.example.com/static/mf-manifest.json',
+ },
+ remoteSnapshot: {
+ metaData: {},
+ },
+ };
+
+ plugin.loadRemoteSnapshot?.(args as any);
+
+ expect('publicPath' in args.remoteSnapshot).toBe(false);
+ expect(args.remoteSnapshot.metaData).toEqual({});
+ });
+});
From 1b8615c0e067fb90800e70a1cc05fb7235f8ba74 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:21:59 +0000
Subject: [PATCH 227/324] test(rsc-mf): cover callback URL host-casing
normalization
---
.../tests/registerServerCallback.test.ts | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
index d93169deb6bb..33c0779d7785 100644
--- a/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
+++ b/tests/integration/rsc-mf/tests/registerServerCallback.test.ts
@@ -513,6 +513,31 @@ describe('registerRemoteServerCallback runtime behavior', () => {
);
});
+ it('dedupes callback registrations when host casing differs', async () => {
+ const { registerRemoteServerCallback } = await importRegisterHelper();
+ registerRemoteServerCallback(
+ 'HTTP://LOCALHOST:3008/server-component-root',
+ 'rscRemote',
+ );
+ registerRemoteServerCallback(
+ 'http://localhost:3008/server-component-root',
+ 'rscRemote',
+ );
+ expect(mockSetServerCallback).toHaveBeenCalledTimes(1);
+
+ const callback = getRegisteredCallback();
+ await callback('host-casing-normalized-action', []);
+
+ expect(global.fetch).toHaveBeenCalledWith(
+ 'http://localhost:3008/server-component-root',
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'x-rsc-action': 'remote:rscRemote:host-casing-normalized-action',
+ }),
+ }),
+ );
+ });
+
it('dedupes root callback registrations for origin with and without slash', async () => {
const { registerRemoteServerCallback } = await importRegisterHelper();
registerRemoteServerCallback('http://127.0.0.1:3008', 'rscRemote');
From 95bf06c663cb86287c0f454acb8138bfaccfdc0d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:23:40 +0000
Subject: [PATCH 228/324] test(rsc-mf): cover remote entry URL normalization in
runtime plugin
---
.../tests/forceRemotePublicPath.test.ts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
index aad8d617d0d1..cb07cac02bbd 100644
--- a/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
+++ b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
@@ -83,6 +83,34 @@ describe('host forceRemotePublicPath runtime plugin', () => {
);
});
+ it('normalizes entry URL query, hash, and default port in rewritten paths', () => {
+ const plugin = forceRemotePublicPath();
+ const args = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ entry:
+ 'https://remote.example.com:443/static/mf-manifest.json?cache=1#v',
+ },
+ remoteSnapshot: {
+ publicPath: 'https://stale.example.com/static/',
+ metaData: {
+ publicPath: 'https://stale.example.com/static/',
+ ssrPublicPath: 'https://stale.example.com/static/bundles/',
+ },
+ },
+ };
+
+ plugin.loadRemoteSnapshot?.(args as any);
+
+ expect(args.remoteSnapshot.publicPath).toBe('https://remote.example.com/');
+ expect(args.remoteSnapshot.metaData.publicPath).toBe(
+ 'https://remote.example.com/',
+ );
+ expect(args.remoteSnapshot.metaData.ssrPublicPath).toBe(
+ 'https://remote.example.com/bundles/',
+ );
+ });
+
it('only updates snapshot fields that exist', () => {
const plugin = forceRemotePublicPath();
const args = {
From 57ba0af3c076a2a8649887001df8c960f5c1eb5b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:26:38 +0000
Subject: [PATCH 229/324] test(rsc-mf): cover additional federated asset proxy
path markers
---
.../rsc-mf/tests/modernServerConfig.test.ts | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 7401ae77344f..884c0fdbcf58 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -143,6 +143,58 @@ describe('rsc-mf host modern.server middleware contracts', () => {
await expect(context.res?.text()).resolves.toBe('.remote-style{}');
});
+ it('proxies async JS chunks with react server component marker', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(async () => {
+ return new Response('proxied-rsc-chunk', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ });
+ });
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/503_react-server-components_0f2d4f91.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3999/static/js/async/503_react-server-components_0f2d4f91.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('proxied-rsc-chunk');
+ });
+
+ it('proxies async JS chunks containing node_modules react markers', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(async () => {
+ return new Response('proxied-react-chunk', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ });
+ });
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/node_modules_pnpm_react_19.0.0_react-dom_19.0.0.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3999/static/js/async/node_modules_pnpm_react_19.0.0_react-dom_19.0.0.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('proxied-react-chunk');
+ });
+
it('falls through when request path is outside federated asset patterns', async () => {
const handler = getProxyMiddlewareHandler();
const next = jest.fn(async (): Promise => undefined);
From b04a9b4cd18a197a6dbf3c87833b676f1fc6bb26 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:28:30 +0000
Subject: [PATCH 230/324] fix(rsc-mf): ignore malformed remote entry URLs in
runtime plugin
---
.../host/runtime/forceRemotePublicPath.ts | 13 ++++++++-
.../tests/forceRemotePublicPath.test.ts | 27 +++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/host/runtime/forceRemotePublicPath.ts b/tests/integration/rsc-mf/host/runtime/forceRemotePublicPath.ts
index 8945fb778d8e..0e074972eb84 100644
--- a/tests/integration/rsc-mf/host/runtime/forceRemotePublicPath.ts
+++ b/tests/integration/rsc-mf/host/runtime/forceRemotePublicPath.ts
@@ -1,5 +1,13 @@
import type { ModuleFederationRuntimePlugin } from '@module-federation/modern-js-v3';
+const getRemotePublicPath = (entry: string) => {
+ try {
+ return `${new URL(entry).origin}/`;
+ } catch {
+ return undefined;
+ }
+};
+
const forceRemotePublicPath = (): ModuleFederationRuntimePlugin => ({
name: 'rsc-mf-force-remote-public-path',
loadRemoteSnapshot(args: any) {
@@ -12,7 +20,10 @@ const forceRemotePublicPath = (): ModuleFederationRuntimePlugin => ({
if (!entry || typeof entry !== 'string') {
return args;
}
- const remotePublicPath = `${new URL(entry).origin}/`;
+ const remotePublicPath = getRemotePublicPath(entry);
+ if (!remotePublicPath) {
+ return args;
+ }
if ('publicPath' in remoteSnapshot) {
remoteSnapshot.publicPath = remotePublicPath;
diff --git a/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
index cb07cac02bbd..af991850185c 100644
--- a/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
+++ b/tests/integration/rsc-mf/tests/forceRemotePublicPath.test.ts
@@ -55,6 +55,33 @@ describe('host forceRemotePublicPath runtime plugin', () => {
);
});
+ it('does not mutate when entry is not a valid URL', () => {
+ const plugin = forceRemotePublicPath();
+ const args = {
+ remoteInfo: {
+ alias: 'rscRemote',
+ entry: 'http://',
+ },
+ remoteSnapshot: {
+ publicPath: 'http://example.com/static/',
+ metaData: {
+ publicPath: 'http://example.com/static/',
+ ssrPublicPath: 'http://example.com/static/bundles/',
+ },
+ },
+ };
+
+ plugin.loadRemoteSnapshot?.(args as any);
+
+ expect(args.remoteSnapshot.publicPath).toBe('http://example.com/static/');
+ expect(args.remoteSnapshot.metaData.publicPath).toBe(
+ 'http://example.com/static/',
+ );
+ expect(args.remoteSnapshot.metaData.ssrPublicPath).toBe(
+ 'http://example.com/static/bundles/',
+ );
+ });
+
it('forces origin-based public paths for rscRemote snapshots', () => {
const plugin = forceRemotePublicPath();
const args = {
From 22b8c20743daf6b7792bf1213a5790e201f05352 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:32:31 +0000
Subject: [PATCH 231/324] fix(rsc-mf): add manifest fallback for stale expose
chunk paths
---
.../rsc-mf/host/server/modern.server.ts | 137 +++++++++++++++++-
.../rsc-mf/tests/modernServerConfig.test.ts | 80 +++++++++-
2 files changed, 210 insertions(+), 7 deletions(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index c10cb09bf252..d84702202c06 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -3,6 +3,124 @@ import {
defineServerConfig,
} from '@modern-js/server-runtime';
+const REMOTE_MANIFEST_PATH = '/static/mf-manifest.json';
+const EXPOSE_CHUNK_HASH_SUFFIX_PATTERN = /\.[a-f0-9]{6,}$/i;
+
+interface RemoteManifestAssetEntry {
+ assets?: {
+ js?: {
+ sync?: string[];
+ async?: string[];
+ };
+ css?: {
+ sync?: string[];
+ async?: string[];
+ };
+ };
+}
+
+interface RemoteManifestShape {
+ shared?: RemoteManifestAssetEntry[];
+ exposes?: RemoteManifestAssetEntry[];
+}
+
+const toCanonicalChunkName = (filePath: string) =>
+ filePath
+ .replace(/\/+$/, '')
+ .split('/')
+ .pop()
+ ?.replace(/\.(js|css)$/i, '')
+ .replace(EXPOSE_CHUNK_HASH_SUFFIX_PATTERN, '');
+
+const collectManifestAssetPaths = (manifest: RemoteManifestShape) => {
+ const entries = [...(manifest.shared || []), ...(manifest.exposes || [])];
+ const assetPaths = new Set();
+ for (const entry of entries) {
+ const jsSyncAssets = entry.assets?.js?.sync || [];
+ const jsAsyncAssets = entry.assets?.js?.async || [];
+ const cssSyncAssets = entry.assets?.css?.sync || [];
+ const cssAsyncAssets = entry.assets?.css?.async || [];
+ for (const assetPath of [
+ ...jsSyncAssets,
+ ...jsAsyncAssets,
+ ...cssSyncAssets,
+ ...cssAsyncAssets,
+ ]) {
+ assetPaths.add(assetPath);
+ }
+ }
+ return [...assetPaths];
+};
+
+const resolveManifestFallbackAssetPath = (
+ pathname: string,
+ manifest: RemoteManifestShape,
+) => {
+ if (
+ !pathname.includes('__federation_expose_') ||
+ (!pathname.endsWith('.js') && !pathname.endsWith('.css'))
+ ) {
+ return undefined;
+ }
+
+ const canonicalRequestedChunkName = toCanonicalChunkName(pathname);
+ if (!canonicalRequestedChunkName) {
+ return undefined;
+ }
+
+ const requestedAssetDirectory = pathname.includes('/static/css/async/')
+ ? 'static/css/async/'
+ : 'static/js/async/';
+ const manifestAssets = collectManifestAssetPaths(manifest);
+ return manifestAssets.find(assetPath => {
+ if (!assetPath.startsWith(requestedAssetDirectory)) {
+ return false;
+ }
+ return toCanonicalChunkName(assetPath) === canonicalRequestedChunkName;
+ });
+};
+
+const fetchRemoteManifestFallbackAsset = async ({
+ remoteOrigin,
+ pathname,
+ search,
+}: {
+ remoteOrigin: string;
+ pathname: string;
+ search: string;
+}) => {
+ const manifestResponse = await fetch(`${remoteOrigin}${REMOTE_MANIFEST_PATH}`)
+ .then(response => {
+ if (!response.ok) {
+ return undefined;
+ }
+ return response;
+ })
+ .catch((): undefined => undefined);
+
+ if (!manifestResponse) {
+ return undefined;
+ }
+
+ const manifest = (await manifestResponse.json()) as RemoteManifestShape;
+ const fallbackAssetPath = resolveManifestFallbackAssetPath(
+ pathname,
+ manifest,
+ );
+ if (!fallbackAssetPath) {
+ return undefined;
+ }
+
+ const fallbackAssetUrl = `${remoteOrigin}/${fallbackAssetPath}${search}`;
+ const fallbackAssetResponse = await fetch(fallbackAssetUrl).catch(
+ (): undefined => undefined,
+ );
+ if (!fallbackAssetResponse || !fallbackAssetResponse.ok) {
+ return undefined;
+ }
+ return fallbackAssetResponse;
+};
+
const shouldProxyRemoteAsset = (pathname: string) => {
if (pathname.startsWith('/static/js/async/')) {
return (
@@ -34,17 +152,26 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
return;
}
- const remoteUrl = `http://127.0.0.1:${remotePort}${pathname}${reqUrl.search}`;
+ const remoteOrigin = `http://127.0.0.1:${remotePort}`;
+ const remoteUrl = `${remoteOrigin}${pathname}${reqUrl.search}`;
const upstream = await fetch(remoteUrl).catch((): undefined => undefined);
- if (!upstream || !upstream.ok) {
+ const resolvedUpstream = upstream?.ok
+ ? upstream
+ : await fetchRemoteManifestFallbackAsset({
+ remoteOrigin,
+ pathname,
+ search: reqUrl.search,
+ });
+
+ if (!resolvedUpstream || !resolvedUpstream.ok) {
await next();
return;
}
- c.res = new Response(await upstream.arrayBuffer(), {
- status: upstream.status,
- headers: upstream.headers,
+ c.res = new Response(await resolvedUpstream.arrayBuffer(), {
+ status: resolvedUpstream.status,
+ headers: resolvedUpstream.headers,
});
};
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 884c0fdbcf58..3d155dfd1ee5 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -247,7 +247,11 @@ describe('rsc-mf host modern.server middleware contracts', () => {
await withRemotePort('3999', () => handler(context, next));
- expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
expect(next).toHaveBeenCalledTimes(1);
expect(context.res).toBeUndefined();
});
@@ -266,8 +270,80 @@ describe('rsc-mf host modern.server middleware contracts', () => {
await withRemotePort('3999', () => handler(context, next));
- expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
expect(next).toHaveBeenCalledTimes(1);
expect(context.res).toBeUndefined();
});
+
+ it('recovers from stale expose chunk path via manifest-driven fallback', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'static/js/async/__federation_expose_RemoteServerCard.6e997e54ed.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteServerCard.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteServerCard.js',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteServerCard.6e997e54ed.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('fallback-hit');
+ });
});
From 9dcaef77e950371551afca0a96f097a5485de79f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:49:36 +0000
Subject: [PATCH 232/324] test(rsc-mf): cover shared-asset manifest fallback
resolution
---
.../rsc-mf/tests/modernServerConfig.test.ts | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 3d155dfd1ee5..43b21aceb23a 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -346,4 +346,72 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).not.toHaveBeenCalled();
await expect(context.res?.text()).resolves.toBe('fallback-hit');
});
+
+ it('recovers stale expose path when manifest match is under shared assets', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ shared: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('shared-fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.js',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('shared-fallback-hit');
+ });
});
From 40873029f93e2a83d26580579be6b287e952c4ad Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:51:27 +0000
Subject: [PATCH 233/324] test(rsc-mf): cover css stale-path manifest fallback
---
.../rsc-mf/tests/modernServerConfig.test.ts | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 43b21aceb23a..020e4de0b4d2 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -414,4 +414,72 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).not.toHaveBeenCalled();
await expect(context.res?.text()).resolves.toBe('shared-fallback-hit');
});
+
+ it('recovers stale CSS expose path via manifest-driven fallback', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [],
+ async: [],
+ },
+ css: {
+ sync: [
+ 'static/css/async/__federation_expose_RemoteClientCounter.9f773de2aa.css',
+ ],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('.fallback-style{}', {
+ status: 200,
+ headers: {
+ 'content-type': 'text/css',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/css/async/__federation_expose_RemoteClientCounter.css',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:3999/static/css/async/__federation_expose_RemoteClientCounter.css',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/css/async/__federation_expose_RemoteClientCounter.9f773de2aa.css',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('.fallback-style{}');
+ });
});
From bc6434c8c52363bea398b6c366097e0cdd8dfd6d Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:54:03 +0000
Subject: [PATCH 234/324] test(rsc-mf): assert no-match manifest fallback
passthrough
---
.../rsc-mf/tests/modernServerConfig.test.ts | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 020e4de0b4d2..d4eaff3b3c26 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -482,4 +482,61 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).not.toHaveBeenCalled();
await expect(context.res?.text()).resolves.toBe('.fallback-style{}');
});
+
+ it('falls through when manifest lookup has no matching fallback asset', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'static/js/async/__federation_expose_other.abc123.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteServerCard.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 1,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteServerCard.js',
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ 'http://127.0.0.1:3999/static/mf-manifest.json',
+ );
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
});
From 800c14c42f1cd43fac4fd23120e13efc122fb45b Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:55:46 +0000
Subject: [PATCH 235/324] fix(rsc-mf): tolerate invalid remote manifest
fallback payloads
---
.../rsc-mf/host/server/modern.server.ts | 7 ++++-
.../rsc-mf/tests/modernServerConfig.test.ts | 29 +++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index d84702202c06..e8be793692af 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -102,7 +102,12 @@ const fetchRemoteManifestFallbackAsset = async ({
return undefined;
}
- const manifest = (await manifestResponse.json()) as RemoteManifestShape;
+ const manifest = (await manifestResponse
+ .json()
+ .catch((): undefined => undefined)) as RemoteManifestShape | undefined;
+ if (!manifest) {
+ return undefined;
+ }
const fallbackAssetPath = resolveManifestFallbackAssetPath(
pathname,
manifest,
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index d4eaff3b3c26..cbc236ca4048 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -539,4 +539,33 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).toHaveBeenCalledTimes(1);
expect(context.res).toBeUndefined();
});
+
+ it('falls through when manifest response body is invalid JSON', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response('not-json-manifest', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteServerCard.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
});
From 9b627099545a2a80bf4c44ea61c10fa2e77788e7 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 09:57:22 +0000
Subject: [PATCH 236/324] test(rsc-mf): cover manifest-fetch failure
passthrough
---
.../rsc-mf/tests/modernServerConfig.test.ts | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index cbc236ca4048..5c5a803ffe8f 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -568,4 +568,26 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).toHaveBeenCalledTimes(1);
expect(context.res).toBeUndefined();
});
+
+ it('falls through when manifest request throws after stale asset miss', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockRejectedValueOnce(new Error('manifest-fetch-failed')),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteServerCard.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
});
From 8b96753dbdbe16703f4f449cd2a44df1d5679060 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 10:00:45 +0000
Subject: [PATCH 237/324] test(rsc-mf): extend manifest fallback query and
async-asset coverage
---
.../rsc-mf/tests/modernServerConfig.test.ts | 120 ++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 5c5a803ffe8f..5b0623c94fa8 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -590,4 +590,124 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).toHaveBeenCalledTimes(1);
expect(context.res).toBeUndefined();
});
+
+ it('preserves query string when retrying manifest-resolved fallback asset', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('query-fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js?cache=1&v=2',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js?cache=1&v=2',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('query-fallback-hit');
+ });
+
+ it('resolves fallback asset paths from manifest async asset arrays', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ shared: [
+ {
+ assets: {
+ js: {
+ sync: [],
+ async: [
+ 'static/js/async/__federation_expose_nestedActions.a8ce95b11a.js',
+ ],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('async-array-fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_nestedActions.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_nestedActions.a8ce95b11a.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe('async-array-fallback-hit');
+ });
});
From 3a11926d4ca0dac83692f7e83f79bb01c153fc7f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 10:03:26 +0000
Subject: [PATCH 238/324] refactor(rsc-mf): skip manifest fallback for
non-expose proxy paths
---
.../rsc-mf/host/server/modern.server.ts | 13 ++++++----
.../rsc-mf/tests/modernServerConfig.test.ts | 24 +++++++++++++++++++
2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index e8be793692af..00f59a4d30c2 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -24,6 +24,10 @@ interface RemoteManifestShape {
exposes?: RemoteManifestAssetEntry[];
}
+const isManifestFallbackEligiblePath = (pathname: string) =>
+ pathname.includes('__federation_expose_') &&
+ (pathname.endsWith('.js') || pathname.endsWith('.css'));
+
const toCanonicalChunkName = (filePath: string) =>
filePath
.replace(/\/+$/, '')
@@ -56,10 +60,7 @@ const resolveManifestFallbackAssetPath = (
pathname: string,
manifest: RemoteManifestShape,
) => {
- if (
- !pathname.includes('__federation_expose_') ||
- (!pathname.endsWith('.js') && !pathname.endsWith('.css'))
- ) {
+ if (!isManifestFallbackEligiblePath(pathname)) {
return undefined;
}
@@ -89,6 +90,10 @@ const fetchRemoteManifestFallbackAsset = async ({
pathname: string;
search: string;
}) => {
+ if (!isManifestFallbackEligiblePath(pathname)) {
+ return undefined;
+ }
+
const manifestResponse = await fetch(`${remoteOrigin}${REMOTE_MANIFEST_PATH}`)
.then(response => {
if (!response.ok) {
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 5b0623c94fa8..892883366837 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -710,4 +710,28 @@ describe('rsc-mf host modern.server middleware contracts', () => {
expect(next).not.toHaveBeenCalled();
await expect(context.res?.text()).resolves.toBe('async-array-fallback-hit');
});
+
+ it('does not attempt manifest fallback for non-expose marker chunk paths', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 })),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/503_react-server-components_0f2d4f91.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledWith(
+ 'http://127.0.0.1:3999/static/js/async/503_react-server-components_0f2d4f91.js',
+ );
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
});
From 4321302d3759e07e3e978320c72ef83eb5e4a961 Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 10:05:32 +0000
Subject: [PATCH 239/324] fix(rsc-mf): support alphanumeric fallback hash
suffix matching
---
.../rsc-mf/host/server/modern.server.ts | 2 +-
.../rsc-mf/tests/modernServerConfig.test.ts | 62 +++++++++++++++++++
2 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index 00f59a4d30c2..f198171ee51b 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -4,7 +4,7 @@ import {
} from '@modern-js/server-runtime';
const REMOTE_MANIFEST_PATH = '/static/mf-manifest.json';
-const EXPOSE_CHUNK_HASH_SUFFIX_PATTERN = /\.[a-f0-9]{6,}$/i;
+const EXPOSE_CHUNK_HASH_SUFFIX_PATTERN = /\.[a-z0-9]{6,}$/i;
interface RemoteManifestAssetEntry {
assets?: {
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index 892883366837..d453823105e0 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -651,6 +651,68 @@ describe('rsc-mf host modern.server middleware contracts', () => {
await expect(context.res?.text()).resolves.toBe('query-fallback-hit');
});
+ it('matches fallback chunks when manifest hash suffix includes non-hex characters', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'static/js/async/__federation_expose_RemoteServerCard.a1b2c3x9.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('non-hex-hash-fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteServerCard.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteServerCard.a1b2c3x9.js',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe(
+ 'non-hex-hash-fallback-hit',
+ );
+ });
+
it('resolves fallback asset paths from manifest async asset arrays', async () => {
const handler = getProxyMiddlewareHandler();
const next = jest.fn(async (): Promise => undefined);
From 18a81935df3883f5c25df71ae79d06bcbbe4f5cc Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 10:20:20 +0000
Subject: [PATCH 240/324] test(rsc-mf): harden manifest fallback URL resolution
---
.../rsc-mf/host/server/modern.server.ts | 59 +++++++++-
.../rsc-mf/tests/modernServerConfig.test.ts | 111 ++++++++++++++++++
2 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/tests/integration/rsc-mf/host/server/modern.server.ts b/tests/integration/rsc-mf/host/server/modern.server.ts
index f198171ee51b..7f8c701edb6e 100644
--- a/tests/integration/rsc-mf/host/server/modern.server.ts
+++ b/tests/integration/rsc-mf/host/server/modern.server.ts
@@ -36,6 +36,14 @@ const toCanonicalChunkName = (filePath: string) =>
?.replace(/\.(js|css)$/i, '')
.replace(EXPOSE_CHUNK_HASH_SUFFIX_PATTERN, '');
+const toNormalizedManifestAssetPath = (assetPath: string) => {
+ try {
+ return new URL(assetPath).pathname.replace(/^\/+/, '');
+ } catch {
+ return assetPath.replace(/^[./]+/, '').split(/[?#]/, 1)[0];
+ }
+};
+
const collectManifestAssetPaths = (manifest: RemoteManifestShape) => {
const entries = [...(manifest.shared || []), ...(manifest.exposes || [])];
const assetPaths = new Set();
@@ -74,13 +82,51 @@ const resolveManifestFallbackAssetPath = (
: 'static/js/async/';
const manifestAssets = collectManifestAssetPaths(manifest);
return manifestAssets.find(assetPath => {
- if (!assetPath.startsWith(requestedAssetDirectory)) {
+ const normalizedAssetPath = toNormalizedManifestAssetPath(assetPath);
+ if (!normalizedAssetPath.startsWith(requestedAssetDirectory)) {
return false;
}
- return toCanonicalChunkName(assetPath) === canonicalRequestedChunkName;
+ return (
+ toCanonicalChunkName(normalizedAssetPath) === canonicalRequestedChunkName
+ );
});
};
+const createManifestFallbackAssetUrl = ({
+ remoteOrigin,
+ fallbackAssetPath,
+ requestSearch,
+}: {
+ remoteOrigin: string;
+ fallbackAssetPath: string;
+ requestSearch: string;
+}) => {
+ let fallbackAssetUrl: URL;
+ try {
+ fallbackAssetUrl = new URL(fallbackAssetPath, `${remoteOrigin}/`);
+ } catch {
+ return undefined;
+ }
+
+ if (fallbackAssetUrl.origin !== new URL(remoteOrigin).origin) {
+ return undefined;
+ }
+
+ if (!requestSearch) {
+ return fallbackAssetUrl.toString();
+ }
+
+ const mergedSearchParams = new URLSearchParams(fallbackAssetUrl.search);
+ const requestSearchParams = new URLSearchParams(requestSearch);
+ for (const [key, value] of requestSearchParams.entries()) {
+ mergedSearchParams.set(key, value);
+ }
+ const mergedSearch = mergedSearchParams.toString();
+ fallbackAssetUrl.search = mergedSearch ? `?${mergedSearch}` : '';
+
+ return fallbackAssetUrl.toString();
+};
+
const fetchRemoteManifestFallbackAsset = async ({
remoteOrigin,
pathname,
@@ -121,7 +167,14 @@ const fetchRemoteManifestFallbackAsset = async ({
return undefined;
}
- const fallbackAssetUrl = `${remoteOrigin}/${fallbackAssetPath}${search}`;
+ const fallbackAssetUrl = createManifestFallbackAssetUrl({
+ remoteOrigin,
+ fallbackAssetPath,
+ requestSearch: search,
+ });
+ if (!fallbackAssetUrl) {
+ return undefined;
+ }
const fallbackAssetResponse = await fetch(fallbackAssetUrl).catch(
(): undefined => undefined,
);
diff --git a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
index d453823105e0..06045fe889d9 100644
--- a/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
+++ b/tests/integration/rsc-mf/tests/modernServerConfig.test.ts
@@ -651,6 +651,117 @@ describe('rsc-mf host modern.server middleware contracts', () => {
await expect(context.res?.text()).resolves.toBe('query-fallback-hit');
});
+ it('supports absolute manifest fallback asset URLs and merges request query params', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js?manifest=1',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ )
+ .mockResolvedValueOnce(
+ new Response('absolute-query-fallback-hit', {
+ status: 200,
+ headers: {
+ 'content-type': 'application/javascript',
+ },
+ }),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js?cache=1',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 3,
+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js?manifest=1&cache=1',
+ );
+ expect(next).not.toHaveBeenCalled();
+ await expect(context.res?.text()).resolves.toBe(
+ 'absolute-query-fallback-hit',
+ );
+ });
+
+ it('falls through when manifest fallback asset URL points to another origin', async () => {
+ const handler = getProxyMiddlewareHandler();
+ const next = jest.fn(async (): Promise => undefined);
+ const fetchMock = installFetchMock(
+ jest
+ .fn()
+ .mockResolvedValueOnce(new Response('not-found', { status: 404 }))
+ .mockResolvedValueOnce(
+ new Response(
+ JSON.stringify({
+ exposes: [
+ {
+ assets: {
+ js: {
+ sync: [
+ 'https://cdn.example.com/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js',
+ ],
+ async: [],
+ },
+ css: {
+ sync: [],
+ async: [],
+ },
+ },
+ },
+ ],
+ }),
+ {
+ status: 200,
+ headers: {
+ 'content-type': 'application/json',
+ },
+ },
+ ),
+ ),
+ );
+ const context: { req: { url: string }; res?: Response } = {
+ req: {
+ url: 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js',
+ },
+ };
+
+ await withRemotePort('3999', () => handler(context, next));
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(next).toHaveBeenCalledTimes(1);
+ expect(context.res).toBeUndefined();
+ });
+
it('matches fallback chunks when manifest hash suffix includes non-hex characters', async () => {
const handler = getProxyMiddlewareHandler();
const next = jest.fn(async (): Promise => undefined);
From 260278b5afae4fb26ac3dd19c0bccd63d978642f Mon Sep 17 00:00:00 2001
From: Cursor Agent
Date: Sat, 14 Feb 2026 10:26:04 +0000
Subject: [PATCH 241/324] feat(rsc-mf): add remote expose-asset fallback
middleware
---
.../rsc-mf/remote/server/modern.server.ts | 216 ++++++++++++++++
.../tests/remoteModernServerConfig.test.ts | 244 ++++++++++++++++++
.../tests/types/modern-js-server-runtime.d.ts | 9 +-
3 files changed, 468 insertions(+), 1 deletion(-)
create mode 100644 tests/integration/rsc-mf/remote/server/modern.server.ts
create mode 100644 tests/integration/rsc-mf/tests/remoteModernServerConfig.test.ts
diff --git a/tests/integration/rsc-mf/remote/server/modern.server.ts b/tests/integration/rsc-mf/remote/server/modern.server.ts
new file mode 100644
index 000000000000..dd8263a7df3a
--- /dev/null
+++ b/tests/integration/rsc-mf/remote/server/modern.server.ts
@@ -0,0 +1,216 @@
+import {
+ type MiddlewareHandler,
+ defineServerConfig,
+} from '@modern-js/server-runtime';
+
+const INTERNAL_FALLBACK_HEADER = 'x-rsc-mf-internal-fallback';
+const REMOTE_MANIFEST_PATH = '/static/mf-manifest.json';
+const EXPOSE_CHUNK_HASH_SUFFIX_PATTERN = /\.[a-z0-9]{6,}$/i;
+
+interface RemoteManifestAssetEntry {
+ assets?: {
+ js?: {
+ sync?: string[];
+ async?: string[];
+ };
+ css?: {
+ sync?: string[];
+ async?: string[];
+ };
+ };
+}
+
+interface RemoteManifestShape {
+ shared?: RemoteManifestAssetEntry[];
+ exposes?: RemoteManifestAssetEntry[];
+}
+
+const isExposeAssetRequestPath = (pathname: string) =>
+ pathname.includes('__federation_expose_') &&
+ (pathname.endsWith('.js') || pathname.endsWith('.css'));
+
+const toCanonicalChunkName = (filePath: string) =>
+ filePath
+ .replace(/\/+$/, '')
+ .split('/')
+ .pop()
+ ?.replace(/\.(js|css)$/i, '')
+ .replace(EXPOSE_CHUNK_HASH_SUFFIX_PATTERN, '');
+
+const toNormalizedManifestAssetPath = (assetPath: string) => {
+ try {
+ return new URL(assetPath).pathname.replace(/^\/+/, '');
+ } catch {
+ return assetPath.replace(/^[./]+/, '').split(/[?#]/, 1)[0];
+ }
+};
+
+const collectManifestAssetPaths = (manifest: RemoteManifestShape) => {
+ const entries = [...(manifest.shared || []), ...(manifest.exposes || [])];
+ const assetPaths = new Set();
+ for (const entry of entries) {
+ const jsSyncAssets = entry.assets?.js?.sync || [];
+ const jsAsyncAssets = entry.assets?.js?.async || [];
+ const cssSyncAssets = entry.assets?.css?.sync || [];
+ const cssAsyncAssets = entry.assets?.css?.async || [];
+ for (const assetPath of [
+ ...jsSyncAssets,
+ ...jsAsyncAssets,
+ ...cssSyncAssets,
+ ...cssAsyncAssets,
+ ]) {
+ assetPaths.add(assetPath);
+ }
+ }
+ return [...assetPaths];
+};
+
+const resolveManifestFallbackAssetPath = (
+ pathname: string,
+ manifest: RemoteManifestShape,
+) => {
+ if (!isExposeAssetRequestPath(pathname)) {
+ return undefined;
+ }
+
+ const canonicalRequestedChunkName = toCanonicalChunkName(pathname);
+ if (!canonicalRequestedChunkName) {
+ return undefined;
+ }
+
+ const requestedAssetDirectory = pathname.includes('/static/css/async/')
+ ? 'static/css/async/'
+ : 'static/js/async/';
+ const manifestAssets = collectManifestAssetPaths(manifest);
+ return manifestAssets.find(assetPath => {
+ const normalizedAssetPath = toNormalizedManifestAssetPath(assetPath);
+ if (!normalizedAssetPath.startsWith(requestedAssetDirectory)) {
+ return false;
+ }
+ return (
+ toCanonicalChunkName(normalizedAssetPath) === canonicalRequestedChunkName
+ );
+ });
+};
+
+const createManifestFallbackAssetUrl = ({
+ remoteOrigin,
+ fallbackAssetPath,
+ requestSearch,
+}: {
+ remoteOrigin: string;
+ fallbackAssetPath: string;
+ requestSearch: string;
+}) => {
+ let fallbackAssetUrl: URL;
+ try {
+ fallbackAssetUrl = new URL(fallbackAssetPath, `${remoteOrigin}/`);
+ } catch {
+ return undefined;
+ }
+
+ if (fallbackAssetUrl.origin !== remoteOrigin) {
+ return undefined;
+ }
+
+ if (!requestSearch) {
+ return fallbackAssetUrl.toString();
+ }
+
+ const mergedSearchParams = new URLSearchParams(fallbackAssetUrl.search);
+ const requestSearchParams = new URLSearchParams(requestSearch);
+ for (const [key, value] of requestSearchParams.entries()) {
+ mergedSearchParams.set(key, value);
+ }
+ const mergedSearch = mergedSearchParams.toString();
+ fallbackAssetUrl.search = mergedSearch ? `?${mergedSearch}` : '';
+
+ return fallbackAssetUrl.toString();
+};
+
+const recoverRemoteExposeAssetMiddleware: MiddlewareHandler = async (
+ c,
+ next,
+) => {
+ const reqUrl = new URL(c.req.url);
+ const pathname = reqUrl.pathname;
+ if (!isExposeAssetRequestPath(pathname)) {
+ await next();
+ return;
+ }
+
+ const requestHeaders = c.req.headers;
+ const isInternalFallbackFetch =
+ requestHeaders?.get?.(INTERNAL_FALLBACK_HEADER) === '1';
+ if (isInternalFallbackFetch) {
+ await next();
+ return;
+ }
+
+ const remoteOrigin = reqUrl.origin;
+ const manifestResponse = await fetch(
+ `${remoteOrigin}${REMOTE_MANIFEST_PATH}`,
+ {
+ headers: {
+ [INTERNAL_FALLBACK_HEADER]: '1',
+ },
+ },
+ ).catch((): undefined => undefined);
+ if (!manifestResponse?.ok) {
+ await next();
+ return;
+ }
+
+ const manifest = (await manifestResponse
+ .json()
+ .catch((): undefined => undefined)) as RemoteManifestShape | undefined;
+ if (!manifest) {
+ await next();
+ return;
+ }
+
+ const fallbackAssetPath = resolveManifestFallbackAssetPath(
+ pathname,
+ manifest,
+ );
+ if (!fallbackAssetPath) {
+ await next();
+ return;
+ }
+
+ const fallbackAssetUrl = createManifestFallbackAssetUrl({
+ remoteOrigin,
+ fallbackAssetPath,
+ requestSearch: reqUrl.search,
+ });
+ if (!fallbackAssetUrl || fallbackAssetUrl === reqUrl.toString()) {
+ await next();
+ return;
+ }
+
+ const fallbackAssetResponse = await fetch(fallbackAssetUrl, {
+ headers: {
+ [INTERNAL_FALLBACK_HEADER]: '1',
+ },
+ }).catch((): undefined => undefined);
+ if (!fallbackAssetResponse?.ok) {
+ await next();
+ return;
+ }
+
+ c.res = new Response(await fallbackAssetResponse.arrayBuffer(), {
+ status: fallbackAssetResponse.status,
+ headers: fallbackAssetResponse.headers,
+ });
+};
+
+export default defineServerConfig({
+ middlewares: [
+ {
+ name: 'recover-remote-federation-expose-asset',
+ handler: recoverRemoteExposeAssetMiddleware,
+ order: 'pre',
+ before: ['server-static'],
+ },
+ ],
+});
diff --git a/tests/integration/rsc-mf/tests/remoteModernServerConfig.test.ts b/tests/integration/rsc-mf/tests/remoteModernServerConfig.test.ts
new file mode 100644
index 000000000000..4e15989845f0
--- /dev/null
+++ b/tests/integration/rsc-mf/tests/remoteModernServerConfig.test.ts
@@ -0,0 +1,244 @@
+const REMOTE_SERVER_CONFIG_MODULE = '../remote/server/modern.server';
+const INTERNAL_FALLBACK_HEADER = 'x-rsc-mf-internal-fallback';
+
+const loadRemoteServerConfig = () => {
+ jest.resetModules();
+ jest.doMock('@modern-js/server-runtime', () => ({
+ defineServerConfig: (config: unknown) => config,
+ }));
+
+ let config: any;
+ jest.isolateModules(() => {
+ config = require(REMOTE_SERVER_CONFIG_MODULE).default;
+ });
+
+ return config;
+};
+
+const getRecoverMiddlewareHandler = () => {
+ const config = loadRemoteServerConfig();
+ if (!Array.isArray(config.middlewares)) {
+ throw new Error('Remote server config did not provide a middlewares array');
+ }
+
+ const middleware = config.middlewares.find(
+ (entry: { name?: string }) =>
+ entry.name === 'recover-remote-federation-expose-asset',
+ );
+ if (!middleware) {
+ throw new Error(
+ 'recover-remote-federation-expose-asset middleware missing',
+ );
+ }
+
+ expect(middleware.order).toBe('pre');
+ expect(middleware.before).toEqual(['server-static']);
+ expect(typeof middleware.handler).toBe('function');
+
+ return middleware.handler as (
+ c: {
+ req: { url: string; headers?: { get?: (name: string) => string | null } };
+ res?: Response;
+ },
+ next: () => Promise,
+ ) => Promise;
+};
+
+describe('rsc-mf remote modern.server middleware contracts', () => {
+ const originalFetch = global.fetch;
+ const originalFetchDescriptor = Object.getOwnPropertyDescriptor(
+ global,
+ 'fetch',
+ );
+
+ const installFetchMock = (implementation: typeof fetch) => {
+ const fetchMock = jest.fn(implementation);
+ Object.defineProperty(global, 'fetch', {
+ value: fetchMock,
+ configurable: true,
+ writable: true,
+ });
+ return fetchMock;
+ };
+
+ afterAll(() => {
+ if (originalFetchDescriptor) {
+ Object.defineProperty(global, 'fetch', originalFetchDescriptor);
+ return;
+ }
+ global.fetch = originalFetch;
+ });
+
+ it('recovers stale expose asset path via remote manifest fallback', async () => {
+ const handler = getRecoverMiddlewareHandler();
+ const next = jest.fn(async (): Promise