diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 0000000..dbb2ecb
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+ "changelog": "@changesets/cli/changelog",
+ "commit": false,
+ "fixed": [["@module-federation/tanstack"]],
+ "linked": [],
+ "access": "public",
+ "baseBranch": "main",
+ "updateInternalDependencies": "patch",
+ "ignore": []
+}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..1ce0e02
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+name: CI
+
+on:
+ pull_request:
+ branches: [main]
+ push:
+ branches: [main]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ verify:
+ name: Verify (Node ${{ matrix.node }})
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ node: ["22.18.0", "24", "26"]
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: ${{ matrix.node }}
+ cache: pnpm
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm format:check
+ - run: pnpm typecheck
+ - run: pnpm build
+ - run: pnpm exec playwright install --with-deps chromium
+ - run: pnpm test
+ - run: pnpm pack:tanstack
diff --git a/.github/workflows/pkg-pr-new.yml b/.github/workflows/pkg-pr-new.yml
new file mode 100644
index 0000000..0e0a314
--- /dev/null
+++ b/.github/workflows/pkg-pr-new.yml
@@ -0,0 +1,22 @@
+name: pkg-pr-new
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+
+permissions: {}
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24
+ cache: pnpm
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm build:package
+ - run: pnpm dlx pkg-pr-new@0.0.54 publish ./packages/tanstack
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 0000000..c0e9964
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,21 @@
+name: Validate PR title
+
+on:
+ pull_request:
+ branches: [main]
+
+permissions:
+ pull-requests: read
+
+jobs:
+ semantic-pr:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Accept generated release title
+ if: ${{ startsWith(github.event.pull_request.title, 'Release ') }}
+ run: echo "Generated release PR title accepted."
+
+ - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
+ if: ${{ !startsWith(github.event.pull_request.title, 'Release ') }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-pull-request.yml b/.github/workflows/release-pull-request.yml
new file mode 100644
index 0000000..a48475c
--- /dev/null
+++ b/.github/workflows/release-pull-request.yml
@@ -0,0 +1,44 @@
+name: Release Pull Request
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ pull-requests: write
+
+concurrency:
+ group: release-pull-request
+ cancel-in-progress: false
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Validate release request
+ env:
+ REPO_SCOPED_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }}
+ run: |
+ test "$GITHUB_REF" = "refs/heads/main" || { echo "Release PRs are main-only."; exit 1; }
+ test -n "$REPO_SCOPED_TOKEN" || { echo "REPO_SCOPED_TOKEN is required."; exit 1; }
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 10
+ token: ${{ secrets.REPO_SCOPED_TOKEN }}
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24
+ cache: pnpm
+ - run: pnpm install --frozen-lockfile --ignore-scripts
+ - uses: module-federation/actions@842df3a7740093a5ff44de2b9a890106046b8e32 # v2
+ with:
+ version: latest
+ versionNumber: auto
+ type: pull request
+ tools: changeset
+ coreNpmName: "@module-federation/tanstack"
+ env:
+ GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }}
+ REPOSITORY: ${{ github.repository }}
+ REF: ${{ github.ref }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..09a12cc
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,99 @@
+name: Release
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+ inputs:
+ version:
+ type: choice
+ required: true
+ default: next
+ options: [latest, next]
+ branch:
+ required: true
+ default: main
+
+permissions:
+ contents: read
+ id-token: write
+
+concurrency:
+ group: publish-module-federation-tanstack
+ cancel-in-progress: false
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ environment: Publish
+ steps:
+ - name: Validate manual target
+ if: github.event_name == 'workflow_dispatch'
+ env:
+ RELEASE_BRANCH: ${{ inputs.branch }}
+ run: test "$RELEASE_BRANCH" = "main" || { echo "Releases are main-only."; exit 1; }
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+ ref: ${{ github.event.release.tag_name || inputs.branch }}
+ - name: Verify source branch
+ run: |
+ git fetch --no-tags origin main:refs/remotes/origin/main
+ git merge-base --is-ancestor HEAD origin/main || { echo "Source is not on main."; exit 1; }
+ - uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24
+ cache: pnpm
+ registry-url: https://registry.npmjs.org/
+ - run: pnpm install --frozen-lockfile
+ - name: Verify release tag
+ if: github.event_name == 'release'
+ env:
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
+ run: |
+ test "${RELEASE_TAG#v}" = "$RELEASE_TAG" || { echo "Tags must not start with v."; exit 1; }
+ test "$(node -p "require('./packages/tanstack/package.json').version")" = "$RELEASE_TAG" || { echo "Tag/version mismatch."; exit 1; }
+ - name: Generate preview version
+ if: github.event_name == 'workflow_dispatch' && inputs.version == 'next'
+ run: |
+ pnpm changeset version --snapshot next
+ SNAPSHOT_VERSION="$(node -p "require('./packages/tanstack/package.json').version")"
+ BASE_VERSION="${SNAPSHOT_VERSION%%-*}"
+ npm pkg set version="${BASE_VERSION}-next.${GITHUB_RUN_ID}" --prefix packages/tanstack
+ - run: pnpm format:check
+ - run: pnpm typecheck
+ - run: pnpm build
+ - run: pnpm exec playwright install --with-deps chromium
+ - run: pnpm test
+ - run: pnpm pack:tanstack
+ - name: Compute dist-tag
+ id: dist
+ env:
+ INPUT_VERSION: ${{ inputs.version }}
+ PRERELEASE: ${{ github.event.release.prerelease || false }}
+ run: |
+ TAG=latest
+ if [ "$INPUT_VERSION" = "next" ] || [ "$PRERELEASE" = "true" ]; then TAG=next; fi
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
+ - name: Refuse conflicting republish
+ id: publish-check
+ env:
+ PACKAGE: "@module-federation/tanstack"
+ DIST_TAG: ${{ steps.dist.outputs.tag }}
+ run: |
+ VERSION="$(node -p "require('./packages/tanstack/package.json').version")"
+ EXISTING="$(npm view "$PACKAGE@$VERSION" version --json 2>/dev/null || true)"
+ EXISTING="${EXISTING#\"}"; EXISTING="${EXISTING%\"}"
+ if [ "$EXISTING" = "$VERSION" ]; then
+ CURRENT="$(npm view "$PACKAGE" "dist-tags.$DIST_TAG" --json 2>/dev/null || true)"
+ CURRENT="${CURRENT#\"}"; CURRENT="${CURRENT%\"}"
+ test "$CURRENT" = "$VERSION" || { echo "Existing version has conflicting dist-tag."; exit 1; }
+ echo "publish=false" >> "$GITHUB_OUTPUT"
+ else
+ echo "publish=true" >> "$GITHUB_OUTPUT"
+ fi
+ - name: Publish to npm
+ if: steps.publish-check.outputs.publish == 'true'
+ working-directory: packages/tanstack
+ run: npm publish --provenance --tag "${{ steps.dist.outputs.tag }}" --access public
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cc0b184
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+node_modules/
+dist/
+.turbo/
+.mf/
+@mf-types/
+*.log
+pnpm-debug.log*
+coverage/
+*.tgz
+*.tsbuildinfo
+.DS_Store
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..77c3854
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,5 @@
+dist
+node_modules
+pnpm-lock.yaml
+.turbo
+**/routeTree.gen.ts
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..bccee91
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+ "semi": true,
+ "singleQuote": false,
+ "trailingComma": "all",
+ "printWidth": 100
+}
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..3bad16e
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,10 @@
+
+
+# This is NOT the Turborepo you know
+
+Turborepo configuration, task behavior, and CLI commands can vary between installed versions and may differ from your training data. Resolve the `turbo` package from this file's directory or relevant workspace; in monorepos, it may not be visible from the repository root. For example, run `node -p "require.resolve('turbo/package.json')"` from a workspace that depends on `turbo`.
+
+Read `docs/README.md` inside that installed package first, then read the relevant pages from its `docs/` directory before changing Turborepo configuration or commands. Heed deprecation notices. These bundled docs match the installed package version and are available without network access.
+
+This block is written and re-added by `turbo` before repository-scoped commands when an AI agent is detected. In the Turborepo source repository, its template is defined in `crates/turborepo-cli/src/cli/agent_guidance.rs`. Removing the managed block while updates are enabled means a later qualifying invocation will add it again. Set `"agentGuidance": false` in the root `turbo.json` or `turbo.jsonc` to opt out; this does not remove an existing block. Keep the block committed with your work to avoid an uncommitted change on the next agent invocation.
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b0cebd8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Module Federation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 5ad6652..ad5f4af 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,147 @@
-# tanstack
\ No newline at end of file
+# @module-federation/tanstack
+
+Module Federation support for TanStack Start on Vite and Rsbuild. Rsbuild uses
+Rspack under the hood.
+
+## Install
+
+```bash
+pnpm add @module-federation/tanstack @tanstack/react-start
+```
+
+Install the adapter for the bundler you use. They are optional peers so an
+Rsbuild-only application does not install or resolve the Vite adapter, and a
+Vite-only application does not install or resolve the Rsbuild adapter.
+
+```bash
+pnpm add @module-federation/vite vite # Vite
+pnpm add @module-federation/rsbuild-plugin @rsbuild/core # Rsbuild
+```
+
+## Configure
+
+The federation wrapper must come before `tanstackStart()` so Module Federation
+can normalize TanStack's client and SSR entrypoints:
+
+```ts
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/vite";
+import { tanstackStart } from "@tanstack/react-start/plugin/vite";
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ tanstackStartModuleFederation({
+ name: "host",
+ remotes: {
+ remote: {
+ type: "module",
+ name: "remote",
+ entry: "https://example.test/remoteEntry.js",
+ },
+ },
+ }),
+ tanstackStart(),
+ react(),
+ ],
+});
+```
+
+Defaults are `remoteEntry.js`, `manifest: true`, and
+`hostInitInjectLocation: "entry"`. React and `react-dom` are shared
+singletons; when the config declares `remotes`, they are also eager so the
+host's own React stays in the share scope. Explicit entries in `shared` take
+precedence.
+
+Do not set a global Module Federation `target`. TanStack Start builds client
+and SSR environments from one Vite configuration, so the wrapper leaves target
+selection to `@module-federation/vite` for each environment.
+
+The package supports Node 22.18+, 24.11+, and 26+, plus TanStack Start
+1.167.43+. The Vite adapter requires Vite 8 and `@module-federation/vite`
+1.23.3+.
+
+The package root remains a Vite compatibility export. New Vite projects can
+import `/vite` explicitly. Rsbuild projects must import `/rsbuild`:
+
+```ts
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ name: "host",
+ shareStrategy: "loaded-first",
+ remotes: { remote: "remote@https://example.test/mf-manifest.json" },
+ },
+ }),
+ ],
+});
+```
+
+The Rsbuild adapter emits script-compatible browser output, so its manifest can
+be consumed by Vite and Rsbuild hosts. It shares singleton `react` and
+`react-dom` (eager for hosts, lazy for remotes), enables async startup, and
+gives remotes `publicPath: "auto"` so other origins load their chunks from the
+remote. Hosts should use `shareStrategy: "loaded-first"` so one offline remote
+cannot fail startup.
+
+Rsbuild SSR federation is opt-in with `server: true`. A remote builds a Node
+container, `remoteEntry.ssr.cjs`, next to its browser entry and advertises it in
+its manifest, so Vite and Rsbuild hosts can render it on the server. A host
+loads remotes on the server from an async-node CommonJS server build, and
+renders Vite remotes too when `@module-federation/vite` is installed. See the
+[package README](packages/tanstack/README.md#ssr-federation).
+
+`@module-federation/tanstack/runtime` has two helpers for route code:
+`lazyRemote`, a `React.lazy` that loads a failed remote again instead of
+failing until the server restarts, and `getRemoteStylesheets`, which reads a
+remote's stylesheets from its manifest so a route can put them in the server
+response's `
`. See
+[rendering remotes on the server](packages/tanstack/README.md#rendering-remotes-on-the-server).
+
+## Support status
+
+| Host | Remote | Browser federation | Federated SSR |
+| ------- | ------- | ------------------ | ---------------------------------- |
+| Vite | Vite | Supported | Supported |
+| Vite | Rsbuild | Supported | Supported (remote: `server: true`) |
+| Rsbuild | Vite | Supported | Supported (host: `server: true`) |
+| Rsbuild | Rsbuild | Supported | Supported (both: `server: true`) |
+
+Known limitations are listed in the
+[package README](packages/tanstack/README.md#known-limitations), and
+[`TODO.md`](TODO.md) tracks the remaining work.
+
+## Examples
+
+The workspace has six TanStack Start apps; see [`apps/README.md`](apps/README.md).
+
+The repository uses pnpm 12 (pinned in `packageManager`). pnpm 12 ships as a
+native binary, so an older global pnpm cannot switch to it automatically;
+install pnpm 12 itself (see https://pnpm.io/installation) before running these
+commands.
+
+```bash
+pnpm install
+pnpm start # development servers
+pnpm preview # production builds
+```
+
+Open the Vite host at http://127.0.0.1:3000, the Rsbuild host at
+http://127.0.0.1:3003, or the Rsbuild SSR host at http://127.0.0.1:3005.
+
+`pnpm test` builds everything, then runs the six apps twice, as development
+servers and as production builds, and drives every host in headless Chromium.
+It checks server-rendered remote markup from both bundlers (including
+concurrent first requests), remote stylesheets in the server response,
+hydration, remote interactivity, shared React context, console errors,
+manifest asset reachability, and the fallback and recovery when remotes go
+offline. Run
+`pnpm exec playwright install chromium` once before the first local test run.
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..ef738f2
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,178 @@
+# Federation TODO
+
+This file tracks what `@module-federation/tanstack` proves today and the work
+left after 0.1.0.
+
+Assessment date: 2026-10-06.
+
+## Support boundary
+
+| Host | Remote | Browser federation | Federated SSR | Proof (development and production) |
+| ------- | ------- | ------------------ | ------------- | --------------------------------------------------------------------- |
+| Vite | Vite | Supported | Supported | `vite-host` renders `vite-remote` on the server |
+| Vite | Rsbuild | Supported | Supported | `vite-host` renders `rsbuild-ssr-remote` on the server |
+| Rsbuild | Vite | Supported | Supported | `rsbuild-ssr-host` renders `vite-remote` on the server |
+| Rsbuild | Rsbuild | Supported | Supported | `rsbuild-ssr-host` renders `rsbuild-ssr-remote` on the server |
+| Any | Any | Supported | — | `rsbuild-host` and `vite-host` load browser-only remotes on hydration |
+
+`test/example-runtime.test.mjs` (development servers) and
+`test/example-production.test.mjs` (production builds) run the same scenarios
+through `test/support/examples.mjs` on every supported Node line in CI: remote
+markup in the initial HTML for eight concurrent first requests, remote
+stylesheets in the response (builds), hydration without console errors, remote
+interactivity, one React instance and shared context, fallback and recovery
+while every remote is offline, and hosts that start during an outage rendering
+the remotes once they return.
+
+## Done for 0.1.0
+
+### Rsbuild remotes on the server
+
+- [x] Default `experiments.asyncStartup: true` for browser and server
+ federation, preserving an explicit `false`.
+- [x] Share `react` and `react-dom` as singletons: eager for hosts, lazy for
+ remotes and server containers, so remotes cannot replace a host's React.
+- [x] Build a remote's Node container in a dedicated `mf-server` environment:
+ `remoteEntry.ssr.cjs` next to `remoteEntry.js`, chunks in `ssr/`. It
+ contains only the exposed modules; the app's server bundle is never
+ published.
+- [x] Advertise the container in the browser manifest as a `commonjs-module`
+ `ssrRemoteEntry`, which Module Federation otherwise only does for
+ Rslib's `dual` target.
+- [x] Give remotes `publicPath: "auto"`. TanStack Start derives `/` from
+ `server.base`, which made production remotes request their chunks from
+ the host's origin, and made Node hosts fail to fetch them.
+- [x] Keep the container next to the manifest, so its chunks resolve the same
+ way from the container URL (Module Federation's Node runtime) and from
+ the manifest URL (`@module-federation/vite`).
+
+### Rsbuild hosts on the server
+
+- [x] Load remotes in a host's server bundle as async-node CommonJS, keep
+ `dist/server/index.js` as an ES module that re-exports it, and write the
+ server output to disk in development so async-node chunks match the
+ in-memory entry. The dev bundle goes to
+ `node_modules/.cache/tanstack-start-federation/`, so it never replaces a
+ production build in `dist/server`.
+- [x] `@module-federation/tanstack/node-entry-loader` compiles CommonJS
+ containers as CommonJS modules, so their `import()` calls work in
+ Rsbuild's development runner without experimental Node flags or
+ warnings.
+- [x] Vite remotes: the loader hands ES module entries to
+ `@module-federation/vite`'s SSR loader, loaded with Node's `require` so
+ its imports bypass Rsbuild's runner. It registers the host's loaded
+ shared modules under their node_modules paths, so React imported from
+ node_modules by a Vite dev server's module runner is the host's React.
+- [x] Failures throw `RemoteEntryError` with `phase` (`fetch`, `evaluate`,
+ `loader`), the remote, the URL, and the original `cause`, instead of
+ falling through to Module Federation's Node loader, which cannot load
+ ES modules without Node flags.
+
+### Vite hosts
+
+- [x] Support Vite 8 only, like TanStack Start's examples (Vite ^8.0.14 with
+ `@vitejs/plugin-react` 6, which requires Vite 8). The `vite` peer range
+ is `^8.0.0`, and the adapter stops with an error on older versions: on
+ Vite 7, `@module-federation/vite` hangs server-side remote loads in
+ development and emits an unresolved `virtual:` import in production.
+- [x] Require `@module-federation/vite` 1.23.3, which ships the fixes for the
+ problems found here (see "Fixed upstream" below), so the adapter needs
+ no workarounds for it.
+
+### SSR quality and hardening
+
+- [x] `getRemoteStylesheets` (`@module-federation/tanstack/runtime`) reads an
+ expose's stylesheets from the remote manifest for the route `head`, so
+ server-rendered remote markup is styled before JavaScript loads. The
+ production suite checks it with JavaScript disabled.
+- [x] Production builds (`vite preview`, `rsbuild preview`) run the same browser
+ scenarios as development servers.
+- [x] Hosts render a fallback, not a 500 or a blank page, while remotes are
+ offline, and render remote markup again once they return, in development
+ and production.
+- [x] Hosts recover from a remote that failed its first load, such as a host
+ started during an outage. Three layers kept the failure:
+ `@module-federation/vite`'s single load attempt (fixed in 1.23.3),
+ Rspack's module cache (a failed remote module kept empty exports;
+ Rspack's `strictModuleExceptionHandling` caches the error instead, so
+ the adapter removes the module from the cache), and `React.lazy`
+ (`lazyRemote`).
+- [x] Every remote, including the Vite remote, works as a standalone TanStack
+ Start app (`@module-federation/vite` 1.23.3).
+- [x] `useState`, `useEffect`, Suspense, and error boundaries across the
+ federation boundary (counter, hydration status, lazy remote components,
+ `RemoteBoundary`).
+- [x] React context created by each host and read by every remote, including
+ across bundlers and in server-rendered HTML, through the singleton
+ `example-host-context` package.
+
+## Open
+
+### Upstream issues
+
+To report to `module-federation/core`:
+
+- [ ] `@module-federation/webpack-bundler-runtime`: a remote module that
+ failed stays in the module cache with empty exports, although the load
+ itself is retried. Worked around by `remoteRetryPlugin`.
+- [ ] `@module-federation/node`: a container without an absolute public path
+ logs `Backup remote entry found` for every chunk it loads through a Vite
+ host.
+
+Fixed upstream in `@module-federation/vite` 1.23.3:
+
+- [x] An unawaited `__mf_remote_pending` turned a remote outage into an
+ unhandled rejection that exited a dev server
+ ([vite#1421](https://github.com/module-federation/vite/pull/1421)).
+- [x] A server wrapper made one load attempt, so a remote that failed its
+ first load failed for the life of the process
+ ([vite#1424](https://github.com/module-federation/vite/issues/1424),
+ fixed by [vite#1426](https://github.com/module-federation/vite/pull/1426)).
+- [x] The SSR loader could not load a CommonJS server container from a
+ manifest ([vite#1423](https://github.com/module-federation/vite/issues/1423),
+ fixed by [vite#1425](https://github.com/module-federation/vite/pull/1425)).
+- [x] Rollup builds (Vite 5 to 7) kept an unresolved `virtual:mf-exposes-ssr:`
+ import in the SSR entry outside Nuxt
+ ([vite#1422](https://github.com/module-federation/vite/pull/1422)).
+- [x] A Vite remote with `exposes` did not hydrate when opened directly
+ ([vite#1413](https://github.com/module-federation/vite/issues/1413),
+ fixed by [vite#1415](https://github.com/module-federation/vite/pull/1415)
+ and [vite#1420](https://github.com/module-federation/vite/pull/1420)).
+
+### SSR quality
+
+- [ ] Revalidate a changed remote manifest and server entry without restarting
+ the host, and prove no stale container or shared module is served.
+ `@module-federation/vite` has `revalidate()` and `maxAgeMs` for its own
+ loader; the Module Federation runtime caches containers for the life of
+ the process.
+- [ ] Test cyclic imports across chunks in a server remote graph.
+- [ ] In development, a Vite remote's server modules import React from the files
+ its dev server resolves, so host and remote must resolve React to the
+ same files (true in a monorepo). Production builds take React from the
+ share scope.
+
+### Shared dependencies
+
+- [x] React range: React 19. TanStack Start 1.168 accepts React 18, but its
+ Rsbuild server build fails with it: TanStack Router imports React's
+ `use`, which React 18 lacks. Vite apps build with React 18; revisit when
+ TanStack Start supports it on both bundlers.
+- [ ] Validate version-mismatch warnings for incompatible React majors, and
+ that `import: false` fails at startup when the host cannot provide a
+ package. With mismatched React majors, the federation runtime already
+ warns (`Version 18.3.1 ... does not satisfy the requirement ... 19.3.0`).
+
+### Error reporting
+
+- [ ] Distinguish manifest, chunk, and shared-dependency failures the way
+ `RemoteEntryError` does for server entries.
+- [ ] Add optional observability reports for raw runtime codes that do not
+ contain enough context.
+
+## Release work for each new SSR combination
+
+- [ ] Update the support table only after the combination passes the
+ development and production scenarios on every supported Node line.
+- [ ] Add a Changeset and list the tested bundler and Node versions in the
+ release notes.
diff --git a/apps/README.md b/apps/README.md
new file mode 100644
index 0000000..3fde10c
--- /dev/null
+++ b/apps/README.md
@@ -0,0 +1,65 @@
+# TanStack Start examples
+
+Six TanStack Start applications: a host and a remote for each bundler, plus an
+Rsbuild pair that federates on the server. Both SSR hosts render a Vite remote
+and an Rsbuild remote into their initial HTML.
+
+`host-context` is a small shared package: each host provides its name through a
+React context, and every remote card shows "Host: …". It is shared as a
+singleton, so the right name only appears when host and remote resolve one
+module instance.
+
+| App | Port | Role |
+| -------------------- | ---- | -------------------------------------------------------------------------------- |
+| `vite-host` | 3000 | Server-renders the Vite and Rsbuild SSR remotes; loads `rsbuild-remote` later |
+| `vite-remote` | 3001 | Exposes `./StatusCard`, rendered into both SSR hosts' initial HTML |
+| `rsbuild-remote` | 3002 | Exposes `./StatusCard` through a browser manifest |
+| `rsbuild-host` | 3003 | Loads both browser remotes with `loadRemote()` after hydration |
+| `rsbuild-ssr-remote` | 3004 | Exposes `./StatusCard` with a Node container (`server: true`) for both SSR hosts |
+| `rsbuild-ssr-host` | 3005 | Server-renders the Rsbuild SSR and Vite remotes (`server: true`) |
+
+From the repository root:
+
+```bash
+pnpm start # development servers
+pnpm preview # production builds (`vite preview` / `rsbuild preview`)
+```
+
+Then open http://127.0.0.1:3000, http://127.0.0.1:3003, or
+http://127.0.0.1:3005. Every remote card has a counter button; clicking it
+proves the remote shares the host's React instance. Cards rendered on the
+server show "Rendered on the server" until they hydrate.
+
+## What each host shows
+
+- **Vite host.** The route loader imports the Vite remote and the Rsbuild SSR
+ remote, so both cards are in the server response and hydrate in place. The
+ loader also reads each remote's stylesheets with `getRemoteStylesheets`, and
+ the route's `head` links them, so the cards are styled before JavaScript
+ runs. The `rsbuild-remote` card mounts after hydration. The cards are
+ `lazyRemote` components, which load again after a failure. Every remote sits
+ behind `RemoteBoundary`, an error boundary with a fallback card, and the
+ loader ignores failed imports, so an offline remote never fails the route.
+- **Rsbuild host.** `RemoteCardSlot` calls `loadRemote()` in an effect and
+ shows "Remote unavailable" when a remote fails. The host uses
+ `shareStrategy: "loaded-first"`, so it does not fetch every remote's
+ manifest at startup.
+- **Rsbuild SSR host.** Same pattern as the Vite host, on Rsbuild. The
+ Module Federation Node runtime loads the Rsbuild remote's
+ `remoteEntry.ssr.cjs` container, and hands the Vite remote's ES module entry
+ to `@module-federation/vite`'s SSR loader, which is why this app depends on
+ `@module-federation/vite` and `vite`.
+
+Stop a remote while the hosts are open and reload them: each host keeps
+rendering and shows its fallback, then renders the remote again once it is
+back. The same holds for a host started before its remotes.
+
+## Notes
+
+- The federation wrapper must come before `tanstackStart()` in the Vite
+ configs, and after it in the Rsbuild configs.
+- Each `start` script runs the bundler's development server. In Vite's CLI the
+ bare `vite` command starts the dev server; `vite start` would treat `start`
+ as a project directory.
+- Every remote also works as a standalone TanStack Start app: open port 3001,
+ 3002, or 3004 directly, and its card shows "Host: standalone".
diff --git a/apps/host-context/package.json b/apps/host-context/package.json
new file mode 100644
index 0000000..b832dfa
--- /dev/null
+++ b/apps/host-context/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "example-host-context",
+ "version": "0.0.0",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "exports": {
+ ".": "./src/index.ts"
+ },
+ "peerDependencies": {
+ "react": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "19.3.0",
+ "react": "19.3.0"
+ }
+}
diff --git a/apps/host-context/src/index.ts b/apps/host-context/src/index.ts
new file mode 100644
index 0000000..806c0f5
--- /dev/null
+++ b/apps/host-context/src/index.ts
@@ -0,0 +1,11 @@
+import { createContext, useContext } from "react";
+
+/**
+ * Provided by each host and read by every remote card. Shared as a Module Federation
+ * singleton, so a remote only sees the host's value if both resolve one module instance.
+ */
+export const HostContext = createContext("standalone");
+
+export function useHostName() {
+ return useContext(HostContext);
+}
diff --git a/apps/rsbuild-host/package.json b/apps/rsbuild-host/package.json
new file mode 100644
index 0000000..fad3a00
--- /dev/null
+++ b/apps/rsbuild-host/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "tanstack-start-rsbuild-host",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "rsbuild build",
+ "dev": "rsbuild dev --port 3003 --strict-port",
+ "start": "rsbuild dev --host 127.0.0.1 --port 3003 --strict-port",
+ "preview": "rsbuild preview --host 127.0.0.1 --port 3003",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/rsbuild-plugin": "2.9.2",
+ "@module-federation/tanstack": "workspace:*",
+ "@rsbuild/core": "2.2.11",
+ "@rsbuild/plugin-react": "2.1.1",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "typescript": "7.0.2"
+ }
+}
diff --git a/apps/rsbuild-host/rsbuild.config.ts b/apps/rsbuild-host/rsbuild.config.ts
new file mode 100644
index 0000000..caec5e4
--- /dev/null
+++ b/apps/rsbuild-host/rsbuild.config.ts
@@ -0,0 +1,27 @@
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ dev: { lazyCompilation: false },
+ server: { host: "127.0.0.1", port: 3003 },
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ dts: false,
+ name: "tanstack_rsbuild_host",
+ // Workspace dependencies declare "workspace:*", which is not a semver range.
+ shared: { "example-host-context": { requiredVersion: "*", singleton: true } },
+ // Resolve remotes on demand so one offline remote cannot block host startup.
+ shareStrategy: "loaded-first",
+ remotes: {
+ tanstack_vite_remote: "tanstack_vite_remote@http://127.0.0.1:3001/mf-manifest.json",
+ tanstack_rsbuild_remote: "tanstack_rsbuild_remote@http://127.0.0.1:3002/mf-manifest.json",
+ },
+ },
+ }),
+ ],
+});
diff --git a/apps/rsbuild-host/src/assets.d.ts b/apps/rsbuild-host/src/assets.d.ts
new file mode 100644
index 0000000..596a189
--- /dev/null
+++ b/apps/rsbuild-host/src/assets.d.ts
@@ -0,0 +1,4 @@
+declare module "*.css?url" {
+ const href: string;
+ export default href;
+}
diff --git a/apps/rsbuild-host/src/components/RemoteCardSlot.tsx b/apps/rsbuild-host/src/components/RemoteCardSlot.tsx
new file mode 100644
index 0000000..c99449f
--- /dev/null
+++ b/apps/rsbuild-host/src/components/RemoteCardSlot.tsx
@@ -0,0 +1,38 @@
+import { loadRemote } from "@module-federation/runtime";
+import { useEffect, useState, type ComponentType } from "react";
+
+type RemoteModule = {
+ default: ComponentType;
+};
+
+export function RemoteCardSlot({ fallback, remote }: { fallback: string; remote: string }) {
+ const [RemoteCard, setRemoteCard] = useState(null);
+ const [failed, setFailed] = useState(false);
+
+ useEffect(() => {
+ let active = true;
+ setRemoteCard(null);
+ setFailed(false);
+
+ loadRemote(remote)
+ .then((remoteModule) => {
+ if (!active) return;
+ if (remoteModule?.default) {
+ setRemoteCard(() => remoteModule.default);
+ } else {
+ setFailed(true);
+ }
+ })
+ .catch(() => {
+ if (active) setFailed(true);
+ });
+
+ return () => {
+ active = false;
+ };
+ }, [remote]);
+
+ if (failed) return Remote unavailable
;
+ if (!RemoteCard) return {fallback}
;
+ return ;
+}
diff --git a/apps/rsbuild-host/src/routeTree.gen.ts b/apps/rsbuild-host/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/rsbuild-host/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/rsbuild-host/src/router.tsx b/apps/rsbuild-host/src/router.tsx
new file mode 100644
index 0000000..6982ebb
--- /dev/null
+++ b/apps/rsbuild-host/src/router.tsx
@@ -0,0 +1,16 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({
+ defaultPreload: "intent",
+ routeTree,
+ scrollRestoration: true,
+ });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/rsbuild-host/src/routes/__root.tsx b/apps/rsbuild-host/src/routes/__root.tsx
new file mode 100644
index 0000000..c235e44
--- /dev/null
+++ b/apps/rsbuild-host/src/routes/__root.tsx
@@ -0,0 +1,39 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import { HostContext } from "example-host-context";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ href: stylesHref, rel: "stylesheet" }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ ],
+ }),
+ component: Root,
+});
+
+function Root() {
+ return (
+
+
+
+
+
+ );
+}
+
+function Document({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/rsbuild-host/src/routes/index.tsx b/apps/rsbuild-host/src/routes/index.tsx
new file mode 100644
index 0000000..41b643c
--- /dev/null
+++ b/apps/rsbuild-host/src/routes/index.tsx
@@ -0,0 +1,24 @@
+import { createFileRoute } from "@tanstack/react-router";
+import { RemoteCardSlot } from "../components/RemoteCardSlot";
+
+export const Route = createFileRoute("/")({ component: Home });
+
+function Home() {
+ return (
+
+ Rsbuild host
+ Rspack host, two remote formats.
+ This TanStack Start app loads both remotes through the browser runtime.
+
+
+
+
+
+ );
+}
diff --git a/apps/rsbuild-host/src/styles.css b/apps/rsbuild-host/src/styles.css
new file mode 100644
index 0000000..e379e6a
--- /dev/null
+++ b/apps/rsbuild-host/src/styles.css
@@ -0,0 +1,32 @@
+:root {
+ background: #111;
+ color: #edf6ef;
+ font-family: system-ui, sans-serif;
+}
+body {
+ margin: 0;
+}
+.page-shell {
+ width: min(760px, calc(100% - 40px));
+ margin: 0 auto;
+ padding: 80px 0;
+}
+.eyebrow {
+ color: #91f1b0;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+h1 {
+ font-size: clamp(3rem, 10vw, 6rem);
+ margin: 12px 0;
+}
+.remote-loading {
+ border: 1px solid #4b6653;
+ margin-top: 36px;
+ padding: 30px;
+}
+.remote-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 20px;
+}
diff --git a/apps/rsbuild-host/tsconfig.json b/apps/rsbuild-host/tsconfig.json
new file mode 100644
index 0000000..0416574
--- /dev/null
+++ b/apps/rsbuild-host/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "rsbuild.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/rsbuild-remote/package.json b/apps/rsbuild-remote/package.json
new file mode 100644
index 0000000..4aee25b
--- /dev/null
+++ b/apps/rsbuild-remote/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "tanstack-start-rsbuild-remote",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "rsbuild build",
+ "dev": "rsbuild dev --port 3002 --strict-port",
+ "start": "rsbuild dev --host 127.0.0.1 --port 3002 --strict-port",
+ "preview": "rsbuild preview --host 127.0.0.1 --port 3002",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/rsbuild-plugin": "2.9.2",
+ "@module-federation/tanstack": "workspace:*",
+ "@rsbuild/core": "2.2.11",
+ "@rsbuild/plugin-react": "2.1.1",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "typescript": "7.0.2"
+ }
+}
diff --git a/apps/rsbuild-remote/rsbuild.config.ts b/apps/rsbuild-remote/rsbuild.config.ts
new file mode 100644
index 0000000..34d992e
--- /dev/null
+++ b/apps/rsbuild-remote/rsbuild.config.ts
@@ -0,0 +1,28 @@
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ dev: { lazyCompilation: false },
+ server: {
+ cors: { origin: ["http://127.0.0.1:3000", "http://127.0.0.1:3003"] },
+ host: "127.0.0.1",
+ port: 3002,
+ },
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ // The type-hints runtime plugin opens a WebSocket to the dev type server, which
+ // races host startup and logs errors in the browser. Types are still generated.
+ dev: { disableDynamicRemoteTypeHints: true },
+ exposes: { "./StatusCard": "./src/components/StatusCard.tsx" },
+ name: "tanstack_rsbuild_remote",
+ // Workspace dependencies declare "workspace:*", which is not a semver range.
+ shared: { "example-host-context": { requiredVersion: "*", singleton: true } },
+ },
+ }),
+ ],
+});
diff --git a/apps/rsbuild-remote/src/assets.d.ts b/apps/rsbuild-remote/src/assets.d.ts
new file mode 100644
index 0000000..18e9eca
--- /dev/null
+++ b/apps/rsbuild-remote/src/assets.d.ts
@@ -0,0 +1,6 @@
+declare module "*.css";
+
+declare module "*.css?url" {
+ const href: string;
+ export default href;
+}
diff --git a/apps/rsbuild-remote/src/components/StatusCard.css b/apps/rsbuild-remote/src/components/StatusCard.css
new file mode 100644
index 0000000..42e1cc1
--- /dev/null
+++ b/apps/rsbuild-remote/src/components/StatusCard.css
@@ -0,0 +1,23 @@
+.rsbuild-card {
+ border: 1px solid #83502a;
+ background: #291c13;
+ color: #fff3e8;
+ padding: 30px;
+}
+
+.rsbuild-card .eyebrow {
+ color: #ffbc7c;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+
+.rsbuild-card h2 {
+ font-size: 2rem;
+}
+
+.rsbuild-card button {
+ background: #ffbc7c;
+ border: 0;
+ cursor: pointer;
+ padding: 12px;
+}
diff --git a/apps/rsbuild-remote/src/components/StatusCard.tsx b/apps/rsbuild-remote/src/components/StatusCard.tsx
new file mode 100644
index 0000000..b5b37cc
--- /dev/null
+++ b/apps/rsbuild-remote/src/components/StatusCard.tsx
@@ -0,0 +1,19 @@
+import { useHostName } from "example-host-context";
+import { useState } from "react";
+import "./StatusCard.css";
+
+export default function StatusCard() {
+ const hostName = useHostName();
+ const [count, setCount] = useState(0);
+ return (
+
+ Federated from Rsbuild
+ One component, either host.
+ This card is built by Rspack and shared with the Vite host.
+ Host: {hostName}
+ setCount((value) => value + 1)}>
+ Remote count {count}
+
+
+ );
+}
diff --git a/apps/rsbuild-remote/src/routeTree.gen.ts b/apps/rsbuild-remote/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/rsbuild-remote/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/rsbuild-remote/src/router.tsx b/apps/rsbuild-remote/src/router.tsx
new file mode 100644
index 0000000..673839e
--- /dev/null
+++ b/apps/rsbuild-remote/src/router.tsx
@@ -0,0 +1,12 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({ defaultPreload: "intent", routeTree, scrollRestoration: true });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/rsbuild-remote/src/routes/__root.tsx b/apps/rsbuild-remote/src/routes/__root.tsx
new file mode 100644
index 0000000..2eb5fe8
--- /dev/null
+++ b/apps/rsbuild-remote/src/routes/__root.tsx
@@ -0,0 +1,36 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ href: stylesHref, rel: "stylesheet" }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ ],
+ }),
+ component: Root,
+});
+
+function Root() {
+ return (
+
+
+
+ );
+}
+
+function Document({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/rsbuild-remote/src/routes/index.tsx b/apps/rsbuild-remote/src/routes/index.tsx
new file mode 100644
index 0000000..9cfe99e
--- /dev/null
+++ b/apps/rsbuild-remote/src/routes/index.tsx
@@ -0,0 +1,14 @@
+import { createFileRoute } from "@tanstack/react-router";
+import StatusCard from "../components/StatusCard";
+
+export const Route = createFileRoute("/")({ component: Home });
+
+function Home() {
+ return (
+
+ Rsbuild remote
+ Rspack-built remote.
+
+
+ );
+}
diff --git a/apps/rsbuild-remote/src/styles.css b/apps/rsbuild-remote/src/styles.css
new file mode 100644
index 0000000..fbab7d3
--- /dev/null
+++ b/apps/rsbuild-remote/src/styles.css
@@ -0,0 +1,22 @@
+:root {
+ background: #16110d;
+ color: #fff3e8;
+ font-family: system-ui, sans-serif;
+}
+body {
+ margin: 0;
+}
+.page-shell {
+ width: min(760px, calc(100% - 40px));
+ margin: 0 auto;
+ padding: 80px 0;
+}
+.eyebrow {
+ color: #ffbc7c;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+h1 {
+ font-size: clamp(3rem, 10vw, 6rem);
+ margin: 12px 0 48px;
+}
diff --git a/apps/rsbuild-remote/tsconfig.json b/apps/rsbuild-remote/tsconfig.json
new file mode 100644
index 0000000..0416574
--- /dev/null
+++ b/apps/rsbuild-remote/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "rsbuild.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/rsbuild-ssr-host/package.json b/apps/rsbuild-ssr-host/package.json
new file mode 100644
index 0000000..c8e67d3
--- /dev/null
+++ b/apps/rsbuild-ssr-host/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "tanstack-start-rsbuild-ssr-host",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "rsbuild build",
+ "dev": "rsbuild dev --port 3005 --strict-port",
+ "start": "rsbuild dev --host 127.0.0.1 --port 3005 --strict-port",
+ "preview": "rsbuild preview --host 127.0.0.1 --port 3005",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@module-federation/vite": "1.23.3",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/rsbuild-plugin": "2.9.2",
+ "@module-federation/tanstack": "workspace:*",
+ "@rsbuild/core": "2.2.11",
+ "@rsbuild/plugin-react": "2.1.1",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "typescript": "7.0.2",
+ "vite": "8.3.2"
+ }
+}
diff --git a/apps/rsbuild-ssr-host/rsbuild.config.ts b/apps/rsbuild-ssr-host/rsbuild.config.ts
new file mode 100644
index 0000000..f02e28e
--- /dev/null
+++ b/apps/rsbuild-ssr-host/rsbuild.config.ts
@@ -0,0 +1,29 @@
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ dev: { lazyCompilation: false },
+ server: { host: "127.0.0.1", port: 3005 },
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ dts: false,
+ name: "tanstack_rsbuild_ssr_host",
+ // Workspace dependencies declare "workspace:*", which is not a semver range.
+ shared: { "example-host-context": { requiredVersion: "*", singleton: true } },
+ shareStrategy: "loaded-first",
+ remotes: {
+ tanstack_rsbuild_ssr_remote:
+ "tanstack_rsbuild_ssr_remote@http://127.0.0.1:3004/mf-manifest.json",
+ tanstack_vite_remote: "tanstack_vite_remote@http://127.0.0.1:3001/mf-manifest.json",
+ },
+ },
+ // Loads remotes on the server. Vite remotes also need @module-federation/vite installed.
+ server: true,
+ }),
+ ],
+});
diff --git a/apps/rsbuild-ssr-host/src/assets.d.ts b/apps/rsbuild-ssr-host/src/assets.d.ts
new file mode 100644
index 0000000..596a189
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/assets.d.ts
@@ -0,0 +1,4 @@
+declare module "*.css?url" {
+ const href: string;
+ export default href;
+}
diff --git a/apps/rsbuild-ssr-host/src/components/RemoteBoundary.tsx b/apps/rsbuild-ssr-host/src/components/RemoteBoundary.tsx
new file mode 100644
index 0000000..7e953b5
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/components/RemoteBoundary.tsx
@@ -0,0 +1,28 @@
+import { Component, Suspense, type ReactNode } from "react";
+
+type Props = { children: ReactNode; fallback: string; name: string };
+
+/** Keeps a failed remote from taking down the host route. */
+export class RemoteBoundary extends Component {
+ state = { failed: false };
+
+ static getDerivedStateFromError() {
+ return { failed: true };
+ }
+
+ componentDidCatch(error: unknown) {
+ console.warn(`[${this.props.name}] remote failed to render`, error);
+ }
+
+ render() {
+ if (this.state.failed) {
+ return {this.props.name} is unavailable
;
+ }
+
+ return (
+ {this.props.fallback}}>
+ {this.props.children}
+
+ );
+ }
+}
diff --git a/apps/rsbuild-ssr-host/src/remote.d.ts b/apps/rsbuild-ssr-host/src/remote.d.ts
new file mode 100644
index 0000000..c46c4d0
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/remote.d.ts
@@ -0,0 +1,13 @@
+declare module "tanstack_rsbuild_ssr_remote/StatusCard" {
+ import type { ComponentType } from "react";
+
+ const StatusCard: ComponentType;
+ export default StatusCard;
+}
+
+declare module "tanstack_vite_remote/StatusCard" {
+ import type { ComponentType } from "react";
+
+ const StatusCard: ComponentType;
+ export default StatusCard;
+}
diff --git a/apps/rsbuild-ssr-host/src/routeTree.gen.ts b/apps/rsbuild-ssr-host/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/rsbuild-ssr-host/src/router.tsx b/apps/rsbuild-ssr-host/src/router.tsx
new file mode 100644
index 0000000..6982ebb
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/router.tsx
@@ -0,0 +1,16 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({
+ defaultPreload: "intent",
+ routeTree,
+ scrollRestoration: true,
+ });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/rsbuild-ssr-host/src/routes/__root.tsx b/apps/rsbuild-ssr-host/src/routes/__root.tsx
new file mode 100644
index 0000000..cc68b8a
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/routes/__root.tsx
@@ -0,0 +1,39 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import { HostContext } from "example-host-context";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ href: stylesHref, rel: "stylesheet" }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ ],
+ }),
+ component: Root,
+});
+
+function Root() {
+ return (
+
+
+
+
+
+ );
+}
+
+function Document({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/rsbuild-ssr-host/src/routes/index.tsx b/apps/rsbuild-ssr-host/src/routes/index.tsx
new file mode 100644
index 0000000..fa5dc6e
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/routes/index.tsx
@@ -0,0 +1,57 @@
+import { getRemoteStylesheets, lazyRemote } from "@module-federation/tanstack/runtime";
+import { createFileRoute } from "@tanstack/react-router";
+import { RemoteBoundary } from "../components/RemoteBoundary";
+
+// Unlike React.lazy, lazyRemote loads again after a failure, so a server that hit a remote
+// outage renders the remote once it is back.
+const RsbuildStatusCard = lazyRemote(() => import("tanstack_rsbuild_ssr_remote/StatusCard"));
+const ViteStatusCard = lazyRemote(() => import("tanstack_vite_remote/StatusCard"));
+
+// Manifests of the remotes this route renders on the server.
+const serverRenderedManifests = [
+ "http://127.0.0.1:3004/mf-manifest.json",
+ "http://127.0.0.1:3001/mf-manifest.json",
+];
+
+export const Route = createFileRoute("/")({
+ // Loading the remotes before render puts their markup in the server response.
+ // An unavailable remote must not fail the route: its boundary renders a fallback.
+ loader: async () => {
+ const [stylesheets] = await Promise.all([
+ Promise.all(
+ serverRenderedManifests.map((manifest) =>
+ getRemoteStylesheets(manifest, "./StatusCard").catch(() => []),
+ ),
+ ).then((lists) => lists.flat()),
+ import("tanstack_rsbuild_ssr_remote/StatusCard").catch(() => null),
+ import("tanstack_vite_remote/StatusCard").catch(() => null),
+ ]);
+ return { stylesheets };
+ },
+ // The remote markup arrives with the HTML, so its stylesheets must too. Otherwise it stays
+ // unstyled until the remote's JavaScript loads.
+ head: ({ loaderData }) => ({
+ links: loaderData?.stylesheets.map((href) => ({ href, rel: "stylesheet" })),
+ }),
+ component: Home,
+});
+
+function Home() {
+ return (
+
+ Rsbuild SSR host
+ Server-rendered from Rsbuild and Vite.
+
+ This TanStack Start server renders both remote cards before the page reaches the browser.
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/rsbuild-ssr-host/src/styles.css b/apps/rsbuild-ssr-host/src/styles.css
new file mode 100644
index 0000000..e379e6a
--- /dev/null
+++ b/apps/rsbuild-ssr-host/src/styles.css
@@ -0,0 +1,32 @@
+:root {
+ background: #111;
+ color: #edf6ef;
+ font-family: system-ui, sans-serif;
+}
+body {
+ margin: 0;
+}
+.page-shell {
+ width: min(760px, calc(100% - 40px));
+ margin: 0 auto;
+ padding: 80px 0;
+}
+.eyebrow {
+ color: #91f1b0;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+h1 {
+ font-size: clamp(3rem, 10vw, 6rem);
+ margin: 12px 0;
+}
+.remote-loading {
+ border: 1px solid #4b6653;
+ margin-top: 36px;
+ padding: 30px;
+}
+.remote-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 20px;
+}
diff --git a/apps/rsbuild-ssr-host/tsconfig.json b/apps/rsbuild-ssr-host/tsconfig.json
new file mode 100644
index 0000000..0416574
--- /dev/null
+++ b/apps/rsbuild-ssr-host/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "rsbuild.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/rsbuild-ssr-remote/package.json b/apps/rsbuild-ssr-remote/package.json
new file mode 100644
index 0000000..db721b7
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "tanstack-start-rsbuild-ssr-remote",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "rsbuild build",
+ "dev": "rsbuild dev --port 3004 --strict-port",
+ "start": "rsbuild dev --host 127.0.0.1 --port 3004 --strict-port",
+ "preview": "rsbuild preview --host 127.0.0.1 --port 3004",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/rsbuild-plugin": "2.9.2",
+ "@module-federation/tanstack": "workspace:*",
+ "@rsbuild/core": "2.2.11",
+ "@rsbuild/plugin-react": "2.1.1",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "typescript": "7.0.2"
+ }
+}
diff --git a/apps/rsbuild-ssr-remote/rsbuild.config.ts b/apps/rsbuild-ssr-remote/rsbuild.config.ts
new file mode 100644
index 0000000..8e302bf
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/rsbuild.config.ts
@@ -0,0 +1,30 @@
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ dev: { lazyCompilation: false },
+ server: {
+ cors: { origin: ["http://127.0.0.1:3000", "http://127.0.0.1:3005"] },
+ host: "127.0.0.1",
+ port: 3004,
+ },
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ dev: { disableDynamicRemoteTypeHints: true },
+ dts: false,
+ exposes: { "./StatusCard": "./src/components/StatusCard.tsx" },
+ name: "tanstack_rsbuild_ssr_remote",
+ // Workspace dependencies declare "workspace:*", which is not a semver range.
+ shared: { "example-host-context": { requiredVersion: "*", singleton: true } },
+ },
+ // Builds an async-node server container next to the browser container, so an
+ // Rsbuild host can render this card on the server.
+ server: true,
+ }),
+ ],
+});
diff --git a/apps/rsbuild-ssr-remote/src/assets.d.ts b/apps/rsbuild-ssr-remote/src/assets.d.ts
new file mode 100644
index 0000000..18e9eca
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/assets.d.ts
@@ -0,0 +1,6 @@
+declare module "*.css";
+
+declare module "*.css?url" {
+ const href: string;
+ export default href;
+}
diff --git a/apps/rsbuild-ssr-remote/src/components/StatusCard.css b/apps/rsbuild-ssr-remote/src/components/StatusCard.css
new file mode 100644
index 0000000..a0dfe22
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/components/StatusCard.css
@@ -0,0 +1,23 @@
+.rsbuild-ssr-card {
+ border: 1px solid #83502a;
+ background: #291c13;
+ color: #fff3e8;
+ padding: 30px;
+}
+
+.rsbuild-ssr-card .eyebrow {
+ color: #ffbc7c;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+
+.rsbuild-ssr-card h2 {
+ font-size: 2rem;
+}
+
+.rsbuild-ssr-card button {
+ background: #ffbc7c;
+ border: 0;
+ cursor: pointer;
+ padding: 12px;
+}
diff --git a/apps/rsbuild-ssr-remote/src/components/StatusCard.tsx b/apps/rsbuild-ssr-remote/src/components/StatusCard.tsx
new file mode 100644
index 0000000..68c0080
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/components/StatusCard.tsx
@@ -0,0 +1,28 @@
+import { useHostName } from "example-host-context";
+import { useEffect, useState } from "react";
+import "./StatusCard.css";
+
+export default function StatusCard() {
+ const hostName = useHostName();
+ const [count, setCount] = useState(0);
+ const [hydrated, setHydrated] = useState(false);
+
+ useEffect(() => {
+ setHydrated(true);
+ }, []);
+
+ return (
+
+ Federated SSR from Rsbuild
+
+ {hydrated ? "Hydrated on the host" : "Rendered on the server"}
+
+ Server-rendered by an Rsbuild remote.
+ The host's server loaded this card from the remote's async-node container.
+ Host: {hostName}
+ setCount((value) => value + 1)}>
+ Remote count {count}
+
+
+ );
+}
diff --git a/apps/rsbuild-ssr-remote/src/routeTree.gen.ts b/apps/rsbuild-ssr-remote/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/rsbuild-ssr-remote/src/router.tsx b/apps/rsbuild-ssr-remote/src/router.tsx
new file mode 100644
index 0000000..673839e
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/router.tsx
@@ -0,0 +1,12 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({ defaultPreload: "intent", routeTree, scrollRestoration: true });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/rsbuild-ssr-remote/src/routes/__root.tsx b/apps/rsbuild-ssr-remote/src/routes/__root.tsx
new file mode 100644
index 0000000..2eb5fe8
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/routes/__root.tsx
@@ -0,0 +1,36 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ href: stylesHref, rel: "stylesheet" }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ ],
+ }),
+ component: Root,
+});
+
+function Root() {
+ return (
+
+
+
+ );
+}
+
+function Document({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/rsbuild-ssr-remote/src/routes/index.tsx b/apps/rsbuild-ssr-remote/src/routes/index.tsx
new file mode 100644
index 0000000..badc535
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/routes/index.tsx
@@ -0,0 +1,14 @@
+import { createFileRoute } from "@tanstack/react-router";
+import StatusCard from "../components/StatusCard";
+
+export const Route = createFileRoute("/")({ component: Home });
+
+function Home() {
+ return (
+
+ Rsbuild SSR remote
+ Rspack-built SSR remote.
+
+
+ );
+}
diff --git a/apps/rsbuild-ssr-remote/src/styles.css b/apps/rsbuild-ssr-remote/src/styles.css
new file mode 100644
index 0000000..fbab7d3
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/src/styles.css
@@ -0,0 +1,22 @@
+:root {
+ background: #16110d;
+ color: #fff3e8;
+ font-family: system-ui, sans-serif;
+}
+body {
+ margin: 0;
+}
+.page-shell {
+ width: min(760px, calc(100% - 40px));
+ margin: 0 auto;
+ padding: 80px 0;
+}
+.eyebrow {
+ color: #ffbc7c;
+ font-family: monospace;
+ text-transform: uppercase;
+}
+h1 {
+ font-size: clamp(3rem, 10vw, 6rem);
+ margin: 12px 0 48px;
+}
diff --git a/apps/rsbuild-ssr-remote/tsconfig.json b/apps/rsbuild-ssr-remote/tsconfig.json
new file mode 100644
index 0000000..0416574
--- /dev/null
+++ b/apps/rsbuild-ssr-remote/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "rsbuild.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/vite-host/package.json b/apps/vite-host/package.json
new file mode 100644
index 0000000..c822690
--- /dev/null
+++ b/apps/vite-host/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "tanstack-start-vite-host",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "vite build",
+ "dev": "vite dev --port 3000 --strictPort",
+ "start": "vite --host 127.0.0.1 --port 3000 --strictPort",
+ "preview": "vite preview --host 127.0.0.1 --port 3000 --strictPort",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/tanstack": "workspace:*",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "@vitejs/plugin-react": "6.1.2",
+ "typescript": "7.0.2",
+ "vite": "8.3.2"
+ }
+}
diff --git a/apps/vite-host/src/components/RemoteBoundary.tsx b/apps/vite-host/src/components/RemoteBoundary.tsx
new file mode 100644
index 0000000..7e953b5
--- /dev/null
+++ b/apps/vite-host/src/components/RemoteBoundary.tsx
@@ -0,0 +1,28 @@
+import { Component, Suspense, type ReactNode } from "react";
+
+type Props = { children: ReactNode; fallback: string; name: string };
+
+/** Keeps a failed remote from taking down the host route. */
+export class RemoteBoundary extends Component {
+ state = { failed: false };
+
+ static getDerivedStateFromError() {
+ return { failed: true };
+ }
+
+ componentDidCatch(error: unknown) {
+ console.warn(`[${this.props.name}] remote failed to render`, error);
+ }
+
+ render() {
+ if (this.state.failed) {
+ return {this.props.name} is unavailable
;
+ }
+
+ return (
+ {this.props.fallback}}>
+ {this.props.children}
+
+ );
+ }
+}
diff --git a/apps/vite-host/src/remote.d.ts b/apps/vite-host/src/remote.d.ts
new file mode 100644
index 0000000..9342b12
--- /dev/null
+++ b/apps/vite-host/src/remote.d.ts
@@ -0,0 +1,20 @@
+declare module "tanstack_vite_remote/StatusCard" {
+ import type { ComponentType } from "react";
+
+ const StatusCard: ComponentType;
+ export default StatusCard;
+}
+
+declare module "tanstack_rsbuild_remote/StatusCard" {
+ import type { ComponentType } from "react";
+
+ const StatusCard: ComponentType;
+ export default StatusCard;
+}
+
+declare module "tanstack_rsbuild_ssr_remote/StatusCard" {
+ import type { ComponentType } from "react";
+
+ const StatusCard: ComponentType;
+ export default StatusCard;
+}
diff --git a/apps/vite-host/src/routeTree.gen.ts b/apps/vite-host/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/vite-host/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/vite-host/src/router.tsx b/apps/vite-host/src/router.tsx
new file mode 100644
index 0000000..f8bf919
--- /dev/null
+++ b/apps/vite-host/src/router.tsx
@@ -0,0 +1,16 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({
+ routeTree,
+ defaultPreload: "intent",
+ scrollRestoration: true,
+ });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/vite-host/src/routes/__root.tsx b/apps/vite-host/src/routes/__root.tsx
new file mode 100644
index 0000000..44dbaf4
--- /dev/null
+++ b/apps/vite-host/src/routes/__root.tsx
@@ -0,0 +1,40 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import { HostContext } from "example-host-context";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ rel: "stylesheet", href: stylesHref }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ { title: "TanStack Start federation Vite host" },
+ ],
+ }),
+ component: RootComponent,
+});
+
+function RootComponent() {
+ return (
+
+
+
+
+
+ );
+}
+
+function RootDocument({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/vite-host/src/routes/index.tsx b/apps/vite-host/src/routes/index.tsx
new file mode 100644
index 0000000..d889520
--- /dev/null
+++ b/apps/vite-host/src/routes/index.tsx
@@ -0,0 +1,89 @@
+import { getRemoteStylesheets, lazyRemote } from "@module-federation/tanstack/runtime";
+import { createFileRoute } from "@tanstack/react-router";
+import { useEffect, useState } from "react";
+import { RemoteBoundary } from "../components/RemoteBoundary";
+
+// Unlike React.lazy, lazyRemote loads again after a failure, so a server that hit a remote
+// outage renders the remote once it is back.
+const RemoteStatusCard = lazyRemote(() => import("tanstack_vite_remote/StatusCard"));
+const RsbuildStatusCard = lazyRemote(() => import("tanstack_rsbuild_remote/StatusCard"));
+const RsbuildSsrStatusCard = lazyRemote(() => import("tanstack_rsbuild_ssr_remote/StatusCard"));
+
+// Manifests of the remotes this route renders on the server.
+const serverRenderedManifests = [
+ "http://127.0.0.1:3001/mf-manifest.json",
+ "http://127.0.0.1:3004/mf-manifest.json",
+];
+
+export const Route = createFileRoute("/")({
+ // Loading the server-rendered remotes before render puts their markup in the response.
+ // An unavailable remote must not fail the route: its boundary renders a fallback.
+ loader: async () => {
+ const [stylesheets] = await Promise.all([
+ Promise.all(
+ serverRenderedManifests.map((manifest) =>
+ getRemoteStylesheets(manifest, "./StatusCard").catch(() => []),
+ ),
+ ).then((lists) => lists.flat()),
+ import("tanstack_vite_remote/StatusCard").catch(() => null),
+ import("tanstack_rsbuild_ssr_remote/StatusCard").catch(() => null),
+ ]);
+ return { stylesheets };
+ },
+ // The remote markup arrives with the HTML, so its stylesheets must too. Otherwise it stays
+ // unstyled until the remote's JavaScript loads.
+ head: ({ loaderData }) => ({
+ links: loaderData?.stylesheets.map((href) => ({ href, rel: "stylesheet" })),
+ }),
+ component: Home,
+});
+
+function Home() {
+ return (
+
+
+ TanStack Start × Module Federation
+ Two full-stack apps. One React tree.
+
+ This page belongs to the Vite host on port 3000. The Vite remote on port 3001 renders its
+ card on the server; the Rsbuild remote on port 3002 loads in the browser after hydration.
+
+
+
+
+
+ 01
+ Host route
+ Rendered by TanStack Start
+ The route, document shell, and server response come from the host app.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function RsbuildRemoteSlot() {
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+ }, []);
+
+ if (!mounted) return Rsbuild remote loads after hydration
;
+
+ return (
+
+
+
+ );
+}
diff --git a/apps/vite-host/src/styles.css b/apps/vite-host/src/styles.css
new file mode 100644
index 0000000..47b0470
--- /dev/null
+++ b/apps/vite-host/src/styles.css
@@ -0,0 +1,139 @@
+:root {
+ color: #e9efe9;
+ background: #101411;
+ font-family: "Avenir Next", "Trebuchet MS", sans-serif;
+ font-synthesis: none;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-width: 320px;
+ min-height: 100vh;
+ background:
+ linear-gradient(rgba(143, 255, 184, 0.045) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(143, 255, 184, 0.045) 1px, transparent 1px),
+ radial-gradient(circle at 82% 8%, rgba(62, 133, 91, 0.24), transparent 35%), #101411;
+ background-size:
+ 40px 40px,
+ 40px 40px,
+ auto;
+}
+
+button {
+ font: inherit;
+}
+
+.page-shell {
+ width: min(1120px, calc(100% - 40px));
+ margin: 0 auto;
+ padding: 88px 0 72px;
+}
+
+.hero {
+ max-width: 820px;
+ animation: rise 520ms ease-out both;
+}
+
+.eyebrow,
+.card-label,
+.card-index {
+ font-family: "SFMono-Regular", Consolas, monospace;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.eyebrow {
+ color: #8fffb8;
+ font-size: 0.78rem;
+}
+
+h1 {
+ margin: 18px 0 20px;
+ max-width: 760px;
+ font-size: clamp(3rem, 8vw, 6.8rem);
+ line-height: 0.94;
+ letter-spacing: -0.065em;
+}
+
+.lede {
+ max-width: 650px;
+ color: #aeb9b1;
+ font-size: 1.08rem;
+ line-height: 1.7;
+}
+
+.proof-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 18px;
+ margin-top: 64px;
+}
+
+.host-card,
+.remote-loading {
+ min-height: 300px;
+ border: 1px solid #344239;
+ padding: 30px;
+}
+
+.host-card {
+ position: relative;
+ background: rgba(20, 28, 23, 0.82);
+}
+
+.card-index {
+ position: absolute;
+ top: 24px;
+ right: 26px;
+ color: #617066;
+ font-size: 0.72rem;
+}
+
+.card-label {
+ margin: 0 0 70px;
+ color: #8fffb8;
+ font-size: 0.72rem;
+}
+
+.host-card h2 {
+ margin: 0 0 14px;
+ font-size: 1.8rem;
+}
+
+.host-card p:last-child {
+ max-width: 390px;
+ color: #96a39a;
+ line-height: 1.65;
+}
+
+.remote-loading {
+ display: grid;
+ place-items: center;
+ color: #8fffb8;
+ font-family: "SFMono-Regular", Consolas, monospace;
+}
+
+@keyframes rise {
+ from {
+ opacity: 0;
+ transform: translateY(16px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@media (max-width: 760px) {
+ .page-shell {
+ padding-top: 56px;
+ }
+
+ .proof-grid {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/apps/vite-host/tsconfig.json b/apps/vite-host/tsconfig.json
new file mode 100644
index 0000000..189cae2
--- /dev/null
+++ b/apps/vite-host/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node", "vite/client"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/vite-host/vite.config.ts b/apps/vite-host/vite.config.ts
new file mode 100644
index 0000000..805fee3
--- /dev/null
+++ b/apps/vite-host/vite.config.ts
@@ -0,0 +1,45 @@
+import { tanstackStartModuleFederation } from "@module-federation/tanstack";
+import { tanstackStart } from "@tanstack/react-start/plugin/vite";
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ tanstackStartModuleFederation({
+ name: "tanstack_vite_host",
+ dts: false,
+ shared: {
+ // The root route renders the provider synchronously, so a Vite host must provide
+ // the package eagerly. "workspace:*" is not a semver range, hence requiredVersion.
+ "example-host-context": { eager: true, requiredVersion: "*", singleton: true },
+ },
+ remotes: {
+ tanstack_vite_remote: {
+ type: "module",
+ name: "tanstack_vite_remote",
+ entry: "http://127.0.0.1:3001/remoteEntry.js",
+ },
+ tanstack_rsbuild_remote: {
+ type: "global",
+ name: "tanstack_rsbuild_remote",
+ entry: "http://127.0.0.1:3002/mf-manifest.json",
+ },
+ tanstack_rsbuild_ssr_remote: {
+ type: "global",
+ name: "tanstack_rsbuild_ssr_remote",
+ entry: "http://127.0.0.1:3004/mf-manifest.json",
+ },
+ },
+ }),
+ tanstackStart(),
+ react(),
+ ],
+ server: {
+ port: 3000,
+ },
+ ssr: {
+ optimizeDeps: {
+ include: ["react", "react-dom"],
+ },
+ },
+});
diff --git a/apps/vite-remote/package.json b/apps/vite-remote/package.json
new file mode 100644
index 0000000..87f7d6a
--- /dev/null
+++ b/apps/vite-remote/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "tanstack-start-vite-remote",
+ "private": true,
+ "sideEffects": false,
+ "type": "module",
+ "scripts": {
+ "build": "vite build",
+ "dev": "vite dev --port 3001 --strictPort",
+ "start": "vite --host 127.0.0.1 --port 3001 --strictPort",
+ "preview": "vite preview --host 127.0.0.1 --port 3001 --strictPort",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@module-federation/runtime": "2.9.2",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-start": "1.168.60",
+ "example-host-context": "workspace:*",
+ "react": "19.3.0",
+ "react-dom": "19.3.0"
+ },
+ "devDependencies": {
+ "@module-federation/tanstack": "workspace:*",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "@types/react-dom": "19.3.0",
+ "@vitejs/plugin-react": "6.1.2",
+ "typescript": "7.0.2",
+ "vite": "8.3.2"
+ }
+}
diff --git a/apps/vite-remote/src/components/StatusCard.css b/apps/vite-remote/src/components/StatusCard.css
new file mode 100644
index 0000000..c8ab085
--- /dev/null
+++ b/apps/vite-remote/src/components/StatusCard.css
@@ -0,0 +1,77 @@
+.remote-card {
+ position: relative;
+ min-height: 300px;
+ border: 1px solid #7b4d26;
+ background: #241b14;
+ color: #e9efe9;
+ padding: 30px;
+ box-shadow: 14px 14px 0 #0a0d0b;
+ font-family: "Avenir Next", "Trebuchet MS", sans-serif;
+}
+
+.remote-card .card-index,
+.remote-card .card-label,
+.remote-card .remote-status,
+.remote-card button {
+ font-family: "SFMono-Regular", Consolas, monospace;
+}
+
+.remote-card .card-index,
+.remote-card .card-label,
+.remote-card .remote-status {
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+.remote-card .card-index {
+ position: absolute;
+ top: 24px;
+ right: 26px;
+ color: #8f6d4e;
+ font-size: 0.72rem;
+}
+
+.remote-card .card-label {
+ margin: 0 0 58px;
+ color: #f4a95f;
+ font-size: 0.75rem;
+}
+
+.remote-card .remote-status {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ color: #c4cfca;
+ font-size: 0.66rem;
+}
+
+.remote-card .status-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #8fffb8;
+ box-shadow: 0 0 10px rgba(143, 255, 184, 0.72);
+}
+
+.remote-card h2 {
+ margin: 22px 0 12px;
+ font-size: 1.8rem;
+}
+
+.remote-card > p:not(.card-label) {
+ color: #aeb9b1;
+ line-height: 1.65;
+}
+
+.remote-card button {
+ margin-top: 24px;
+ border: 0;
+ background: #f4a95f;
+ color: #17120e;
+ cursor: pointer;
+ padding: 12px 16px;
+}
+
+.remote-card button:hover {
+ background: #ffc27f;
+}
diff --git a/apps/vite-remote/src/components/StatusCard.tsx b/apps/vite-remote/src/components/StatusCard.tsx
new file mode 100644
index 0000000..d60e898
--- /dev/null
+++ b/apps/vite-remote/src/components/StatusCard.tsx
@@ -0,0 +1,30 @@
+import { useHostName } from "example-host-context";
+import { useEffect, useState } from "react";
+import "./StatusCard.css";
+
+export default function StatusCard() {
+ const hostName = useHostName();
+ const [count, setCount] = useState(0);
+ const [hydrated, setHydrated] = useState(false);
+
+ useEffect(() => {
+ setHydrated(true);
+ }, []);
+
+ return (
+
+ 02
+ Federated route module
+
+
+ {hydrated ? "Hydrated on the host" : "Rendered on the server"}
+
+ Owned by the remote app
+ This component crossed an application boundary while React stayed a shared singleton.
+ Host: {hostName}
+ setCount((value) => value + 1)}>
+ Remote count {count}
+
+
+ );
+}
diff --git a/apps/vite-remote/src/routeTree.gen.ts b/apps/vite-remote/src/routeTree.gen.ts
new file mode 100644
index 0000000..dceedff
--- /dev/null
+++ b/apps/vite-remote/src/routeTree.gen.ts
@@ -0,0 +1,68 @@
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file was automatically generated by TanStack Router.
+// You should NOT make any changes in this file as it will be overwritten.
+// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
+
+import { Route as rootRouteImport } from './routes/__root'
+import { Route as IndexRouteImport } from './routes/index'
+
+const IndexRoute = IndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => rootRouteImport,
+} as any)
+
+export interface FileRoutesByFullPath {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesByTo {
+ '/': typeof IndexRoute
+}
+export interface FileRoutesById {
+ __root__: typeof rootRouteImport
+ '/': typeof IndexRoute
+}
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath
+ fullPaths: '/'
+ fileRoutesByTo: FileRoutesByTo
+ to: '/'
+ id: '__root__' | '/'
+ fileRoutesById: FileRoutesById
+}
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute
+}
+
+declare module '@tanstack/react-router' {
+ interface FileRoutesByPath {
+ '/': {
+ id: '/'
+ path: '/'
+ fullPath: '/'
+ preLoaderRoute: typeof IndexRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ }
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+}
+export const routeTree = rootRouteImport
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/apps/vite-remote/src/router.tsx b/apps/vite-remote/src/router.tsx
new file mode 100644
index 0000000..f8bf919
--- /dev/null
+++ b/apps/vite-remote/src/router.tsx
@@ -0,0 +1,16 @@
+import { createRouter } from "@tanstack/react-router";
+import { routeTree } from "./routeTree.gen";
+
+export function getRouter() {
+ return createRouter({
+ routeTree,
+ defaultPreload: "intent",
+ scrollRestoration: true,
+ });
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/apps/vite-remote/src/routes/__root.tsx b/apps/vite-remote/src/routes/__root.tsx
new file mode 100644
index 0000000..987b3fc
--- /dev/null
+++ b/apps/vite-remote/src/routes/__root.tsx
@@ -0,0 +1,37 @@
+import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
+import type { ReactNode } from "react";
+import stylesHref from "../styles.css?url";
+
+export const Route = createRootRoute({
+ head: () => ({
+ links: [{ rel: "stylesheet", href: stylesHref }],
+ meta: [
+ { charSet: "utf-8" },
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
+ { title: "TanStack Start federation Vite remote" },
+ ],
+ }),
+ component: RootComponent,
+});
+
+function RootComponent() {
+ return (
+
+
+
+ );
+}
+
+function RootDocument({ children }: { children: ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/apps/vite-remote/src/routes/index.tsx b/apps/vite-remote/src/routes/index.tsx
new file mode 100644
index 0000000..b1a59cd
--- /dev/null
+++ b/apps/vite-remote/src/routes/index.tsx
@@ -0,0 +1,22 @@
+import { createFileRoute } from "@tanstack/react-router";
+import StatusCard from "../components/StatusCard";
+
+export const Route = createFileRoute("/")({
+ component: Home,
+});
+
+function Home() {
+ return (
+
+
+
Standalone remote
+
This is a complete TanStack Start app.
+
+ It owns a route and a server build, then exposes the same component to the host through
+ Module Federation.
+
+
+
+
+ );
+}
diff --git a/apps/vite-remote/src/styles.css b/apps/vite-remote/src/styles.css
new file mode 100644
index 0000000..2db3a3d
--- /dev/null
+++ b/apps/vite-remote/src/styles.css
@@ -0,0 +1,59 @@
+:root {
+ color: #e9efe9;
+ background: #101411;
+ font-family: "Avenir Next", "Trebuchet MS", sans-serif;
+ font-synthesis: none;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-width: 320px;
+ min-height: 100vh;
+ background: radial-gradient(circle at 75% 12%, rgba(231, 155, 76, 0.2), transparent 32%), #101411;
+}
+
+button {
+ font: inherit;
+}
+
+.remote-page {
+ display: grid;
+ grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);
+ align-items: center;
+ gap: 70px;
+ width: min(1050px, calc(100% - 40px));
+ min-height: 100vh;
+ margin: 0 auto;
+}
+
+.eyebrow {
+ font-family: "SFMono-Regular", Consolas, monospace;
+ color: #f4a95f;
+ font-size: 0.75rem;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+h1 {
+ margin: 18px 0 20px;
+ font-size: clamp(3rem, 6vw, 5.8rem);
+ line-height: 0.96;
+ letter-spacing: -0.06em;
+}
+
+.lede {
+ color: #aeb9b1;
+ line-height: 1.65;
+}
+
+@media (max-width: 780px) {
+ .remote-page {
+ grid-template-columns: 1fr;
+ gap: 40px;
+ padding: 56px 0;
+ }
+}
diff --git a/apps/vite-remote/tsconfig.json b/apps/vite-remote/tsconfig.json
new file mode 100644
index 0000000..189cae2
--- /dev/null
+++ b/apps/vite-remote/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"],
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "noEmit": true,
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022",
+ "types": ["node", "vite/client"],
+ "verbatimModuleSyntax": true
+ }
+}
diff --git a/apps/vite-remote/vite.config.ts b/apps/vite-remote/vite.config.ts
new file mode 100644
index 0000000..ca36c2a
--- /dev/null
+++ b/apps/vite-remote/vite.config.ts
@@ -0,0 +1,34 @@
+import { tanstackStartModuleFederation } from "@module-federation/tanstack";
+import { tanstackStart } from "@tanstack/react-start/plugin/vite";
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ tanstackStartModuleFederation({
+ name: "tanstack_vite_remote",
+ dts: false,
+ // Workspace dependencies declare "workspace:*", which is not a semver range.
+ shared: { "example-host-context": { requiredVersion: "*", singleton: true } },
+ exposes: {
+ "./StatusCard": "./src/components/StatusCard.tsx",
+ },
+ }),
+ tanstackStart(),
+ react(),
+ ],
+ server: {
+ port: 3001,
+ cors: true,
+ origin: "http://127.0.0.1:3001",
+ },
+ preview: {
+ port: 3001,
+ cors: true,
+ },
+ ssr: {
+ optimizeDeps: {
+ include: ["react", "react-dom"],
+ },
+ },
+});
diff --git a/docs/RELEASING.md b/docs/RELEASING.md
new file mode 100644
index 0000000..1909bc4
--- /dev/null
+++ b/docs/RELEASING.md
@@ -0,0 +1,77 @@
+---
+title: Releasing
+summary: Release and trusted npm publishing for @module-federation/tanstack.
+read_when:
+ - Preparing a release
+ - Updating release automation
+updated_at: 2026-10-07
+---
+
+# Releasing
+
+Add a Changeset to every user-visible package change:
+
+```bash
+pnpm changeset
+```
+
+Run the complete local gate before merging:
+
+```bash
+pnpm install --frozen-lockfile
+pnpm format:check
+pnpm typecheck
+pnpm build
+pnpm test
+pnpm pack:tanstack
+```
+
+The `Release Pull Request` workflow versions the package and updates its
+changelog. After merging that PR, publish from `main` with a GitHub Release
+whose tag exactly matches `packages/tanstack/package.json` (without a `v`), or
+dispatch `Release` with `version=latest`. Preview dispatches use `version=next`
+and publish to npm's `next` dist-tag.
+
+GitHub prerelease tags must match the prerelease version already committed in
+`packages/tanstack/package.json`. The workflow publishes that exact version to
+the `next` dist-tag.
+
+The publish workflow reruns the gate, checks that the source is reachable from
+`main`, uses npm provenance, and refuses to republish an existing version under
+a different dist-tag. It publishes through npm trusted publishing for
+repository `module-federation/tanstack`, workflow `release.yml`, environment
+`Publish`, so the repository needs a `Publish` environment.
+
+## First publish
+
+npm only lets a package that already exists name a trusted publisher, so the
+workflow cannot publish `@module-federation/tanstack` the first time. Bootstrap
+it once, as a maintainer with publish rights in the `@module-federation` npm
+organization:
+
+1. Publish a placeholder from an empty directory: a `package.json` with
+ `"name": "@module-federation/tanstack"` and `"version": "0.0.0"`, then
+ `npm publish --access public`.
+2. Add the trusted publisher on npmjs.com (package settings, "Trusted
+ Publisher", GitHub Actions) or with npm 11.10+:
+ `npm trust github @module-federation/tanstack --file release.yml --repo module-federation/tanstack --env Publish --allow-publish`.
+3. Release `0.1.0` through the workflow within two days: npm discards a trusted
+ publisher configuration that has not published by then.
+4. Deprecate the placeholder:
+ `npm deprecate @module-federation/tanstack@0.0.0 "Placeholder; use 0.1.0 or later."`
+
+Trusted publishing needs npm 11.5.1+ on Node 22.14+; the workflow's Node 24
+includes it. Releases after `0.1.0` need no manual step.
+
+The release gate builds the six example apps and checks their manifests and
+server bundles. It then runs the apps twice, as development servers and as
+production builds, and drives every host in headless Chromium: server-rendered
+remote markup for every Vite and Rsbuild host and remote pair (including
+concurrent first requests), remote stylesheets in the server response,
+hydration, remote interactivity, one shared React instance and context, no
+console errors, reachable manifest assets, the fallback and recovery when
+remotes go offline, and hosts that start during an outage rendering the remotes
+once they return.
+
+The test suite needs Chromium. Locally, run `pnpm exec playwright install
+chromium` once; the workflows install it before `pnpm test`.
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6ad1669
--- /dev/null
+++ b/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "mf-tanstack",
+ "private": true,
+ "packageManager": "pnpm@12.9.1",
+ "engines": {
+ "node": "^22.18.0 || ^24.11.0 || >=26.0.0"
+ },
+ "scripts": {
+ "build": "turbo run build",
+ "build:package": "pnpm --filter @module-federation/tanstack build",
+ "dev": "pnpm build:package && turbo run dev",
+ "test": "pnpm build && node --test --test-concurrency=1 test/*.test.mjs",
+ "typecheck": "turbo run typecheck",
+ "format": "prettier --write .",
+ "format:check": "prettier --check .",
+ "pack:tanstack": "pnpm --filter @module-federation/tanstack pack:dry",
+ "start": "pnpm build:package && turbo run start",
+ "preview": "pnpm build && turbo run preview",
+ "changeset": "changeset",
+ "changeset:status": "changeset status"
+ },
+ "devDependencies": {
+ "@changesets/cli": "3.0.3",
+ "playwright": "1.63.0",
+ "prettier": "3.9.9",
+ "turbo": "2.11.7",
+ "typescript": "7.0.2"
+ }
+}
diff --git a/packages/tanstack/CHANGELOG.md b/packages/tanstack/CHANGELOG.md
new file mode 100644
index 0000000..8486c6e
--- /dev/null
+++ b/packages/tanstack/CHANGELOG.md
@@ -0,0 +1,36 @@
+# Changelog
+
+## 0.1.0
+
+Initial release: Module Federation for TanStack Start on Vite and Rsbuild.
+
+- `@module-federation/tanstack/vite` (also the package root) wraps
+ `@module-federation/vite` with TanStack Start defaults: `remoteEntry.js`, a
+ manifest, entry-level host init, and environment-specific build targets.
+ Hosts share eager singleton `react` and `react-dom`, so a remote built by
+ another bundler cannot replace the host's React instance. It requires Vite 8
+ and stops with an error on older versions.
+- `@module-federation/tanstack/rsbuild` wraps
+ `@module-federation/rsbuild-plugin` with script-compatible browser output,
+ async startup, role-aware React sharing, and `publicPath: "auto"` for
+ remotes, so production remotes load from their own origin.
+- Requires `@module-federation/vite` 1.23.3, which fixes federated SSR of
+ CommonJS server containers and retries failed server-side remote loads.
+- Rsbuild SSR federation with `server: true`: remotes ship a Node container,
+ `remoteEntry.ssr.cjs`, with their browser assets and advertise it in their
+ manifest; hosts load remotes on the server from an async-node CommonJS build
+ that keeps `dist/server/index.js` as its entry.
+- Federated SSR for every host and remote pair: Vite hosts render Rsbuild
+ remotes built with `server: true`, and Rsbuild hosts render Vite remotes
+ through `@module-federation/vite`'s SSR loader.
+- `@module-federation/tanstack/node-entry-loader`: the runtime plugin Rsbuild
+ hosts use to load remote server entries. Failures throw `RemoteEntryError`
+ with the failing phase and the original cause.
+- `@module-federation/tanstack/runtime`: `lazyRemote`, a `React.lazy` that
+ loads a failed remote again instead of failing until the server restarts, and
+ `getRemoteStylesheets`, which reads a remote's stylesheets from its manifest
+ so server-rendered remote markup is styled before JavaScript loads.
+- Hosts that hit a remote outage, including at startup, render the remote again
+ once it returns, and every remote also runs as a standalone app.
+- Tested in development and production builds on Node 22.18, 24, and 26, with
+ Vite 8.3, Rsbuild 2.2, TanStack Start 1.168, and React 19.3.
diff --git a/packages/tanstack/LICENSE b/packages/tanstack/LICENSE
new file mode 100644
index 0000000..b0cebd8
--- /dev/null
+++ b/packages/tanstack/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Module Federation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/tanstack/README.md b/packages/tanstack/README.md
new file mode 100644
index 0000000..f54143b
--- /dev/null
+++ b/packages/tanstack/README.md
@@ -0,0 +1,224 @@
+# @module-federation/tanstack
+
+TanStack Start integration for Module Federation on Vite and Rsbuild. The
+adapter packages are optional peers, so importing one adapter does not resolve
+the other.
+
+## Support status
+
+| Host | Remote | Browser federation | Federated SSR |
+| ------- | ------- | ------------------ | ---------------------------------- |
+| Vite | Vite | Supported | Supported |
+| Vite | Rsbuild | Supported | Supported (remote: `server: true`) |
+| Rsbuild | Vite | Supported | Supported (host: `server: true`) |
+| Rsbuild | Rsbuild | Supported | Supported (both: `server: true`) |
+
+"Federated SSR" means the remote component is rendered into the host's initial
+HTML. Every row is covered by browser tests against both development servers
+and production builds: the remote hydrates, shares the host's React and
+context, responds to clicks, logs no errors, and the host falls back and
+recovers when the remote goes offline.
+
+## Vite
+
+```ts
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/vite";
+import { tanstackStart } from "@tanstack/react-start/plugin/vite";
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ tanstackStartModuleFederation({
+ name: "host",
+ remotes: {
+ remote: {
+ type: "module",
+ name: "remote",
+ entry: "https://example.test/remoteEntry.js",
+ },
+ },
+ }),
+ tanstackStart(),
+ react(),
+ ],
+});
+```
+
+Place the federation wrapper before `tanstackStart()`, followed by the React
+plugin. The root import (`@module-federation/tanstack`) is the same Vite
+adapter.
+
+Defaults:
+
+- `filename: "remoteEntry.js"`, `manifest: true`, and
+ `hostInitInjectLocation: "entry"`.
+- `react` and `react-dom` are shared singletons. When the config declares
+ `remotes`, they are also `eager`, so the host's own React stays in the share
+ scope and a remote built by another bundler cannot replace it. Remote-only
+ builds stay lazy.
+- Any entry you pass in `shared` replaces the default for that package.
+
+A Vite host renders before lazy shared modules resolve, so mark any other shared
+package the host imports from its entry or root route as `eager: true`, as the
+wrapper does for React. Remotes can keep their shares lazy.
+
+The wrapper omits the global Module Federation `target` option. TanStack
+Start's client and SSR environments need `@module-federation/vite` to select
+`web` and `node` independently.
+
+The Vite adapter requires Vite 8, like TanStack Start's own examples and
+`@vitejs/plugin-react` 6. It stops with an error on older versions, where
+`@module-federation/vite` cannot load remotes on the server.
+
+A Vite host renders Rsbuild remotes on the server when they are built with
+`server: true` (see below). Declare such a remote by its manifest, so the
+server can find the Node container:
+
+```ts
+remotes: {
+ rsbuild_remote: {
+ type: "global",
+ name: "rsbuild_remote",
+ entry: "https://example.test/mf-manifest.json",
+ },
+},
+```
+
+## Rsbuild
+
+```ts
+import { defineConfig } from "@rsbuild/core";
+import { pluginReact } from "@rsbuild/plugin-react";
+import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
+import { tanstackStartModuleFederation } from "@module-federation/tanstack/rsbuild";
+
+export default defineConfig({
+ plugins: [
+ pluginReact(),
+ tanstackStart(),
+ ...tanstackStartModuleFederation({
+ federation: {
+ name: "remote",
+ exposes: { "./StatusCard": "./src/StatusCard.tsx" },
+ },
+ }),
+ ],
+});
+```
+
+The adapter returns an array of Rsbuild plugins; spread it into `plugins`, after
+`tanstackStart()`. It emits script-compatible browser output, so the manifest
+can be consumed by Vite and Rsbuild hosts.
+
+Defaults:
+
+- `react` and `react-dom` are shared singletons, `eager` for hosts (configs with
+ `remotes`) and lazy for remote-only builds.
+- `experiments.asyncStartup: true`, so entries wait for shared modules before
+ running. Pass `experiments: { asyncStartup: false }` to opt out.
+- A remote's browser build uses `publicPath: "auto"`, so hosts on other origins
+ load its chunks from the remote. TanStack Start otherwise derives `/` from
+ `server.base`. An absolute asset prefix, such as a CDN URL, is kept.
+
+For hosts, set `shareStrategy: "loaded-first"`. With the default
+`version-first` strategy, the host fetches every remote's manifest during
+startup, and a single offline remote fails the whole page.
+
+### SSR federation
+
+Pass `server: true` (or an options object) to federate on the server:
+
+- **Remotes** (`exposes`) build a Node container, `remoteEntry.ssr.cjs`, next to
+ `remoteEntry.js` in `dist/client` (its chunks go in `dist/client/ssr/`), and
+ advertise it in `mf-manifest.json` as `ssrRemoteEntry`. Deploy `dist/client`
+ as usual; the container holds only the exposed modules, never the app's
+ server code. The remote's own server output is unchanged. Vite and Rsbuild
+ hosts can both render it.
+- **Hosts** (`remotes`) load remotes on the server through the Module
+ Federation Node runtime. TanStack Start's server output becomes async-node
+ CommonJS (`dist/server/index.cjs`), with `dist/server/index.js` re-exporting
+ it, so `rsbuild preview` and deployments that import `index.js` keep working.
+ The dev server writes its server bundle to
+ `node_modules/.cache/tanstack-start-federation/` instead, so a production
+ build in `dist/server` survives development sessions. Rsbuild remotes need
+ `server: true` too. Vite remotes need nothing extra on
+ their side, but the host must have `@module-federation/vite` (and its `vite`
+ peer) installed: their server entries are ES modules, loaded by that
+ package's SSR loader.
+
+When a remote's server entry cannot load, the host's runtime plugin throws a
+`RemoteEntryError` whose `phase` is `fetch`, `evaluate`, or `loader` and whose
+`cause` is the original error.
+
+## Rendering remotes on the server
+
+Hosts on either bundler render remotes the same way: load the remote in the
+route `loader`, render it with `lazyRemote` inside a Suspense and error
+boundary, and link its stylesheets from the route's `head`:
+
+```tsx
+import { getRemoteStylesheets, lazyRemote } from "@module-federation/tanstack/runtime";
+import { createFileRoute } from "@tanstack/react-router";
+
+const StatusCard = lazyRemote(() => import("remote/StatusCard"));
+
+export const Route = createFileRoute("/")({
+ // Loading the remote before rendering puts its markup in the server response.
+ // A failed load must not fail the route: the boundary renders a fallback.
+ loader: async () => {
+ const [stylesheets] = await Promise.all([
+ getRemoteStylesheets("https://remote.test/mf-manifest.json", "./StatusCard").catch(() => []),
+ import("remote/StatusCard").catch(() => null),
+ ]);
+ return { stylesheets };
+ },
+ head: ({ loaderData }) => ({
+ links: loaderData?.stylesheets.map((href) => ({ href, rel: "stylesheet" })),
+ }),
+ component: () => (
+
+
+
+ ),
+});
+```
+
+`RemoteBoundary` stands for any error boundary around a `Suspense`; the
+examples in `apps/` include one.
+
+- **`lazyRemote(load, { retryAfterMs })`** is `React.lazy` for remotes. A
+ `React.lazy` component that fails once stays failed, so a server that hit a
+ remote outage would render the fallback until it restarts. `lazyRemote` loads
+ again on the first render after `retryAfterMs` (5 seconds by default). The
+ import itself loads again after a failure too: `@module-federation/vite`
+ 1.23.3+ retries failed server loads, and the Rsbuild adapter removes a failed
+ remote module from Rspack's module cache.
+- **`getRemoteStylesheets(manifestUrl, expose, { maxAgeMs })`** lists the
+ stylesheets the remote's manifest declares for an expose, as absolute URLs. A
+ remote's CSS otherwise loads with its JavaScript, after the HTML, so the
+ server-rendered markup would be unstyled until then. It works in the browser
+ and on the server, reuses a fetched manifest for 30 seconds (`maxAgeMs`), and
+ rejects when the manifest is unreachable or does not list the expose.
+
+## Known limitations
+
+- In development, a Vite remote's server modules import React from the files
+ its dev server resolves, so host and remote must resolve React to the same
+ files, as they do in a monorepo. Production builds take React from the
+ host's share scope.
+- A Vite dev server injects CSS from JavaScript, so its manifest lists no
+ stylesheets and `getRemoteStylesheets` returns none for it in development.
+
+## Requirements
+
+- Node 22.18+, 24.11+, or 26+.
+- TanStack Start 1.167.43+ (the first release with the Rsbuild integration).
+- React 19, which the tests use. TanStack Start also accepts React 18, but as
+ of 1.168 its Rsbuild server build fails with it: TanStack Router imports
+ React's `use`, which React 18 lacks. React 18 with Vite builds but is
+ untested.
+- Vite: `@module-federation/vite` 1.23.3+ and `vite` 8.
+- Rsbuild: `@module-federation/rsbuild-plugin` and `@rsbuild/core`. An Rsbuild
+ host that renders Vite remotes on the server also needs
+ `@module-federation/vite` 1.23.3+ and `vite`.
diff --git a/packages/tanstack/package.json b/packages/tanstack/package.json
new file mode 100644
index 0000000..a9734d1
--- /dev/null
+++ b/packages/tanstack/package.json
@@ -0,0 +1,142 @@
+{
+ "name": "@module-federation/tanstack",
+ "version": "0.1.0",
+ "type": "module",
+ "description": "TanStack Start integration for Module Federation",
+ "license": "MIT",
+ "sideEffects": false,
+ "main": "./dist/index.cjs",
+ "module": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "require": {
+ "types": "./dist/index.d.cts",
+ "default": "./dist/index.cjs"
+ }
+ },
+ "./vite": {
+ "import": {
+ "types": "./dist/vite.d.ts",
+ "default": "./dist/vite.js"
+ },
+ "require": {
+ "types": "./dist/vite.d.cts",
+ "default": "./dist/vite.cjs"
+ }
+ },
+ "./rsbuild": {
+ "import": {
+ "types": "./dist/rsbuild.d.ts",
+ "default": "./dist/rsbuild.js"
+ },
+ "require": {
+ "types": "./dist/rsbuild.d.cts",
+ "default": "./dist/rsbuild.cjs"
+ }
+ },
+ "./node-entry-loader": {
+ "import": {
+ "types": "./dist/node-entry-loader.d.ts",
+ "default": "./dist/node-entry-loader.js"
+ },
+ "require": {
+ "types": "./dist/node-entry-loader.d.cts",
+ "default": "./dist/node-entry-loader.cjs"
+ }
+ },
+ "./runtime": {
+ "import": {
+ "types": "./dist/runtime.d.ts",
+ "default": "./dist/runtime.js"
+ },
+ "require": {
+ "types": "./dist/runtime.d.cts",
+ "default": "./dist/runtime.cjs"
+ }
+ },
+ "./package.json": "./package.json"
+ },
+ "files": [
+ "dist/**/*",
+ "README.md",
+ "CHANGELOG.md",
+ "LICENSE"
+ ],
+ "publishConfig": {
+ "access": "public",
+ "provenance": true
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/module-federation/tanstack.git",
+ "directory": "packages/tanstack"
+ },
+ "bugs": {
+ "url": "https://github.com/module-federation/tanstack/issues"
+ },
+ "homepage": "https://github.com/module-federation/tanstack#readme",
+ "keywords": [
+ "tanstack",
+ "tanstack-start",
+ "module-federation",
+ "microfrontend"
+ ],
+ "engines": {
+ "node": "^22.18.0 || ^24.11.0 || >=26.0.0"
+ },
+ "scripts": {
+ "build": "rslib build --lib cjs && rslib build --lib esm --no-clean",
+ "dev": "rslib build --watch",
+ "pack:dry": "npm pack --dry-run",
+ "prepack": "pnpm run build",
+ "prepublishOnly": "pnpm run typecheck && pnpm run build",
+ "typecheck": "tsc -p tsconfig.json --noEmit"
+ },
+ "peerDependencies": {
+ "@module-federation/rsbuild-plugin": "^2.9.0",
+ "@module-federation/vite": "^1.23.3",
+ "@rsbuild/core": "^2.0.0",
+ "@tanstack/react-start": "^1.167.43",
+ "react": ">=18.0.0",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@tanstack/react-start": {
+ "optional": true
+ },
+ "@module-federation/rsbuild-plugin": {
+ "optional": true
+ },
+ "@module-federation/vite": {
+ "optional": true
+ },
+ "@rsbuild/core": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ },
+ "devDependencies": {
+ "@module-federation/rsbuild-plugin": "2.9.2",
+ "@module-federation/runtime": "2.9.2",
+ "@module-federation/vite": "1.23.3",
+ "@rsbuild/core": "2.2.11",
+ "@rslib/core": "1.0.3",
+ "@tanstack/react-start": "1.168.60",
+ "@types/node": "26.6.4",
+ "@types/react": "19.3.0",
+ "react": "19.3.0",
+ "react-dom": "19.3.0",
+ "typescript": "7.0.2",
+ "vite": "8.3.2"
+ }
+}
diff --git a/packages/tanstack/rslib.config.ts b/packages/tanstack/rslib.config.ts
new file mode 100644
index 0000000..6ab4262
--- /dev/null
+++ b/packages/tanstack/rslib.config.ts
@@ -0,0 +1,42 @@
+import { defineConfig } from "@rslib/core";
+
+const entry = {
+ index: "./src/index.ts",
+ "node-entry-loader": "./src/node-entry-loader.ts",
+ rsbuild: "./src/rsbuild.ts",
+ runtime: "./src/runtime.ts",
+ shared: "./src/shared.ts",
+ vite: "./src/vite.ts",
+ "vite-compat": "./src/vite-compat.ts",
+};
+
+const output = {
+ distPath: { root: "./dist" },
+ sourceMap: { js: "source-map" },
+ target: "node",
+} as const;
+
+// The `build` script runs the CJS library first. With TypeScript 7, rsbuild-plugin-dts
+// renames every `.d.ts` in `dist` to `.d.cts` during the CJS pass, which would also
+// consume the ESM declarations if they were emitted first.
+export default defineConfig({
+ lib: [
+ {
+ bundle: false,
+ dts: { autoExtension: true },
+ format: "esm",
+ output,
+ redirect: { dts: { extension: true } },
+ source: { entry },
+ syntax: "es2022",
+ },
+ {
+ bundle: false,
+ dts: { autoExtension: true },
+ format: "cjs",
+ output,
+ source: { entry },
+ syntax: "es2022",
+ },
+ ],
+});
diff --git a/packages/tanstack/src/index.ts b/packages/tanstack/src/index.ts
new file mode 100644
index 0000000..24f205b
--- /dev/null
+++ b/packages/tanstack/src/index.ts
@@ -0,0 +1,4 @@
+// The root entrypoint remains Vite-compatible. Rsbuild users should import
+// `@module-federation/tanstack/rsbuild` so their installation never resolves
+// the Vite adapter.
+export { tanstackStartModuleFederation, type TanStackStartModuleFederationOptions } from "./vite";
diff --git a/packages/tanstack/src/node-entry-loader.ts b/packages/tanstack/src/node-entry-loader.ts
new file mode 100644
index 0000000..8d48f45
--- /dev/null
+++ b/packages/tanstack/src/node-entry-loader.ts
@@ -0,0 +1,269 @@
+import type { ModuleFederationRuntimePlugin } from "@module-federation/runtime";
+
+type LoadEntryArgs = Parameters>[0];
+type RemoteEntryExports = NonNullable;
+type RemoteInfo = LoadEntryArgs["remoteInfo"];
+type FederationHost = LoadEntryArgs["origin"];
+type NodeModule = typeof import("node:module");
+
+/** A remote's server entry failed to load. `phase` says which step failed; `cause` keeps the original error. */
+export class RemoteEntryError extends Error {
+ readonly phase: "fetch" | "evaluate" | "loader";
+ readonly remote: string;
+ readonly url: string;
+
+ constructor(
+ message: string,
+ options: { cause?: unknown; phase: RemoteEntryError["phase"]; remote: string; url: string },
+ ) {
+ super(message, { cause: options.cause });
+ this.name = "RemoteEntryError";
+ this.phase = options.phase;
+ this.remote = options.remote;
+ this.url = options.url;
+ }
+}
+
+/**
+ * Loads remote server entries for an Rsbuild host's server bundle.
+ *
+ * - CommonJS containers (Rsbuild remotes) are fetched and compiled here as CommonJS
+ * modules, so their own `import()` calls work. Module Federation's default Node loader
+ * evaluates them with `vm`, which Rsbuild's development runner cannot support.
+ * - ES module entries (Vite remotes) go to `@module-federation/vite`'s SSR loader, which
+ * handles both production builds and Vite dev servers. It is loaded with Node's
+ * `require`, not the bundle's, so its `import()` calls work in Rsbuild's runner too.
+ */
+export default function nodeEntryLoaderPlugin(): ModuleFederationRuntimePlugin {
+ return {
+ name: "tanstack-start-node-entry-loader",
+ async loadEntry(args) {
+ const { remoteInfo } = args;
+ if (!isNodeServer() || !/^https?:\/\//.test(remoteInfo.entry)) return undefined;
+ if (remoteInfo.type === "commonjs-module") return loadCommonJsEntry(remoteInfo);
+ if (remoteInfo.type === "module" || remoteInfo.type === "esm") return loadModuleEntry(args);
+ return undefined;
+ },
+ };
+}
+
+// Matches @module-federation/vite's SSR fetch timeout.
+const FETCH_TIMEOUT_MS = 10_000;
+
+function isNodeServer() {
+ return typeof process !== "undefined" && typeof process.getBuiltinModule === "function";
+}
+
+function nodeModule() {
+ return process.getBuiltinModule("node:module") as NodeModule;
+}
+
+/** Requires from the app, because the host's server bundle has no node_modules of its own. */
+function appRequires() {
+ const { createRequire } = nodeModule();
+ const path = process.getBuiltinModule("node:path") as typeof import("node:path");
+ // The app root first, then the entry script for servers started from elsewhere.
+ return [path.join(process.cwd(), "package.json"), process.argv[1]]
+ .filter((base): base is string => Boolean(base))
+ .map((base) => createRequire(base));
+}
+
+async function loadCommonJsEntry({ entry, entryGlobalName, name }: RemoteInfo) {
+ let source: string;
+ try {
+ const response = await fetch(entry, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
+ if (!response.ok) throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
+ source = await response.text();
+ } catch (cause) {
+ throw new RemoteEntryError(
+ `Could not fetch the server entry of remote "${name}" from ${entry}.`,
+ {
+ cause,
+ phase: "fetch",
+ remote: name,
+ url: entry,
+ },
+ );
+ }
+
+ let exports: Record;
+ try {
+ const Module = nodeModule() as unknown as new (id: string) => CompilableModule;
+ const container = new Module(entry);
+ container.filename = entry;
+ container.paths = appRequires()[0]?.resolve.paths("react") ?? [];
+ // What `require()` does with a file's source: Node compiles it as a CommonJS module
+ // whose `import()` calls use Node's own loader.
+ container._compile(source, entry, "commonjs");
+ exports = container.exports as Record;
+ } catch (cause) {
+ throw new RemoteEntryError(`The server entry of remote "${name}" threw while loading.`, {
+ cause,
+ phase: "evaluate",
+ remote: name,
+ url: entry,
+ });
+ }
+
+ const remoteEntry = (entryGlobalName && exports[entryGlobalName]) || exports;
+ if (!isRemoteEntry(remoteEntry)) {
+ throw new RemoteEntryError(
+ `The server entry of remote "${name}" did not export a federation container.`,
+ { phase: "evaluate", remote: name, url: entry },
+ );
+ }
+ return remoteEntry;
+}
+
+interface CompilableModule {
+ exports: unknown;
+ filename: string;
+ paths: string[];
+ _compile(source: string, filename: string, format?: "commonjs"): void;
+}
+
+function isRemoteEntry(value: unknown): value is RemoteEntryExports {
+ const candidate = value as Partial | undefined;
+ return typeof candidate?.get === "function" && typeof candidate.init === "function";
+}
+
+// Packages a Vite remote's server code may import directly, besides the host's shared
+// packages. Resolving them from the host keeps one copy of each in the process.
+const VITE_SHARED_PACKAGES = [
+ "@module-federation/runtime",
+ "@module-federation/runtime-core",
+ "@module-federation/sdk",
+ "react",
+ "react-dom",
+ "react/compiler-runtime",
+ "react/jsx-dev-runtime",
+ "react/jsx-runtime",
+];
+
+type ViteSsrEntryLoaderModule = {
+ default: (options: { resolvedShared: Record }) => ModuleFederationRuntimePlugin;
+ SsrEntryHttpError?: new (...args: never[]) => Error;
+};
+
+type ViteLoader = {
+ httpError?: ViteSsrEntryLoaderModule["SsrEntryHttpError"];
+ plugin: ModuleFederationRuntimePlugin;
+ require: NodeJS.Require;
+ resolvedShared: Record;
+};
+
+let viteLoader: ViteLoader | undefined;
+
+async function loadModuleEntry(args: LoadEntryArgs) {
+ const { entry, name } = args.remoteInfo;
+ viteLoader ??= createViteLoader(args);
+ // Shared modules the host loaded since the last remote are aligned too.
+ provideHostModules(args.origin, viteLoader.resolvedShared, viteLoader.require);
+
+ let remoteEntry: RemoteEntryExports | void;
+ try {
+ remoteEntry = await viteLoader.plugin.loadEntry?.(args);
+ } catch (cause) {
+ const { httpError } = viteLoader;
+ throw new RemoteEntryError(
+ `Could not load the server entry of remote "${name}" from ${entry}.`,
+ {
+ cause,
+ phase: httpError && cause instanceof httpError ? "fetch" : "evaluate",
+ remote: name,
+ url: entry,
+ },
+ );
+ }
+ // Without an entry the runtime would try its own Node loader, which cannot load ES
+ // modules without Node flags. Report the failure instead. The Vite loader returns
+ // nothing for an unreachable remote, so tell that case apart.
+ if (!remoteEntry) {
+ const reachable = await fetch(entry, {
+ method: "HEAD",
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
+ }).then(
+ (response) => response.ok,
+ () => false,
+ );
+ throw new RemoteEntryError(
+ reachable
+ ? `@module-federation/vite could not load the server entry of remote "${name}" ` +
+ `from ${entry}; its warnings have the cause.`
+ : `Could not reach remote "${name}" at ${entry}.`,
+ { phase: reachable ? "loader" : "fetch", remote: name, url: entry },
+ );
+ }
+ return remoteEntry;
+}
+
+function createViteLoader({ origin, remoteInfo }: LoadEntryArgs): ViteLoader {
+ const requires = appRequires();
+ const resolve = (specifier: string) => {
+ for (const require of requires) {
+ try {
+ return { path: require.resolve(specifier), require };
+ } catch {
+ // Try the next base.
+ }
+ }
+ return undefined;
+ };
+
+ const loader = resolve("@module-federation/vite/ssrEntryLoader");
+ if (!loader) {
+ throw new RemoteEntryError(
+ `Remote "${remoteInfo.name}" is a Vite remote. Add @module-federation/vite to the ` +
+ "host's dependencies to render it on the server.",
+ { phase: "loader", remote: remoteInfo.name, url: remoteInfo.entry },
+ );
+ }
+
+ const resolvedShared: Record = {};
+ for (const specifier of [...VITE_SHARED_PACKAGES, ...Object.keys(origin.options.shared)]) {
+ const resolved = resolve(specifier);
+ if (resolved) resolvedShared[specifier] = resolved.path;
+ }
+
+ // The loader is an ES module; Node 22.12+ requires it synchronously.
+ const loaderModule = loader.require(loader.path) as ViteSsrEntryLoaderModule;
+ return {
+ httpError: loaderModule.SsrEntryHttpError,
+ plugin: loaderModule.default({ resolvedShared }),
+ require: loader.require,
+ resolvedShared,
+ };
+}
+
+/**
+ * Vite remotes can import shared packages from node_modules instead of the share scope:
+ * a Vite dev server's module runner externalizes them, and resolved imports in production
+ * builds point there. The host bundles its own copies, so this registers them in Node's
+ * module cache under their node_modules paths. The process then keeps one React.
+ */
+function provideHostModules(
+ origin: FederationHost,
+ resolvedShared: Record,
+ require: NodeJS.Require,
+) {
+ const Module = nodeModule() as unknown as new (id: string) => CompilableModule & {
+ loaded: boolean;
+ };
+ for (const scope of Object.values(origin.shareScopeMap)) {
+ for (const [packageName, versions] of Object.entries(scope)) {
+ const filename = resolvedShared[packageName];
+ // Something already loaded this package from node_modules; nothing to align.
+ if (!filename || require.cache[filename]) continue;
+ const provided = Object.values(versions).find(
+ (shared) => shared.from === origin.name && shared.loaded && shared.lib,
+ );
+ if (!provided?.lib) continue;
+
+ const cached = new Module(filename);
+ cached.filename = filename;
+ cached.exports = provided.lib();
+ cached.loaded = true;
+ require.cache[filename] = cached as unknown as NodeJS.Module;
+ }
+ }
+}
diff --git a/packages/tanstack/src/rsbuild.ts b/packages/tanstack/src/rsbuild.ts
new file mode 100644
index 0000000..4852b64
--- /dev/null
+++ b/packages/tanstack/src/rsbuild.ts
@@ -0,0 +1,400 @@
+import { join } from "node:path";
+import {
+ pluginModuleFederation,
+ type ModuleFederationOptions,
+} from "@module-federation/rsbuild-plugin";
+import type { RsbuildPlugin } from "@rsbuild/core";
+import { defaultShared, eagerShared, resolveShared } from "./shared";
+
+type ModuleFederationOverride = Partial;
+
+type ClientFederationOptions = ModuleFederationOverride & {
+ chunkLoadingGlobal?: string;
+ environment?: string;
+ forceScriptOutput?: boolean;
+};
+
+type ServerFederationOptions =
+ | false
+ | (ModuleFederationOverride & {
+ chunkFilename?: string;
+ entryFilename?: string;
+ environment?: string;
+ forceCommonJsOutput?: boolean;
+ });
+
+export type TanStackStartRsbuildModuleFederationOptions = {
+ client?: ClientFederationOptions;
+ federation: ModuleFederationOptions;
+ /**
+ * Server-side federation. Pass `true` or an options object to enable it. Defaults to
+ * `false`: browser-only federation.
+ *
+ * - With `exposes`, the build adds a Node container, `remoteEntry.ssr.cjs`, next to the
+ * browser entry (its chunks go in `ssr/`) and advertises it in the browser manifest
+ * as `ssrRemoteEntry`.
+ * - With `remotes`, TanStack Start's server environment loads remotes through the
+ * Module Federation Node runtime, as async-node CommonJS (`dist/server/index.cjs`).
+ */
+ server?: ServerFederationOptions | true;
+};
+
+// The server container sits next to the manifest, like a Vite remote's SSR entry. Hosts
+// resolve its chunks from either the container URL (Module Federation's Node runtime) or
+// the manifest URL (`@module-federation/vite`), so both must share a directory. The
+// extension says the container is CommonJS.
+const SERVER_CONTAINER_FILENAME = "remoteEntry.ssr.cjs";
+const SERVER_CHUNK_DIR = "ssr";
+const SERVER_CONTAINER_ENVIRONMENT = "mf-server";
+const NODE_ENTRY_LOADER = "@module-federation/tanstack/node-entry-loader";
+
+/** Creates browser and optional SSR federation adapters for TanStack Start's Rsbuild integration. */
+export function tanstackStartModuleFederation({
+ client = {},
+ federation,
+ server = false,
+}: TanStackStartRsbuildModuleFederationOptions): RsbuildPlugin[] {
+ const {
+ chunkLoadingGlobal,
+ environment: clientEnvironment = "client",
+ forceScriptOutput = true,
+ ...clientOverrides
+ } = client;
+ const federationName = federation.name;
+ if (!federationName) throw new Error("federation.name is required");
+
+ const isHost = hasEntries(federation.remotes);
+ const isRemote = hasEntries(federation.exposes);
+ const serverEnabled = server !== false;
+ const exposesServerContainer = serverEnabled && isRemote;
+
+ const clientFederationOptions = withDefaults(
+ { ...federation, ...clientOverrides },
+ isHost ? eagerShared : defaultShared,
+ );
+ if (exposesServerContainer) advertiseServerContainer(clientFederationOptions);
+
+ const plugins: RsbuildPlugin[] = [
+ pluginModuleFederation(clientFederationOptions, {
+ environment: clientEnvironment,
+ target: "web",
+ }),
+ ...(isHost ? [remoteRetryPlugin()] : []),
+ clientCompatibilityPlugin({
+ chunkLoadingGlobal: chunkLoadingGlobal ?? `chunk_${federationName}`,
+ environment: clientEnvironment,
+ forceScriptOutput,
+ isRemote,
+ name: federationName,
+ }),
+ ];
+
+ if (!serverEnabled) return plugins;
+
+ const {
+ chunkFilename,
+ entryFilename,
+ environment: serverEnvironment = "ssr",
+ forceCommonJsOutput = true,
+ ...serverOverrides
+ } = server === true ? {} : server;
+
+ if (exposesServerContainer) {
+ const { remotes: _remotes, ...containerOptions } = { ...federation, ...serverOverrides };
+ plugins.push(
+ serverContainerEnvironmentPlugin({ clientEnvironment }),
+ pluginModuleFederation(
+ withDefaults(
+ {
+ ...containerOptions,
+ // The browser build owns the manifest and the federated types.
+ dev: false,
+ dts: false,
+ filename: SERVER_CONTAINER_FILENAME,
+ manifest: false,
+ },
+ defaultShared,
+ ),
+ { environment: SERVER_CONTAINER_ENVIRONMENT, target: "node" },
+ ),
+ );
+ }
+
+ if (isHost) {
+ // The host's own server bundle consumes remotes. Its container, if any, is built by the
+ // dedicated environment above, so TanStack's server output never contains one.
+ const { exposes: _exposes, ...hostOptions } = { ...federation, ...serverOverrides };
+ plugins.push(
+ pluginModuleFederation(
+ {
+ ...withDefaults(hostOptions, eagerShared),
+ manifest: false,
+ runtimePlugins: [...(hostOptions.runtimePlugins ?? []), NODE_ENTRY_LOADER],
+ },
+ { environment: serverEnvironment, target: "node" },
+ ),
+ serverCompatibilityPlugin({
+ chunkFilename:
+ chunkFilename ?? (forceCommonJsOutput ? `[id].${federationName}.cjs` : undefined),
+ entryFilename: entryFilename ?? (forceCommonJsOutput ? "[name].cjs" : undefined),
+ environment: serverEnvironment,
+ forceCommonJsOutput,
+ }),
+ );
+ }
+
+ return plugins;
+}
+
+export const pluginTanStackStartModuleFederation = tanstackStartModuleFederation;
+
+function isAbsoluteUrl(value: unknown): boolean {
+ return typeof value === "string" && /^[a-z][a-z\d+.-]*:\/\//i.test(value);
+}
+
+function hasEntries(value: unknown): boolean {
+ if (Array.isArray(value)) return value.length > 0;
+ return Boolean(value) && typeof value === "object" && Object.keys(value as object).length > 0;
+}
+
+function withDefaults(
+ options: ModuleFederationOptions,
+ sharedDefaults: Record,
+): ModuleFederationOptions {
+ return {
+ ...options,
+ filename: options.filename ?? "remoteEntry.js",
+ manifest: options.manifest ?? true,
+ shared: resolveShared(options.shared, sharedDefaults) as ModuleFederationOptions["shared"],
+ // TanStack Start imports React synchronously from its entries. Async startup waits for
+ // shared modules before running them, so lazy shares cannot fail with RUNTIME-006.
+ experiments: { asyncStartup: true, ...options.experiments },
+ };
+}
+
+/**
+ * Adds the Node container to the browser manifest, as Module Federation's dual-target
+ * build does. A Node consumer reads `ssrRemoteEntry` and fetches the container from the
+ * manifest's public path.
+ */
+function advertiseServerContainer(options: ModuleFederationOptions) {
+ const manifest = options.manifest === true ? {} : options.manifest;
+ if (!manifest) return;
+
+ const userAdditionalData = manifest.additionalData;
+ options.manifest = {
+ ...manifest,
+ async additionalData(context) {
+ const stats = (await userAdditionalData?.(context)) ?? context.stats;
+ Object.assign(stats.metaData, {
+ ssrRemoteEntry: { name: SERVER_CONTAINER_FILENAME, path: "", type: "commonjs-module" },
+ });
+ return stats;
+ },
+ };
+}
+
+/** Builds the remote's Node container in its own environment, into the browser output. */
+function serverContainerEnvironmentPlugin({
+ clientEnvironment,
+}: {
+ clientEnvironment: string;
+}): RsbuildPlugin {
+ return {
+ name: "tanstack-start-federation-server-container",
+ setup(api) {
+ // Module Federation validates its node environment in a `pre` hook, before TanStack
+ // Start defines its own environments, so this one is created bare and placed next to
+ // the browser output once the bundler configs exist.
+ api.modifyRsbuildConfig({
+ order: "pre",
+ handler(config) {
+ config.environments ??= {};
+ config.environments[SERVER_CONTAINER_ENVIRONMENT] = {
+ // Module Federation adds the container entry; the placeholder keeps the
+ // environment from bundling the application.
+ source: { entry: { [SERVER_CONTAINER_ENVIRONMENT]: "data:text/javascript," } },
+ // The output directory is shared with the browser build, which cleans it and
+ // emits the stylesheets.
+ output: { cleanDistPath: false, emitAssets: false, target: "node" },
+ };
+ },
+ });
+
+ api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
+ const clientConfig = bundlerConfigs?.find(({ name }) => name === clientEnvironment);
+ const containerConfig = bundlerConfigs?.find(
+ ({ name }) => name === SERVER_CONTAINER_ENVIRONMENT,
+ );
+ if (!containerConfig) return;
+ if (!clientConfig?.output?.path) {
+ throw new Error(
+ `TanStack Start's "${clientEnvironment}" environment was not found. ` +
+ "Register tanstackStart() before tanstackStartModuleFederation().",
+ );
+ }
+
+ // The container ships with the browser assets and loads its chunks over HTTP from
+ // the same public path.
+ const publicPath = clientConfig.output.publicPath;
+ containerConfig.output ||= {};
+ containerConfig.output.path = clientConfig.output.path;
+ containerConfig.output.filename = `${SERVER_CHUNK_DIR}/[name].js`;
+ containerConfig.output.chunkFilename = `${SERVER_CHUNK_DIR}/[id].[contenthash:8].js`;
+ containerConfig.output.publicPath =
+ typeof publicPath === "string" && publicPath !== "auto" ? publicPath : "auto";
+ });
+ },
+ };
+}
+
+const REMOTE_FAILURE_FACTORY = /(webpackRequire\.m\[id\]\s*=\s*\(\)\s*=>\s*\{)(\s*throw error;)/;
+
+/**
+ * Lets a host load a remote again after a failed load. Module Federation's bundler runtime
+ * replaces a remote module that failed with one that throws, and retries the load on the
+ * next import, but the module cache keeps the first failure's empty exports. A server
+ * that hit a remote outage, or started during one, would then never render that remote.
+ * Rspack's `strictModuleExceptionHandling` caches the error instead, so this removes the
+ * failed module from the cache.
+ */
+function remoteRetryPlugin(): RsbuildPlugin {
+ return {
+ name: "tanstack-start-federation-remote-retry",
+ setup(api) {
+ api.transform(
+ { test: /[\\/]@module-federation[\\/]webpack-bundler-runtime[\\/]dist[\\/]remotes\.c?js$/ },
+ ({ code }) =>
+ // One line, so the rest of the file keeps its positions.
+ code.replace(
+ REMOTE_FAILURE_FACTORY,
+ "$1 if (webpackRequire.c) delete webpackRequire.c[id];$2",
+ ),
+ );
+ },
+ };
+}
+
+function clientCompatibilityPlugin({
+ chunkLoadingGlobal,
+ environment,
+ forceScriptOutput,
+ isRemote,
+ name,
+}: {
+ chunkLoadingGlobal: string;
+ environment: string;
+ forceScriptOutput: boolean;
+ isRemote: boolean;
+ name: string;
+}): RsbuildPlugin {
+ return {
+ name: "tanstack-start-federation-client-compat",
+ setup(api) {
+ api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
+ for (const config of bundlerConfigs ?? []) {
+ if (config.name !== environment) continue;
+
+ config.output ||= {};
+ config.output.chunkFormat = "array-push";
+ config.output.chunkLoading = "jsonp";
+ config.output.chunkLoadingGlobal = chunkLoadingGlobal;
+ config.output.uniqueName ??= name;
+
+ // TanStack Start derives the public path from `server.base`, which Rsbuild always
+ // sets, so a remote ends up with a host-relative "/" in production. Hosts on other
+ // origins would then request its chunks from themselves. "auto" resolves them from
+ // the remote's own script and manifest URLs; an absolute URL (such as a CDN) is kept.
+ if (isRemote && !isAbsoluteUrl(config.output.publicPath)) {
+ config.output.publicPath = "auto";
+ }
+
+ if (forceScriptOutput) {
+ config.output.module = false;
+ const experiments = (config.experiments ??= {}) as { outputModule?: boolean };
+ experiments.outputModule = false;
+ }
+ }
+ });
+ },
+ };
+}
+
+function serverCompatibilityPlugin({
+ chunkFilename,
+ entryFilename,
+ environment,
+ forceCommonJsOutput,
+}: {
+ chunkFilename?: string;
+ entryFilename?: string;
+ environment: string;
+ forceCommonJsOutput: boolean;
+}): RsbuildPlugin {
+ return {
+ name: "tanstack-start-federation-ssr-compat",
+ setup(api) {
+ api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
+ for (const config of bundlerConfigs ?? []) {
+ if (config.name !== environment) continue;
+
+ config.output ||= {};
+ if (forceCommonJsOutput) {
+ config.output.filename = entryFilename ?? "[name].cjs";
+ config.output.chunkFilename =
+ chunkFilename ?? `[id].${config.output.uniqueName ?? "server"}.cjs`;
+ config.target = "async-node";
+ config.output.module = false;
+ config.output.chunkFormat = "commonjs";
+ config.output.chunkLoading = "async-node";
+ config.output.library = { type: "commonjs2" };
+ delete config.output.chunkLoadingGlobal;
+ } else {
+ if (entryFilename) config.output.filename = entryFilename;
+ if (chunkFilename) config.output.chunkFilename = chunkFilename;
+ }
+ }
+ });
+
+ if (!forceCommonJsOutput) return;
+
+ // async-node chunk loading reads chunks from disk, while the dev server runs the entry
+ // from memory. Writing the server output keeps both from the same compilation. The
+ // dev output goes to a cache directory: in `dist/server` it would replace a production
+ // build that `rsbuild preview` serves, and dev chunks share its chunk names.
+ api.modifyEnvironmentConfig((config, { name }) => {
+ if (name !== environment) return;
+ config.dev.writeToDisk = true;
+ if (api.context.action === "dev") {
+ config.output.distPath.root = join(
+ api.context.rootPath,
+ "node_modules",
+ ".cache",
+ "tanstack-start-federation",
+ environment,
+ );
+ }
+ });
+
+ // TanStack Start's preview server, and deployments built against it, import
+ // `dist/server/index.js`. Keep that entry as an ES module that re-exports the CommonJS
+ // bundle. With async startup, the bundle exports a promise that settles once
+ // federation has initialized.
+ api.processAssets(
+ { stage: "additional", environments: [environment] },
+ ({ assets, compilation, sources }) => {
+ if (!assets["index.cjs"] || assets["index.js"]) return;
+ compilation.emitAsset("index.js", new sources.RawSource(SERVER_ENTRY_SHIM));
+ },
+ );
+ },
+ };
+}
+
+const SERVER_ENTRY_SHIM = `import { createRequire } from "node:module";
+
+const server = await createRequire(import.meta.url)("./index.cjs");
+
+export const createServerEntry = server.createServerEntry;
+export default server.default;
+`;
diff --git a/packages/tanstack/src/runtime.ts b/packages/tanstack/src/runtime.ts
new file mode 100644
index 0000000..1c9ba22
--- /dev/null
+++ b/packages/tanstack/src/runtime.ts
@@ -0,0 +1,96 @@
+import { createElement, lazy, type ComponentProps, type ComponentType } from "react";
+
+export type LazyRemoteOptions = {
+ /** How long a failed load stays failed before a render tries again, in milliseconds. Defaults to 5 seconds. */
+ retryAfterMs?: number;
+};
+
+/**
+ * `React.lazy` for remote modules. A component from `React.lazy` that fails to load stays
+ * failed: on a server, every later request renders the same error, even once the remote
+ * is back. This one loads again on the first render after `retryAfterMs`.
+ *
+ * ```tsx
+ * const StatusCard = lazyRemote(() => import("remote/StatusCard"));
+ * ```
+ */
+export function lazyRemote>(
+ load: () => Promise<{ default: T }>,
+ { retryAfterMs = 5_000 }: LazyRemoteOptions = {},
+): ComponentType> {
+ let failedAt: number | undefined;
+ const create = () =>
+ lazy(() =>
+ load().catch((error: unknown) => {
+ failedAt = Date.now();
+ throw error;
+ }),
+ );
+ let current = create();
+
+ return function RemoteComponent(props: ComponentProps) {
+ // React renders again right after a load fails, to report the error. Waiting before a
+ // new attempt keeps that render from starting another load.
+ if (failedAt !== undefined && Date.now() - failedAt >= retryAfterMs) {
+ failedAt = undefined;
+ current = create();
+ }
+ return createElement(current as ComponentType>, props);
+ };
+}
+
+export type RemoteStylesheetOptions = {
+ /** How long a fetched manifest is reused, in milliseconds. Defaults to 30 seconds. */
+ maxAgeMs?: number;
+};
+
+type CssAssets = { async?: string[]; sync?: string[] };
+
+type RemoteManifest = {
+ exposes?: Array<{ assets?: { css?: CssAssets }; name?: string; path?: string }>;
+ metaData?: { publicPath?: string };
+};
+
+const manifests = new Map }>();
+
+/**
+ * Lists the stylesheets a remote's manifest declares for an exposed module, as absolute
+ * URLs. Return them from a route loader and render them in the route's `head`, so markup
+ * a remote rendered on the server is styled before the remote's JavaScript loads.
+ *
+ * Rejects when the manifest cannot be fetched or does not list `expose`.
+ */
+export async function getRemoteStylesheets(
+ manifestUrl: string,
+ expose: string,
+ { maxAgeMs = 30_000 }: RemoteStylesheetOptions = {},
+): Promise {
+ const manifest = await fetchManifest(manifestUrl, maxAgeMs);
+ const name = expose.replace(/^\.\//, "");
+ const exposed = manifest.exposes?.find(
+ (candidate) => candidate.path === expose || candidate.name === name,
+ );
+ if (!exposed) throw new Error(`${manifestUrl} does not expose "${expose}".`);
+
+ // "auto" means the assets sit next to the manifest.
+ const publicPath = manifest.metaData?.publicPath;
+ const base = new URL(publicPath && publicPath !== "auto" ? publicPath : ".", manifestUrl);
+ const { async = [], sync = [] } = exposed.assets?.css ?? {};
+ return [...new Set([...sync, ...async])].map((asset) => new URL(asset, base).href);
+}
+
+function fetchManifest(url: string, maxAgeMs: number) {
+ const cached = manifests.get(url);
+ if (cached && Date.now() - cached.fetchedAt < maxAgeMs) return cached.manifest;
+
+ const manifest = fetch(url).then(async (response) => {
+ if (!response.ok) throw new Error(`${url} responded with HTTP ${response.status}.`);
+ return (await response.json()) as RemoteManifest;
+ });
+ manifests.set(url, { fetchedAt: Date.now(), manifest });
+ // A failed fetch is not reused: the next call retries.
+ manifest.catch(() => {
+ if (manifests.get(url)?.manifest === manifest) manifests.delete(url);
+ });
+ return manifest;
+}
diff --git a/packages/tanstack/src/shared.ts b/packages/tanstack/src/shared.ts
new file mode 100644
index 0000000..20c04ec
--- /dev/null
+++ b/packages/tanstack/src/shared.ts
@@ -0,0 +1,31 @@
+export const defaultShared = {
+ react: { singleton: true },
+ "react-dom": { singleton: true },
+} as const;
+
+export const eagerShared = {
+ react: { eager: true, singleton: true },
+ "react-dom": { eager: true, singleton: true },
+} as const;
+
+export function resolveShared(
+ shared: unknown,
+ defaults: Record = defaultShared,
+): Record {
+ if (Array.isArray(shared)) {
+ return {
+ ...defaults,
+ ...Object.fromEntries(
+ shared
+ .filter((packageName): packageName is string => typeof packageName === "string")
+ .filter((packageName) => !Object.hasOwn(defaults, packageName))
+ .map((packageName) => [packageName, {}]),
+ ),
+ };
+ }
+
+ return {
+ ...defaults,
+ ...(shared && typeof shared === "object" ? shared : {}),
+ };
+}
diff --git a/packages/tanstack/src/vite-compat.ts b/packages/tanstack/src/vite-compat.ts
new file mode 100644
index 0000000..ec82983
--- /dev/null
+++ b/packages/tanstack/src/vite-compat.ts
@@ -0,0 +1,22 @@
+import type { Plugin } from "vite";
+
+/**
+ * Fails fast on Vite 7 and older. `@module-federation/vite` loads remotes on the server
+ * only through Vite 8's module runner and Rolldown output, so federated SSR breaks
+ * silently on older versions.
+ */
+export function viteVersionPlugin(): Plugin {
+ return {
+ name: "tanstack-start-federation:vite-version",
+ enforce: "pre",
+ config() {
+ const version = this.meta.viteVersion;
+ const major = Number(version?.split(".")[0]);
+ if (major < 8) {
+ throw new Error(
+ `@module-federation/tanstack requires Vite 8; this project runs Vite ${version}.`,
+ );
+ }
+ },
+ };
+}
diff --git a/packages/tanstack/src/vite.ts b/packages/tanstack/src/vite.ts
new file mode 100644
index 0000000..ed974e1
--- /dev/null
+++ b/packages/tanstack/src/vite.ts
@@ -0,0 +1,36 @@
+import { federation, type ModuleFederationOptions } from "@module-federation/vite";
+import type { Plugin } from "vite";
+import { defaultShared, eagerShared, resolveShared } from "./shared";
+import { viteVersionPlugin } from "./vite-compat";
+
+export type TanStackStartModuleFederationOptions = Omit;
+
+/** Creates one Vite federation plugin set for TanStack Start's client and SSR environments. */
+export function tanstackStartModuleFederation(
+ options: TanStackStartModuleFederationOptions,
+): Plugin[] {
+ const {
+ shared,
+ target: _environmentSpecificTarget,
+ ...configured
+ } = options as ModuleFederationOptions;
+
+ // A host renders with its own React before any remote registers a provider. Eager host
+ // shares keep that instance in the share scope, so remotes from other bundlers cannot
+ // replace it. Remote-only builds stay lazy and defer to the host.
+ const isHost = Object.keys(configured.remotes ?? {}).length > 0;
+
+ return [
+ viteVersionPlugin(),
+ ...federation({
+ ...configured,
+ filename: configured.filename ?? "remoteEntry.js",
+ manifest: configured.manifest ?? true,
+ hostInitInjectLocation: configured.hostInitInjectLocation ?? "entry",
+ shared: resolveShared(
+ shared,
+ isHost ? eagerShared : defaultShared,
+ ) as ModuleFederationOptions["shared"],
+ }),
+ ];
+}
diff --git a/packages/tanstack/tsconfig.json b/packages/tanstack/tsconfig.json
new file mode 100644
index 0000000..058e070
--- /dev/null
+++ b/packages/tanstack/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "compilerOptions": {
+ "allowImportingTsExtensions": true,
+ "forceConsistentCasingInFileNames": true,
+ "isolatedModules": true,
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "strict": true,
+ "noUncheckedIndexedAccess": true,
+ "rootDir": "./src",
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "noEmit": true,
+ "verbatimModuleSyntax": true
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["dist"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..b0c1c85
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,3425 @@
+---
+lockfileVersion: '9.0'
+
+importers:
+
+ .:
+ configDependencies: {}
+ packageManagerDependencies:
+ '@pnpm/exe':
+ specifier: 12.9.1
+ version: 12.9.1
+ pnpm:
+ specifier: 12.9.1
+ version: 12.9.1
+
+packages:
+
+ '@pnpm/exe.android-arm64@12.9.1':
+ resolution: {integrity: sha512-Hgm1XdqMTfBC8PdGLL+NjZWv4xyi7D6XNrN9fb24XGYlyTBmUtdCefKnCLmHujShRD8BEO1zqM30SNcKBDLysw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@pnpm/exe.android-x64@12.9.1':
+ resolution: {integrity: sha512-WDGCe6jZRVZP3RC/q6hOkZylkPkIQIi1/GcrR/d/YzbihhAHXCczrk+UYnV5TgbsEnAYO7Cx+2rX3nfhHvy24w==}
+ cpu: [x64]
+ os: [android]
+
+ '@pnpm/exe.darwin-arm64@12.9.1':
+ resolution: {integrity: sha512-+7iiEEBgYN9szPWUnAuN6eOVMTI6Hrki5bcuC9n9xl9tTnT53Tpxpo45Hml+W4IrAU0d+Tmd0sPnVIbX59PD6w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@pnpm/exe.darwin-x64@12.9.1':
+ resolution: {integrity: sha512-SK7TxJiR12GbJZGffRFHItkc+Mx+99v6xMMJ9/X//8NwWV1wo17a2bwfGI8qZpl17YwsrmPEFOOqhzE1GIlrtQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@pnpm/exe.freebsd-x64@12.9.1':
+ resolution: {integrity: sha512-4AjLk6uvTs2iO6wMit2hcxJ2M32xb7OV5SNFk+w6G8/NzcjcMB7ENEpyeXyLiP0kcnp8uaCGUct2NfrLCJ35eQ==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@pnpm/exe.linux-arm64-musl@12.9.1':
+ resolution: {integrity: sha512-dZL2ES1ckDWM9v+EtxoOklZ0WNdtayooi9iLiDUubopudX3zXPNR2mlrxBRgjbDgECOndQen2SmyxL5eZiBuKw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@pnpm/exe.linux-arm64@12.9.1':
+ resolution: {integrity: sha512-cx+uF6xqwEtm7B8NV+1ve0xBg9gcuzQZ5R+0WgOWvKG/h978UljS6BgWs1ipIGuGgUdeVhm3PKmBltXIcczLXA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-ppc64@12.9.1':
+ resolution: {integrity: sha512-MpjPsy4XR17zAtLziQZfsN+wveWa/bUJggZtwfo3+SuyRmXnSvVkFD4+v8/3RTWyYaM6mwLUTjZDJ+g3urL+ew==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-riscv64@12.9.1':
+ resolution: {integrity: sha512-Oo67TKqqH+Bno+L6X7Xyorwp1QG82zKIkL0vbo1x2kcPTDiyPbdM+d6lIs4+hzeB1KHT5FDoGzZj2dad7Ft+eg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-s390x@12.9.1':
+ resolution: {integrity: sha512-QAD5FRCdW36HfD58BV7DoDm6z8yv+GgSqcUV1+ERwYjpVQuG6ZTpf5o0x3KDas8eTLIW7MLYVdDdlAurWeArEg==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.linux-x64-musl@12.9.1':
+ resolution: {integrity: sha512-mQDhBsGqcTkrLQM4q5igmRFcr6EAl4UM/FGawY+0CWGcqPpUmYUvDy9LHy80xxkHIWVJ886gvvso2XOjfav1Jw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@pnpm/exe.linux-x64@12.9.1':
+ resolution: {integrity: sha512-+M5N74hM4fc87AAckxx/UIW+dUnWf2eko+HchJs/NZUxehLhekNyMI/GNaNXlvd+kWR+97XXBD51XRkkNiUtrA==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@pnpm/exe.win32-arm64@12.9.1':
+ resolution: {integrity: sha512-mI28C2wxobrDi6x1OYhBRyG10hnDq/4sEIyy5RzoX6LB4kLuv6K/d25HOpMwlW20cuM4M72k9NZpOdcmUxMbEA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@pnpm/exe.win32-x64@12.9.1':
+ resolution: {integrity: sha512-SWoDMT0oD7NrDSIoPpkKD09D9fAQKNjwFZ3lezlCUhAfXxMv70zsfrNT2/P+GoCK2kefXF9OysUZkH1l5vvvfA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@pnpm/exe@12.9.1':
+ resolution: {integrity: sha512-TZOVvYq8nwzmw8IR3P1GKZk87tV7vDPCT3oJlL7IhgYNZfLGov4jX0J8RJxuAXxIT3uxg/uiconrLLBv+X5KyA==}
+ engines: {node: '>=18.*'}
+ hasBin: true
+
+ pnpm@12.9.1:
+ resolution: {integrity: sha512-BrBV//XNINwSeB3hc87TMQzglRvy7GICEaFgRdVETVyTpmMhB2TvKaZTphBFm6A2jw50+E2AxUcjz5Wq57wNbQ==}
+ engines: {node: '>=18.*'}
+ hasBin: true
+
+snapshots:
+
+ '@pnpm/exe.android-arm64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.android-x64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.darwin-arm64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.darwin-x64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.freebsd-x64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-arm64-musl@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-arm64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-ppc64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-riscv64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-s390x@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-x64-musl@12.9.1':
+ optional: true
+
+ '@pnpm/exe.linux-x64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.win32-arm64@12.9.1':
+ optional: true
+
+ '@pnpm/exe.win32-x64@12.9.1':
+ optional: true
+
+ '@pnpm/exe@12.9.1':
+ optionalDependencies:
+ '@pnpm/exe.android-arm64': 12.9.1
+ '@pnpm/exe.android-x64': 12.9.1
+ '@pnpm/exe.darwin-arm64': 12.9.1
+ '@pnpm/exe.darwin-x64': 12.9.1
+ '@pnpm/exe.freebsd-x64': 12.9.1
+ '@pnpm/exe.linux-arm64': 12.9.1
+ '@pnpm/exe.linux-arm64-musl': 12.9.1
+ '@pnpm/exe.linux-ppc64': 12.9.1
+ '@pnpm/exe.linux-riscv64': 12.9.1
+ '@pnpm/exe.linux-s390x': 12.9.1
+ '@pnpm/exe.linux-x64': 12.9.1
+ '@pnpm/exe.linux-x64-musl': 12.9.1
+ '@pnpm/exe.win32-arm64': 12.9.1
+ '@pnpm/exe.win32-x64': 12.9.1
+
+ pnpm@12.9.1:
+ optionalDependencies:
+ '@pnpm/exe.android-arm64': 12.9.1
+ '@pnpm/exe.android-x64': 12.9.1
+ '@pnpm/exe.darwin-arm64': 12.9.1
+ '@pnpm/exe.darwin-x64': 12.9.1
+ '@pnpm/exe.freebsd-x64': 12.9.1
+ '@pnpm/exe.linux-arm64': 12.9.1
+ '@pnpm/exe.linux-arm64-musl': 12.9.1
+ '@pnpm/exe.linux-ppc64': 12.9.1
+ '@pnpm/exe.linux-riscv64': 12.9.1
+ '@pnpm/exe.linux-s390x': 12.9.1
+ '@pnpm/exe.linux-x64': 12.9.1
+ '@pnpm/exe.linux-x64-musl': 12.9.1
+ '@pnpm/exe.win32-arm64': 12.9.1
+ '@pnpm/exe.win32-x64': 12.9.1
+
+---
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: false
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ '@changesets/cli':
+ specifier: 3.0.3
+ version: 3.0.3
+ playwright:
+ specifier: 1.63.0
+ version: 1.63.0
+ prettier:
+ specifier: 3.9.9
+ version: 3.9.9
+ turbo:
+ specifier: 2.11.7
+ version: 2.11.7
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+
+ apps/host-context:
+ devDependencies:
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+
+ apps/rsbuild-host:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/rsbuild-plugin':
+ specifier: 2.9.2
+ version: 2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@rsbuild/core':
+ specifier: 2.2.11
+ version: 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rsbuild/plugin-react':
+ specifier: 2.1.1
+ version: 2.1.1(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+
+ apps/rsbuild-remote:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/rsbuild-plugin':
+ specifier: 2.9.2
+ version: 2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@rsbuild/core':
+ specifier: 2.2.11
+ version: 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rsbuild/plugin-react':
+ specifier: 2.1.1
+ version: 2.1.1(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+
+ apps/rsbuild-ssr-host:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@module-federation/vite':
+ specifier: 1.23.3
+ version: 1.23.3(typescript@7.0.2)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/rsbuild-plugin':
+ specifier: 2.9.2
+ version: 2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@rsbuild/core':
+ specifier: 2.2.11
+ version: 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rsbuild/plugin-react':
+ specifier: 2.1.1
+ version: 2.1.1(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+ vite:
+ specifier: 8.3.2
+ version: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ apps/rsbuild-ssr-remote:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/rsbuild-plugin':
+ specifier: 2.9.2
+ version: 2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@rsbuild/core':
+ specifier: 2.2.11
+ version: 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rsbuild/plugin-react':
+ specifier: 2.1.1
+ version: 2.1.1(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+
+ apps/vite-host:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ '@vitejs/plugin-react':
+ specifier: 6.1.2
+ version: 6.1.2(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+ vite:
+ specifier: 8.3.2
+ version: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ apps/vite-remote:
+ dependencies:
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@tanstack/react-router':
+ specifier: 1.170.41
+ version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ example-host-context:
+ specifier: workspace:*
+ version: link:../host-context
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ devDependencies:
+ '@module-federation/tanstack':
+ specifier: workspace:*
+ version: link:../../packages/tanstack
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ '@types/react-dom':
+ specifier: 19.3.0
+ version: 19.3.0(@types/react@19.3.0)
+ '@vitejs/plugin-react':
+ specifier: 6.1.2
+ version: 6.1.2(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+ vite:
+ specifier: 8.3.2
+ version: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ packages/tanstack:
+ devDependencies:
+ '@module-federation/rsbuild-plugin':
+ specifier: 2.9.2
+ version: 2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/runtime':
+ specifier: 2.9.2
+ version: 2.9.2
+ '@module-federation/vite':
+ specifier: 1.23.3
+ version: 1.23.3(typescript@7.0.2)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@rsbuild/core':
+ specifier: 2.2.11
+ version: 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rslib/core':
+ specifier: 1.0.3
+ version: 1.0.3(@module-federation/runtime-tools@2.9.2)(typescript@7.0.2)
+ '@tanstack/react-start':
+ specifier: 1.168.60
+ version: 1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@types/node':
+ specifier: 26.6.4
+ version: 26.6.4
+ '@types/react':
+ specifier: 19.3.0
+ version: 19.3.0
+ react:
+ specifier: 19.3.0
+ version: 19.3.0
+ react-dom:
+ specifier: 19.3.0
+ version: 19.3.0(react@19.3.0)
+ typescript:
+ specifier: 7.0.2
+ version: 7.0.2
+ vite:
+ specifier: 8.3.2
+ version: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+packages:
+
+ '@ast-grep/napi-darwin-arm64@0.45.3':
+ resolution: {integrity: sha512-rMZJ6frSpR/xSbeV4hiA9WR5hHqk3rVYX8lOqEoUCaUnjEuFXvHdGN4WawJ8pVDq/IqM1UnTtsDSYgUdVmO5DA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@ast-grep/napi-darwin-x64@0.45.3':
+ resolution: {integrity: sha512-tIclZ5pM+YSgk8NNTBoTkaclbS39cU5lbVfSrFWX4LUnxXfUPG+F+ppxyFjKwJTBELsGHEO4LdX3/Lc+FDwPNA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@ast-grep/napi-linux-arm64-gnu@0.45.3':
+ resolution: {integrity: sha512-Bm8F7/oRHQkDXbjH+gBi9oB5huJ0q12r/AIOMIypf5PWlAVvh206Tsw468phw4Oh6kd4Ad1Z+gflNW1MutgK2g==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@ast-grep/napi-linux-arm64-musl@0.45.3':
+ resolution: {integrity: sha512-yr5xcRerV41GeRxmZ8SKbfGeyZRhQePoNNCgTAb4OrWMelWwbMI80aY7/IlF2bo1sN40BSW4hZdGIO/akTd1RQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@ast-grep/napi-linux-x64-gnu@0.45.3':
+ resolution: {integrity: sha512-lluRK3hxfHMQdFuVID6seAKVx4FH0kEwF6rCh5/I40Sf3EtNR2UCBXAqd6RBA6hqlSckktvBxCfw+h4aescDmg==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@ast-grep/napi-linux-x64-musl@0.45.3':
+ resolution: {integrity: sha512-09wJQKq86LqILqQtw0+X09SzhcPwUnMVFKyia7S3XLbLqSeQpAMF55Y+zll53JRQ1dCzFEZJyvTT/7j9vwfE3w==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@ast-grep/napi-win32-arm64-msvc@0.45.3':
+ resolution: {integrity: sha512-/HiVgw2cdtzXLDLoG4eBBcauekNXewfagy7qiVbjkVu/KcCH8dJ9lpj8DzeWwuBNtZxuD8jpiwP0M1pz3Bc3uw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@ast-grep/napi-win32-ia32-msvc@0.45.3':
+ resolution: {integrity: sha512-/gwJrJQUw65uNtAFcG2rtSTr117Gqqy3bfjaljCPKsa65dTeRcMMnjKLlZ6V9/g8z+4Xf78kdhp5ECbir4yfSw==}
+ engines: {node: '>= 10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@ast-grep/napi-win32-x64-msvc@0.45.3':
+ resolution: {integrity: sha512-CEZAMAsaDoQoVE3MT2c/ry3/ydfyaqlTjxv8DK5PG355SrdAYPgevGC2Me6tz4dhphJin89Y20VsnrS5UrYV5Q==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@ast-grep/napi@0.45.3':
+ resolution: {integrity: sha512-bjJsUt0g3UCwbn9bjv7MnoR15rszSm79yPCXn4DWWK0NuYUUqBU/srtNMR4WnpfR7TnfBRdYFoqSNx0pGCNWJg==}
+ engines: {node: '>= 10'}
+
+ '@babel/code-frame@7.29.7':
+ resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.7':
+ resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.7':
+ resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.8':
+ resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.29.7':
+ resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.29.7':
+ resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.29.7':
+ resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.29.7':
+ resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-string-parser@7.29.7':
+ resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.29.7':
+ resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.29.7':
+ resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.7':
+ resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.9':
+ resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/template@7.29.7':
+ resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.8':
+ resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.8':
+ resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@changesets/apply-release-plan@8.1.1':
+ resolution: {integrity: sha512-nk2Hbq3M9NeHMdaIRBDvawKrQJzXB9sGyBUE5yWnIKtvdcNCPj75zBekJYr0gTT2ecJH3eFeTrc8eisPImcv0Q==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/assemble-release-plan@7.0.0':
+ resolution: {integrity: sha512-oEW8BxdA604kGGtDSCiHr5w9Tv4UWe9I2k61IBNZzCOE1kbYaJj4v+lFQNgcEZFkUc2pV/+hASErGDvpJOZCTg==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/changelog-git@1.0.0':
+ resolution: {integrity: sha512-3Dst2Ime2Op5nd4XmWJLPIgp11ZFqJqSkVug9izK6TDcIV4YlhPS4ECbEVR+eGI0bk0r1ItogD4j2Oli87bJrA==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/cli@3.0.3':
+ resolution: {integrity: sha512-L1i67bMfkK6iC/kDejuNO4pFgTRcWIObsD6Qof2woP1I4M8tj17DGlcpRaTzTv1DYSP5EMwWdEtR8X0Pj5Jg3Q==}
+ engines: {node: ^22.11 || ^24 || >=26, npm: '>=10.9.0', pnpm: '>=10.0.0', yarn: '>=4.5.2'}
+ hasBin: true
+
+ '@changesets/config@4.0.1':
+ resolution: {integrity: sha512-PxpxSQLQSLDjceAgRq+4FWlU+HflDIw03mmPVipxoQx9xrXFUjmqTy3SE+n/2t+DqPdpPiLWVr5NRiLZvjyLwg==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/errors@1.0.0':
+ resolution: {integrity: sha512-ElN/mEzn6zmETgjwf5MclCMa9ef59sAR0lfO8VSYIsiRvbC2FbLB/92EoYw10Sl0kGixxHFiJZUSv7dA+YpR8g==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/format@0.1.2':
+ resolution: {integrity: sha512-Caez5XtNXCFS/G5bwyav3wuXL0tMxVd2ZGbaumWbzN08tyzO21asCw7JZhNtVsAZDCvDRUzZN+Iit9SyRITSYA==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/get-dependents-graph@3.0.0':
+ resolution: {integrity: sha512-ji/t5wFA1zREKXRUePE6Qi+Qu2UgxCeSSGQrphezwvQZrp49B7sJ+8+wvM0tA7zPeSxYKCojDy3WWgrl+s+awg==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/git@4.0.1':
+ resolution: {integrity: sha512-6vWpIAC4LkpmlqaIu37ViT5enyd9+uBwAiGqCGhASvkSHBgx4PrtTGXWTMFYpDmZbjgyonyVgMciPrW4MqtJsA==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/parse@1.0.0':
+ resolution: {integrity: sha512-P0iaMb9p9CRYZiTgAllEIF9AUMQHIy1G72tKlcIqJp61icZSsKQNiOPdxAMZG8m/DvZwt/oz5xEbTpike//dWg==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/pre@3.0.0':
+ resolution: {integrity: sha512-Zm/6YliV/a2oeWTqHJf6KxLrQwgcK1i/BRDl2m0EKZvbnxV5fG9QRhwJJGshjsZTUTS6dkfURQ2K6aAvgNw/3Q==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/read@1.0.1':
+ resolution: {integrity: sha512-nzvSC6RcTiWf/dsuwZFXpLzGGsRHYCL68U3uHV7srsulU93aVWY7u2GEJiDZ+4GIIElfaW5EqtKC0UHroY+LTQ==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/should-skip-package@1.0.0':
+ resolution: {integrity: sha512-pwqoJmbONn1XgXmZXPEExgAaT+HdZLjALFTDgIm+PnS5KeO2nLtzA2/Q+4aMFY14kFMuXKG30MObhvDzWgzDgg==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/types@7.0.0':
+ resolution: {integrity: sha512-c5GoiQyt3pxiXjrWSNoP8/GRf4kG+VnKzovx1OQM8dYYALlSwgedmkPmJ+ZqGxqwg9D3Bkj85Uo4KLd5BN3A0w==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@changesets/write@1.0.1':
+ resolution: {integrity: sha512-q/ThtP9gcnEP6xlv7LrY26C2mHqdGBti/MmOVngt/M/oIGYkssmQGxPK9WzBNt2juVcH/vml2WQ+ra8LXYOTaA==}
+ engines: {node: ^22.11 || ^24 || >=26}
+
+ '@clack/core@1.5.1':
+ resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==}
+ engines: {node: '>= 20.12.0'}
+
+ '@clack/prompts@1.8.1':
+ resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==}
+ engines: {node: '>= 20.12.0'}
+
+ '@emnapi/core@1.11.3':
+ resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==}
+
+ '@emnapi/runtime@1.11.3':
+ resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
+
+ '@emnapi/wasi-threads@1.2.3':
+ resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.6.0':
+ resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@manypkg/find-root@3.1.0':
+ resolution: {integrity: sha512-BcSqCyKhBVZ5YkSzOiheMCV41kqAFptW6xGqYSTjkVTl9XQpr+pqHhwgGCOHQtjDCv7Is6EFyA14Sm5GVbVABA==}
+ engines: {node: '>=20.0.0'}
+
+ '@manypkg/get-packages@3.1.0':
+ resolution: {integrity: sha512-0TbBVyvPrP7xGYBI/cP8UP+yl/z+HtbTttAD7FMAJgn/kXOTwh5/60TsqP9ZYY710forNfyV0N8P/IE/ujGZJg==}
+ engines: {node: '>=20.0.0'}
+
+ '@manypkg/tools@2.1.2':
+ resolution: {integrity: sha512-6QEf6yqFbETdwGITKq57aYoPfX/3K8XFNwsAlx0C1M7o8cb79sv1M3w+tWuWvIcSbNqrLF7OD7YpZMVVz335hQ==}
+ engines: {node: '>=20.0.0'}
+
+ '@module-federation/bridge-react-webpack-plugin@2.9.2':
+ resolution: {integrity: sha512-6ikuvP1639g8jzSxveDLz/BOk0VTIkO7aSuvrZgq0waB0h553zFtkTJAXQETezzO+s1taHGhEvFoCtl6DJWu6A==}
+
+ '@module-federation/cli@2.9.2':
+ resolution: {integrity: sha512-1+rNHFGC07lQq7CtgcF9ibtgMcAau4TzdOcLfCv13+o5XWWdM8X1yhPbqQWvj3MO/C/Js7Xwon1sTKjF69Do9g==}
+ engines: {node: '>=16.0.0'}
+ hasBin: true
+
+ '@module-federation/dts-plugin@2.9.2':
+ resolution: {integrity: sha512-J84cRrewtUFnFdMeD/91mHtW+Toh3mAWvGnhsFAc9oEbGwqfzJEfgPJri65xdtzWcNhs1d6FImPMTvnjzOnYvA==}
+ peerDependencies:
+ typescript: ^4.9.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ vue-tsc: '>=1.0.24'
+ peerDependenciesMeta:
+ vue-tsc:
+ optional: true
+
+ '@module-federation/enhanced@2.9.2':
+ resolution: {integrity: sha512-m1/kzb97Eu1v7FUenvwMpJiF6Vc8RNDjFxHS+YNgxy3WjI8s/mQrLJBrGK66qpK3wuP9kx0qB65kRiurB9IjUA==}
+ hasBin: true
+ peerDependencies:
+ typescript: ^4.9.0 || ^5.0.0 || ^6.0.0 || ^7.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@2.9.2':
+ resolution: {integrity: sha512-MTpKubqsJSBgnuw+2Pli1kHL4INeHD5cGnHL84oRANwQAWK7b6lN3ZZTmL3FL6lYn65ImineqZNqGWBv5GQVLQ==}
+
+ '@module-federation/inject-external-runtime-core-plugin@2.9.2':
+ resolution: {integrity: sha512-e8F/+fNwVgwhJVhLURAa7orYe1WFojamf4myf/G4jszGZ6Yx5DoIUjFBMrkLQgY2nuM/cw2/itIY4ZMGL1CJbA==}
+ peerDependencies:
+ '@module-federation/runtime-tools': 2.9.2
+
+ '@module-federation/managers@2.9.2':
+ resolution: {integrity: sha512-VtSKLkT2EA1wqCMFXNiklC+XF+5bZPYY3sUQ9LCFHqKS7v7NOJDrwMV6Qtw3fxH4Y6Pe6P28MiU8D9dlzknCKQ==}
+
+ '@module-federation/manifest@2.9.2':
+ resolution: {integrity: sha512-l9X1g2nHqjdumz9U9jawKo8rKoWXVbSlzLOqs+GYiHfzqSB2/ZQ+4AX0CaJ7orLz2varpGK4qdnQ0saptGuEVw==}
+
+ '@module-federation/node@2.7.52':
+ resolution: {integrity: sha512-K6R3+UoLK7SCxL0bxRs3J17AZeOEOY8ytyqxP3Y1jtO/drVqu1GaB0t+N1hvmle2zfAe9AmSG49cUiO03T5aEQ==}
+ peerDependencies:
+ webpack: ^5.40.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+
+ '@module-federation/rsbuild-plugin@2.9.2':
+ resolution: {integrity: sha512-E6VekVYmFdKWhL/ip75ukhAm/9gbK7f/cRmzS1BxTmw+8EFrrnvScU7qoj1MTSnMvViTtmXS42D49JWZ3SFw3g==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ '@rsbuild/core': ^1.3.21 || ^2.0.0-0
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+
+ '@module-federation/rspack@2.9.2':
+ resolution: {integrity: sha512-RobMJ/msRzJ94L9k1CAsPuhed2N2rvHBRBJhtk7t3pK/UoQM95Ks6KAcmVKBrxTVHWMhsKTCatxC7u7X19LYdA==}
+ peerDependencies:
+ '@rspack/core': ^0.7.0 || ^1.0.0 || ^2.0.0-0
+ typescript: ^4.9.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ vue-tsc: '>=1.0.24'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ vue-tsc:
+ optional: true
+
+ '@module-federation/runtime-core@2.9.2':
+ resolution: {integrity: sha512-S9roTDqLtAWaaDBuug69ZnXXGEx0pUq/yG06J759bjRgfAg2P9+dWEv1q7rB2eMIp7HH4L6s3ColDRYdL6tJ9w==}
+
+ '@module-federation/runtime-tools@2.9.2':
+ resolution: {integrity: sha512-rhOvimSLLnnocfOVUfAzH2xDq1pHMw4f/nSC+JQhSztEgP/1UslPPvcBcenx3B8/6CoYmBbGa2OIBTJ225ZHAg==}
+
+ '@module-federation/runtime@2.9.2':
+ resolution: {integrity: sha512-1lPZVy7TkMTTBMkkjgQt7jA+9FAx226yQqEz+X0lFAIbpxIWfpzNQLD+7IydEe83ZhDJpK3cv/9bn3jjQBZeqQ==}
+
+ '@module-federation/sdk@2.9.2':
+ resolution: {integrity: sha512-ILtBFPuYpVcRA/Qay1lJ2hMtZI8fDE/v1n7xiN17e5qx5rSBR3FaamTsmRpN1hIt+gVnoa76CzOP/Y73d8hHNg==}
+
+ '@module-federation/third-party-dts-extractor@2.9.2':
+ resolution: {integrity: sha512-FKJVGx+/jIe16RfmwoyIDVMPAttIFJv6AJCLkKf05IRNvI3RJFqQ1tLP1YjcfGuumCbYuWGa4QKnMla7YjVpqg==}
+
+ '@module-federation/vite@1.23.3':
+ resolution: {integrity: sha512-XYW7ePFmrSIIvQR4PBHBrujRlFI7TBP+g0QZkw9AsqW/A/x/tT97ypWe+osX4YCkCy57/48AQ0B/3bkl/wZXXQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ '@module-federation/webpack-bundler-runtime@2.9.2':
+ resolution: {integrity: sha512-dDtWiYcCWWgm/mCS7L4KfDHsyr7HwDRnHHS2bgl1H7RQfH4WAi706gT2hhzmV272PI33V7qJHN7Go1d/BamN0Q==}
+
+ '@napi-rs/wasm-runtime@1.1.6':
+ resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==}
+ peerDependencies:
+ '@emnapi/core': ^1.7.1
+ '@emnapi/runtime': ^1.7.1
+
+ '@oozcitak/dom@2.0.2':
+ resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==}
+ engines: {node: '>=20.0'}
+
+ '@oozcitak/infra@2.0.2':
+ resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==}
+ engines: {node: '>=20.0'}
+
+ '@oozcitak/url@3.0.0':
+ resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==}
+ engines: {node: '>=20.0'}
+
+ '@oozcitak/util@10.0.0':
+ resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==}
+ engines: {node: '>=20.0'}
+
+ '@oxc-project/types@0.152.0':
+ resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==}
+
+ '@pnpm/deps.graph-sequencer@1100.0.1':
+ resolution: {integrity: sha512-pOr5+q1fLYKwFN3LAJuGZEnfXDcQ73zqgDHMtGy+K+uIoUqyY+6MeDCWFwfu+4EFuq76I5EPFofoNAI+Bmmq4A==}
+ engines: {node: '>=22.13'}
+
+ '@rolldown/binding-android-arm-eabi@1.2.12':
+ resolution: {integrity: sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@rolldown/binding-android-arm64@1.2.12':
+ resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.2.12':
+ resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.2.12':
+ resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.2.12':
+ resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.2.12':
+ resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.2.12':
+ resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-arm64-musl@1.2.12':
+ resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-linux-ppc64-gnu@1.2.12':
+ resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-s390x-gnu@1.2.12':
+ resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-gnu@1.2.12':
+ resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-musl@1.2.12':
+ resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-openharmony-arm64@1.2.12':
+ resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-win32-arm64-msvc@1.2.12':
+ resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.2.12':
+ resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.1':
+ resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
+
+ '@rsbuild/core@2.2.11':
+ resolution: {integrity: sha512-avPW0j6RaEbtV2mfl0AzTAJEimPX4Xj0pCcZyxNCrE9vkS91HmweM5V7XQj3kI5iTYfHRp9Y6To8RRHYLEvG7A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ core-js: '>= 3.0.0'
+ peerDependenciesMeta:
+ core-js:
+ optional: true
+
+ '@rsbuild/plugin-react@2.1.1':
+ resolution: {integrity: sha512-tLtUedsRtTLS6M4VtwzI6aakFLOFdgl9Sh1ZNBWvxb0Te3EnHrppaE7UiYEmDUXQDJ50gfr6yyirtxY5N6moyg==}
+ peerDependencies:
+ '@rsbuild/core': ^2.0.0
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+
+ '@rslib/core@1.0.3':
+ resolution: {integrity: sha512-a5IZiyf9sNeeE9jcTsTmz16vxcThpbOSJg0BZXzJAxrUFOZX5xG25PJua9hr0LDWGryBX2UQTruVsLQ8BCpqng==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@microsoft/api-extractor': ^7
+ typescript: ^5 || ^6 || ^7
+ peerDependenciesMeta:
+ '@microsoft/api-extractor':
+ optional: true
+ typescript:
+ optional: true
+
+ '@rspack/binding-darwin-arm64@2.2.8':
+ resolution: {integrity: sha512-d6GuY/k7kJk7SOXmruIz0m+2fIXaLv2SnBHEYsbvBzE7ZO6QXq7fSABWFWNnSnNu+brYHA5Dr/skV81bXgTTCw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rspack/binding-darwin-x64@2.2.8':
+ resolution: {integrity: sha512-xCVou/jJASjEAjwy1T3hPJcJqA5QZASJfUwHqEk+nA0v44MagwH8tM8lsOvRfhzR7N2+YFac1rfZOUT8uM3awg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rspack/binding-linux-arm64-gnu@2.2.8':
+ resolution: {integrity: sha512-Zy/ss6YAQTjOWKDkcWrbKtu+pySltqT22wn68nlrWKygPWLNmMdU5anlsnwRTIuQ3MF0YJRS42ARauVtlqvRQw==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rspack/binding-linux-arm64-musl@2.2.8':
+ resolution: {integrity: sha512-lxgp5O8PhL3St9p82llHoNoeWzp9jltW5S9F00p00XPJZHUIuxbwfLSzn/6Wg86USEmafLoBkyD9CM8rBd3SNQ==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rspack/binding-linux-ppc64-gnu@2.2.8':
+ resolution: {integrity: sha512-MY+YqpT02tcDCMgHy+IewQsaz7ql4mbJaAqqMlTIqvQwAUl9dXEP7BL352OgCxm9VRebTldE5lK99A3wVd3zqA==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rspack/binding-linux-riscv64-gnu@2.2.8':
+ resolution: {integrity: sha512-wmN9OigSGNGCKY+AOYaWI8LJcIi8qvs5KjueBueCKOnTV6MPIEujA75QZH1pehTTYKvdGv7r2EtUXUmWpn7/SQ==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rspack/binding-linux-riscv64-musl@2.2.8':
+ resolution: {integrity: sha512-ZcQMYR10hLh581zs9MFnFFn0F7wyt5fkDffyukeMHJEoPJrbkfl6cQtsUdpQnZ+mYGYS5KydD1DT9/eMH65jjw==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@rspack/binding-linux-s390x-gnu@2.2.8':
+ resolution: {integrity: sha512-ahBiE+Ir1FMYvStYicihhSJlS2YRagxtry0jWH8zW287o7C0eiHJ+pteJHHC15T5RJqm0j6w5TuwYe+F9AYxxg==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rspack/binding-linux-x64-gnu@2.2.8':
+ resolution: {integrity: sha512-dncEI515NoPXh3zzWk06Rb3mhSV76myiFKqXiJ8K4fVAe5x/RlweMhvPhHhm7RnIMeBld7BeStzOqj38XFsWGA==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rspack/binding-linux-x64-musl@2.2.8':
+ resolution: {integrity: sha512-pfFyU03PjD0GaQG8zOQOHwq51rrJZetXjTGpMmz7iA1hq/f9lChJsDWrC8/7VXeQLwBofLZlOODqe8OM8OBzgA==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rspack/binding-wasm32-wasi@2.2.8':
+ resolution: {integrity: sha512-3mOJuZTrF56jOh/GD9chLMJKbzPZ6Ty2OIML7+lLz0Yk2XS/xWRfLn85Dmnkb/O6UF65x7+p8VPAIZlBtLTclw==}
+ cpu: [wasm32]
+
+ '@rspack/binding-win32-arm64-msvc@2.2.8':
+ resolution: {integrity: sha512-Cu/RMZT/16s+67xhl6X1pswetL3GLSQl+LnugKRh08Ul21A/tR7vxC4g4aih4u9k5SXCAngxFUt8zAjKnHIBqA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rspack/binding-win32-ia32-msvc@2.2.8':
+ resolution: {integrity: sha512-H/erd6di8OapZhhM0raA/7XduPn9jusfLMeO1XF+AmF9WF3HzHgMjha1j+KwtPgQnaH69w6AhY+G2472VIwQmw==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rspack/binding-win32-x64-msvc@2.2.8':
+ resolution: {integrity: sha512-BziHSUlIQM0MliCqdcHuBXSkQGtPoHQTXJce7fsgnTAzQFgPeog92qTNezYI4IrQ7pQouyiVJ2HPieUbVPRKQQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rspack/binding@2.2.8':
+ resolution: {integrity: sha512-c9flkSua3khHnOKBCRk8BkHGOwU9YB7niv+5JfQXiLZIvJmgKsZ7PD8QrFklMhsJT3oVAc6c9GN7/wy1YkACjA==}
+
+ '@rspack/core@2.2.8':
+ resolution: {integrity: sha512-JugsVrnbMGNYzMH++7gR9enygpP/lAo9PbVRq3XmJg0ryIvCpST0XJjBcccaSjYaaPamsjrddihmgVLMFp+yXw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0
+ '@swc/helpers': ^0.5.23
+ peerDependenciesMeta:
+ '@module-federation/runtime-tools':
+ optional: true
+ '@swc/helpers':
+ optional: true
+
+ '@rspack/plugin-react-refresh@2.0.2':
+ resolution: {integrity: sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==}
+ peerDependencies:
+ '@rspack/core': ^2.0.0
+ react-refresh: '>=0.10.0 <1.0.0'
+ peerDependenciesMeta:
+ '@rspack/core':
+ optional: true
+
+ '@swc/helpers@0.5.23':
+ resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==}
+
+ '@tanstack/history@1.162.4':
+ resolution: {integrity: sha512-utTS5L2OkeYUzXGohL1Z8sefu1GLNOJcxe8Hd6iIdc/Xo1K1nDB2JEp4iSFhvYh33xKC9V91TxrS8qfrpoKobQ==}
+ engines: {node: '>=20.19'}
+
+ '@tanstack/react-router@1.170.41':
+ resolution: {integrity: sha512-Mpvw8Wm5MGDbTqI8Yc9flLKxbOHwoWocv0H2aGKcgw2a017oK5nZWqa954P+DrUx/8fI98YNywnHP5XcD3tQ9w==}
+ engines: {node: '>=20.19'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
+ '@tanstack/react-start-client@1.168.39':
+ resolution: {integrity: sha512-Uby0uo37JlQgUKHU0snDwH9nYiEeAjm9+7pUOFgycU/UszEILC2SO2DSCoNnCMuHKj9z+4URKzBYIP2exT9+wg==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
+ '@tanstack/react-start-rsc@0.1.59':
+ resolution: {integrity: sha512-M2Lqxkk5C1zQncQs5paqX+/OLdOht51pg6D84YfLMrNsjhU/nzb6wd92MIja0mi5i23+L+fxLLjQYR2DObjBlw==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ '@rspack/core': '>=2.0.0-0'
+ '@vitejs/plugin-rsc': '>=0.5.30'
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+ react-server-dom-rspack: '>=0.0.2'
+ peerDependenciesMeta:
+ '@rspack/core':
+ optional: true
+ '@vitejs/plugin-rsc':
+ optional: true
+ react-server-dom-rspack:
+ optional: true
+
+ '@tanstack/react-start-server@1.167.46':
+ resolution: {integrity: sha512-K7z8xBOEdp8u5CZCxWrbS0tFtk5XZGMdhssLeZlRZKlLDbX7BKLdMtJ7th5sR6QVt9MTUAg3LcoqvJMPSFF+lg==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+
+ '@tanstack/react-start@1.168.60':
+ resolution: {integrity: sha512-WMOM0Xlh2lPbVlbjYM6uOxOpiaWRPvODm/dwkLsGKq5tjyHOHZmKckJgwlrZl7OQUqFlOZHYj8bKUTgoeg8cUQ==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ '@rsbuild/core': ^2.0.0
+ '@vitejs/plugin-rsc': '*'
+ react: '>=18.0.0 || >=19.0.0'
+ react-dom: '>=18.0.0 || >=19.0.0'
+ vite: '>=7.0.0'
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+ '@vitejs/plugin-rsc':
+ optional: true
+ vite:
+ optional: true
+
+ '@tanstack/react-store@0.11.2':
+ resolution: {integrity: sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ '@tanstack/router-core@1.171.34':
+ resolution: {integrity: sha512-X+19pGuuLVPvvAvPYw9v/+ktRk5cCll8AtfpBpOhDRmVgUMrfqze0467xtq8YRVVs/mmo5rVtWn/7Tp32RDBKw==}
+ engines: {node: '>=20.19'}
+
+ '@tanstack/router-generator@1.167.40':
+ resolution: {integrity: sha512-WkEueqEvsBBudzO0fx1nWfOmRNW8OAvBoVABTGls9bAWzjdC+KDGHvjCNrvn88ofs1F6gqL8aWnzKCbxW3dCyQ==}
+ engines: {node: '>=20.19'}
+
+ '@tanstack/router-plugin@1.168.42':
+ resolution: {integrity: sha512-vAR5WXJh/ErseEWQftDhsJcr2c++ucRQ6FbqN3ygMO44+ZxxRfW3sIpZmddHROVSmBk8jc6MrwjTPNjVhd62Vw==}
+ engines: {node: '>=20.19'}
+ peerDependencies:
+ '@rsbuild/core': '>=1.0.2 || ^2.0.0'
+ '@tanstack/react-router': ^1.170.41
+ vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0'
+ vite-plugin-solid: ^2.11.10 || ^3.0.0-0
+ webpack: '>=5.92.0'
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+ '@tanstack/react-router':
+ optional: true
+ vite:
+ optional: true
+ vite-plugin-solid:
+ optional: true
+ webpack:
+ optional: true
+
+ '@tanstack/router-utils@1.162.3':
+ resolution: {integrity: sha512-Icb0xGuG1+54IV0WMLRcc3ErTx2HeJWyPG661FkQ8UT6guoBq1FJjFRqlG/JS0xi4mFFkBhvwO7tbLa32f3yxA==}
+ engines: {node: '>=20.19'}
+
+ '@tanstack/start-client-core@1.170.34':
+ resolution: {integrity: sha512-LfwZSbau2MLLZ/uPAoO+NC9fK3J66c0wLhnNQqIa+Goqw7bXPjkHwlsjY7evlUz1AnyhhQ1Qab95v+VmP0TZ9A==}
+ engines: {node: '>=22.12.0'}
+
+ '@tanstack/start-fn-stubs@1.162.0':
+ resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==}
+ engines: {node: '>=22.12.0'}
+
+ '@tanstack/start-plugin-core@1.171.49':
+ resolution: {integrity: sha512-HPOb7LnMc71k38cd5uvMybPPUU/Q/56KvSqQzSWz7cps1ZDFXaxUM6EFaFHLCdgTWqGexNGDdRE+sUVPVBM4Xg==}
+ engines: {node: '>=22.12.0'}
+ peerDependencies:
+ '@rsbuild/core': ^2.0.0
+ vite: '>=7.0.0'
+ peerDependenciesMeta:
+ '@rsbuild/core':
+ optional: true
+ vite:
+ optional: true
+
+ '@tanstack/start-server-core@1.169.39':
+ resolution: {integrity: sha512-pqqkxhXY46nuFSYt6TsMGyABiplUzHFHndKAlRRGC0fWDrJCH1koWxVMoxySa51ZETV79f/z73b5UZ1jfIkXwQ==}
+ engines: {node: '>=22.12.0'}
+
+ '@tanstack/start-storage-context@1.167.36':
+ resolution: {integrity: sha512-x+xCXK2GtFzY6NbXqAg8YpU6cwAjDfMeYSNzxfGzntpjbwBRHHrXeC/kYUnBBQCV7wK4kJ8vBBQGP0OyYTasUg==}
+ engines: {node: '>=22.12.0'}
+
+ '@tanstack/store@0.11.2':
+ resolution: {integrity: sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==}
+
+ '@tanstack/virtual-file-routes@1.162.0':
+ resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==}
+ engines: {node: '>=20.19'}
+
+ '@turbo/darwin-64@2.11.7':
+ resolution: {integrity: sha512-Z2LFOxwbiJueD1miByXJS/BrW21vv6YaQXZustty5jEX4vQYw6zyh101Sz1QO7WG0mqBzKagZ/DoAeeujI0/Sw==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@turbo/darwin-arm64@2.11.7':
+ resolution: {integrity: sha512-Vhv8ybgIflosNDSSRD9fNXHlCFA60dsGyTqQmc7l28SEX5jOaweCCD4BBYNd8/p0WGkw3e7tZbfA9w6FsujGvw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@turbo/linux-64@2.11.7':
+ resolution: {integrity: sha512-rAqRp3blQKk1+ylMGlZHAW0eJjVNuuGUm4ZrC6RU1Im8tLryvaO4a2zLQ/FQi1TRlmKqKV9YXBki2YeytlLbXA==}
+ cpu: [x64]
+ os: [android, linux]
+
+ '@turbo/linux-arm64@2.11.7':
+ resolution: {integrity: sha512-thVYGov7S+llXAxrl3kBb/efalav0xhrjl5NHCR6AfKx14JkbqaetvbVwyss4FvZ9rt+Pv3xsTb+8SIYix8DTg==}
+ cpu: [arm64]
+ os: [android, linux]
+
+ '@turbo/windows-64@2.11.7':
+ resolution: {integrity: sha512-ZIoKT7J7KutgYl4bGxmmgeUQjG+7E0nY8BF9dxUOiMH2vdTsM4JQ2uSwTYFkTR2Llbg6ghGjSmuZ8LQtkLEYjg==}
+ cpu: [x64]
+ os: [win32]
+
+ '@turbo/windows-arm64@2.11.7':
+ resolution: {integrity: sha512-88Xv2f7SLGVJ68lRRx8o375dKmnZYNdDtvlKcPA0kZpcF93eAQd8l96BKQ0/AMHG0bMJA0Z5QqoqtetxzNsC+g==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tybys/wasm-util@0.10.4':
+ resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/node@26.6.4':
+ resolution: {integrity: sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==}
+
+ '@types/react-dom@19.3.0':
+ resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==}
+ peerDependencies:
+ '@types/react': ^19.3.0
+
+ '@types/react@19.3.0':
+ resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==}
+
+ '@typescript/typescript-aix-ppc64@7.0.2':
+ resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@typescript/typescript-darwin-arm64@7.0.2':
+ resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@typescript/typescript-darwin-x64@7.0.2':
+ resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@typescript/typescript-freebsd-arm64@7.0.2':
+ resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@typescript/typescript-freebsd-x64@7.0.2':
+ resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@typescript/typescript-linux-arm64@7.0.2':
+ resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@typescript/typescript-linux-arm@7.0.2':
+ resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@typescript/typescript-linux-loong64@7.0.2':
+ resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@typescript/typescript-linux-mips64el@7.0.2':
+ resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@typescript/typescript-linux-ppc64@7.0.2':
+ resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@typescript/typescript-linux-riscv64@7.0.2':
+ resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@typescript/typescript-linux-s390x@7.0.2':
+ resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==}
+ engines: {node: '>=16.20.0'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@typescript/typescript-linux-x64@7.0.2':
+ resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@typescript/typescript-netbsd-arm64@7.0.2':
+ resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@typescript/typescript-netbsd-x64@7.0.2':
+ resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@typescript/typescript-openbsd-arm64@7.0.2':
+ resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@typescript/typescript-openbsd-x64@7.0.2':
+ resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@typescript/typescript-sunos-x64@7.0.2':
+ resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@typescript/typescript-win32-arm64@7.0.2':
+ resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==}
+ engines: {node: '>=16.20.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@typescript/typescript-win32-x64@7.0.2':
+ resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==}
+ engines: {node: '>=16.20.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@vitejs/plugin-react@6.1.2':
+ resolution: {integrity: sha512-fhJNGUdscQa4HkI0xFxwonWyhnVReCPDbXI7FH7jmzpnVCrFQI7PRrhWecO263610vOrs9tr2Y4xcf8uAdFxbw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
+ babel-plugin-react-compiler: ^1.0.0
+ oxc-transform-react: ^0.152.0
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@rolldown/plugin-babel':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+ oxc-transform-react:
+ optional: true
+
+ adm-zip@0.6.1:
+ resolution: {integrity: sha512-Xwrja8nx9e5o2N1my4DsKCeKpdrnACyr1wtbPxBDgGzKzKyE9kRtBFA8mWldI+RVlD7CBZNWY/wQ2+ydwOR6kQ==}
+ engines: {node: '>=14.0'}
+
+ ajv-formats@2.1.1:
+ resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
+
+ ajv-keywords@5.1.0:
+ resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==}
+ peerDependencies:
+ ajv: ^8.8.2
+
+ ajv@8.20.0:
+ resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
+
+ ansis@4.4.0:
+ resolution: {integrity: sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==}
+ engines: {node: '>=14'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ babel-dead-code-elimination@1.0.12:
+ resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
+
+ baseline-browser-mapping@2.11.27:
+ resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ browserslist@4.29.3:
+ resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ cac@7.0.0:
+ resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==}
+ engines: {node: '>=20.19.0'}
+
+ caniuse-lite@1.0.30001814:
+ resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==}
+
+ chokidar@5.0.0:
+ resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
+ engines: {node: '>= 20.19.0'}
+
+ commander@11.1.0:
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
+ engines: {node: '>=16'}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cookie-es@3.1.1:
+ resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==}
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ diff@8.0.4:
+ resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
+ engines: {node: '>=0.3.1'}
+
+ electron-to-chromium@1.5.444:
+ resolution: {integrity: sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==}
+
+ encoding@0.1.13:
+ resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ exsolve@1.1.3:
+ resolution: {integrity: sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-string-truncated-width@3.0.3:
+ resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==}
+
+ fast-string-width@3.0.2:
+ resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==}
+
+ fast-uri@3.1.8:
+ resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==}
+
+ fast-wrap-ansi@0.2.2:
+ resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fetchdts@0.1.7:
+ resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ h3@2.0.1-rc.20:
+ resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==}
+ engines: {node: '>=20.11.1'}
+ hasBin: true
+ peerDependencies:
+ crossws: ^0.4.1
+ peerDependenciesMeta:
+ crossws:
+ optional: true
+
+ human-id@4.2.2:
+ resolution: {integrity: sha512-Z+8unD6em/MJwyrkWQ2M3wygRGI1+MztbutiNwk1DCuEPXOZRWGjtcMPZYP1exY9iNZMhd7ZOSMQSo9WYtiQRw==}
+ hasBin: true
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ import-meta-resolve@4.2.0:
+ resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
+
+ isbot@5.2.2:
+ resolution: {integrity: sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==}
+ engines: {node: '>=18'}
+
+ isomorphic-ws@5.0.0:
+ resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
+ peerDependencies:
+ ws: '*'
+
+ jiti@2.4.2:
+ resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
+ hasBin: true
+
+ jiti@2.7.0:
+ resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
+ hasBin: true
+
+ jju@1.4.0:
+ resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.3.2:
+ resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==}
+ hasBin: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-schema-traverse@1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ jsonc-parser@3.3.1:
+ resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
+
+ launch-editor@2.14.1:
+ resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==}
+
+ lightningcss-android-arm64@1.33.0:
+ resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.33.0:
+ resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.33.0:
+ resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.33.0:
+ resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.33.0:
+ resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.33.0:
+ resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-arm64-musl@1.33.0:
+ resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-linux-x64-gnu@1.33.0:
+ resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-x64-musl@1.33.0:
+ resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-win32-arm64-msvc@1.33.0:
+ resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.33.0:
+ resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.33.0:
+ resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
+ engines: {node: '>= 12.0.0'}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.20:
+ resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+
+ node-releases@2.0.57:
+ resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==}
+ engines: {node: '>=18'}
+
+ package-manager-detector@1.9.0:
+ resolution: {integrity: sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==}
+
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.7:
+ resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==}
+ engines: {node: '>=12'}
+
+ playwright-core@1.63.0:
+ resolution: {integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==}
+ engines: {node: '>=20'}
+ hasBin: true
+
+ playwright@1.63.0:
+ resolution: {integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==}
+ engines: {node: '>=20'}
+ hasBin: true
+
+ postcss@8.5.29:
+ resolution: {integrity: sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prettier@3.9.9:
+ resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==}
+ engines: {node: '>=14'}
+ hasBin: true
+
+ react-dom@19.3.0:
+ resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==}
+ peerDependencies:
+ react: ^19.3.0
+
+ react-refresh@0.19.0:
+ resolution: {integrity: sha512-5HdstYgoJBbBofjapO5qCPcovECJCBfvjLb+iTcsmqDFVMRdqy0qs7iiInBJTUXmIFc2bjoc5b2HVLp2zRtYhQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@19.3.0:
+ resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==}
+ engines: {node: '>=0.10.0'}
+
+ readdirp@5.1.1:
+ resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
+ engines: {node: '>= 20.19.0'}
+
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
+ rolldown@1.2.12:
+ resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
+ rou3@0.8.1:
+ resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==}
+
+ rsbuild-plugin-dts@1.0.3:
+ resolution: {integrity: sha512-wVxMYvWmVPam6SeZsz8OixHm+4JPfLJAAMTD0Q2te2SxksvjuHC3wuvU12teSmloQ3nFX1YC6guNzuYqDYw+vQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@microsoft/api-extractor': ^7
+ '@rsbuild/core': ^2.0.0
+ typescript: ^5 || ^6 || ^7
+ peerDependenciesMeta:
+ '@microsoft/api-extractor':
+ optional: true
+ typescript:
+ optional: true
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ scheduler@0.28.0:
+ resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
+
+ schema-utils@4.3.0:
+ resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==}
+ engines: {node: '>= 10.13.0'}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.8.5:
+ resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ seroval-plugins@1.6.8:
+ resolution: {integrity: sha512-N7mWAMydj89EnYTHtRpS3LBrAz3J9O6oVrqpuXuvlAHfAUG8WEKqtbAd7SBiJNY5NfCAFhSdyAh7wI4Shjqy4g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ seroval: ^1.0
+
+ seroval@1.6.8:
+ resolution: {integrity: sha512-HlSgSAkTk4EqHcje1ptJjfZi1YDv5KbhVJ/d3P7T/nAXua2VmDu+AKDX5VTdFfZf48nDkWB2TKYt0DrCSa+3wg==}
+ engines: {node: '>=10'}
+
+ shell-quote@1.12.0:
+ resolution: {integrity: sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==}
+ engines: {node: '>= 0.4'}
+
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+ source-map-js@1.2.2:
+ resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.7.6:
+ resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
+ engines: {node: '>= 12'}
+
+ srvx@0.11.22:
+ resolution: {integrity: sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==}
+ engines: {node: '>=20.16.0'}
+ hasBin: true
+
+ tapable@2.3.0:
+ resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
+ engines: {node: '>=6'}
+
+ tinyexec@1.3.1:
+ resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
+ tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ turbo@2.11.7:
+ resolution: {integrity: sha512-RhXHbqfvY6o3xt/zSHCwSNwLrZlXiqHzewi4eAj9PtZ1T1CqgMJ2yIDb7SKPTG9IikTm925mfzL6hldQVdyNWw==}
+ hasBin: true
+
+ typescript@7.0.2:
+ resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==}
+ engines: {node: '>=16.20.0'}
+ hasBin: true
+
+ ufo@1.6.4:
+ resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
+
+ undici-types@8.9.0:
+ resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==}
+
+ undici@7.29.1:
+ resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==}
+ engines: {node: '>=20.18.1'}
+
+ unplugin@3.4.0:
+ resolution: {integrity: sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@farmfe/core': '*'
+ '@rsbuild/core': '*'
+ '@rspack/core': '*'
+ bun-types-no-globals: '*'
+ esbuild: '*'
+ rolldown: '*'
+ rollup: '*'
+ unloader: '*'
+ vite: '*'
+ webpack: '*'
+ peerDependenciesMeta:
+ '@farmfe/core':
+ optional: true
+ '@rsbuild/core':
+ optional: true
+ '@rspack/core':
+ optional: true
+ bun-types-no-globals:
+ optional: true
+ esbuild:
+ optional: true
+ rolldown:
+ optional: true
+ rollup:
+ optional: true
+ unloader:
+ optional: true
+ vite:
+ optional: true
+ webpack:
+ optional: true
+
+ update-browserslist-db@1.3.3:
+ resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ use-sync-external-store@1.7.0:
+ resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ vite@8.3.2:
+ resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ '@vitejs/devtools': ^0.7.1
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitefu@1.1.3:
+ resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
+ webidl-conversions@3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
+ webpack-virtual-modules@0.6.2:
+ resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+
+ whatwg-url@5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+
+ ws@8.21.3:
+ resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ xmlbuilder2@4.0.3:
+ resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==}
+ engines: {node: '>=20.0'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yaml@2.9.1:
+ resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==}
+ engines: {node: '>= 14.6'}
+ hasBin: true
+
+ zod@4.6.5:
+ resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==}
+
+snapshots:
+
+ '@ast-grep/napi-darwin-arm64@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-darwin-x64@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-linux-arm64-gnu@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-linux-arm64-musl@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-linux-x64-gnu@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-linux-x64-musl@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-win32-arm64-msvc@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-win32-ia32-msvc@0.45.3':
+ optional: true
+
+ '@ast-grep/napi-win32-x64-msvc@0.45.3':
+ optional: true
+
+ '@ast-grep/napi@0.45.3':
+ optionalDependencies:
+ '@ast-grep/napi-darwin-arm64': 0.45.3
+ '@ast-grep/napi-darwin-x64': 0.45.3
+ '@ast-grep/napi-linux-arm64-gnu': 0.45.3
+ '@ast-grep/napi-linux-arm64-musl': 0.45.3
+ '@ast-grep/napi-linux-x64-gnu': 0.45.3
+ '@ast-grep/napi-linux-x64-musl': 0.45.3
+ '@ast-grep/napi-win32-arm64-msvc': 0.45.3
+ '@ast-grep/napi-win32-ia32-msvc': 0.45.3
+ '@ast-grep/napi-win32-x64-msvc': 0.45.3
+
+ '@babel/code-frame@7.29.7':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.29.7
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.7': {}
+
+ '@babel/core@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.8
+ '@babel/helper-compilation-targets': 7.29.7
+ '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
+ '@babel/helpers': 7.29.7
+ '@babel/parser': 7.29.9
+ '@babel/template': 7.29.7
+ '@babel/traverse': 7.29.8
+ '@babel/types': 7.29.8
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.8':
+ dependencies:
+ '@babel/parser': 7.29.9
+ '@babel/types': 7.29.8
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.29.7':
+ dependencies:
+ '@babel/compat-data': 7.29.7
+ '@babel/helper-validator-option': 7.29.7
+ browserslist: 4.29.3
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.29.7': {}
+
+ '@babel/helper-module-imports@7.29.7':
+ dependencies:
+ '@babel/traverse': 7.29.8
+ '@babel/types': 7.29.8
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-module-imports': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+ '@babel/traverse': 7.29.8
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-string-parser@7.29.7': {}
+
+ '@babel/helper-validator-identifier@7.29.7': {}
+
+ '@babel/helper-validator-option@7.29.7': {}
+
+ '@babel/helpers@7.29.7':
+ dependencies:
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.8
+
+ '@babel/parser@7.29.9':
+ dependencies:
+ '@babel/types': 7.29.8
+
+ '@babel/template@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/parser': 7.29.9
+ '@babel/types': 7.29.8
+
+ '@babel/traverse@7.29.8':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.8
+ '@babel/helper-globals': 7.29.7
+ '@babel/parser': 7.29.9
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.8
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.8':
+ dependencies:
+ '@babel/helper-string-parser': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+
+ '@changesets/apply-release-plan@8.1.1':
+ dependencies:
+ '@changesets/config': 4.0.1
+ '@changesets/format': 0.1.2
+ '@changesets/git': 4.0.1
+ '@changesets/should-skip-package': 1.0.0
+ '@changesets/types': 7.0.0
+ import-meta-resolve: 4.2.0
+ jsonc-parser: 3.3.1
+ semver: 7.8.5
+
+ '@changesets/assemble-release-plan@7.0.0':
+ dependencies:
+ '@changesets/errors': 1.0.0
+ '@changesets/get-dependents-graph': 3.0.0
+ '@changesets/should-skip-package': 1.0.0
+ '@changesets/types': 7.0.0
+ semver: 7.8.5
+
+ '@changesets/changelog-git@1.0.0':
+ dependencies:
+ '@changesets/types': 7.0.0
+
+ '@changesets/cli@3.0.3':
+ dependencies:
+ '@changesets/apply-release-plan': 8.1.1
+ '@changesets/assemble-release-plan': 7.0.0
+ '@changesets/changelog-git': 1.0.0
+ '@changesets/config': 4.0.1
+ '@changesets/errors': 1.0.0
+ '@changesets/get-dependents-graph': 3.0.0
+ '@changesets/git': 4.0.1
+ '@changesets/pre': 3.0.0
+ '@changesets/read': 1.0.1
+ '@changesets/should-skip-package': 1.0.0
+ '@changesets/types': 7.0.0
+ '@changesets/write': 1.0.1
+ '@clack/prompts': 1.8.1
+ '@manypkg/get-packages': 3.1.0
+ '@pnpm/deps.graph-sequencer': 1100.0.1
+ cac: 7.0.0
+ import-meta-resolve: 4.2.0
+ launch-editor: 2.14.1
+ package-manager-detector: 1.9.0
+ semver: 7.8.5
+ tinyexec: 1.3.1
+
+ '@changesets/config@4.0.1':
+ dependencies:
+ '@changesets/get-dependents-graph': 3.0.0
+ '@changesets/should-skip-package': 1.0.0
+ '@changesets/types': 7.0.0
+ '@manypkg/get-packages': 3.1.0
+ picomatch: 4.0.7
+
+ '@changesets/errors@1.0.0': {}
+
+ '@changesets/format@0.1.2':
+ dependencies:
+ package-manager-detector: 1.9.0
+ tinyexec: 1.3.1
+
+ '@changesets/get-dependents-graph@3.0.0':
+ dependencies:
+ '@changesets/types': 7.0.0
+ semver: 7.8.5
+
+ '@changesets/git@4.0.1':
+ dependencies:
+ '@changesets/errors': 1.0.0
+ '@changesets/types': 7.0.0
+ '@manypkg/get-packages': 3.1.0
+ picomatch: 4.0.7
+ tinyexec: 1.3.1
+
+ '@changesets/parse@1.0.0':
+ dependencies:
+ '@changesets/types': 7.0.0
+ yaml: 2.9.1
+
+ '@changesets/pre@3.0.0':
+ dependencies:
+ '@changesets/errors': 1.0.0
+ '@changesets/types': 7.0.0
+ '@manypkg/get-packages': 3.1.0
+
+ '@changesets/read@1.0.1':
+ dependencies:
+ '@changesets/git': 4.0.1
+ '@changesets/parse': 1.0.0
+ '@changesets/types': 7.0.0
+
+ '@changesets/should-skip-package@1.0.0':
+ dependencies:
+ '@changesets/types': 7.0.0
+
+ '@changesets/types@7.0.0': {}
+
+ '@changesets/write@1.0.1':
+ dependencies:
+ '@changesets/format': 0.1.2
+ '@changesets/types': 7.0.0
+ human-id: 4.2.2
+
+ '@clack/core@1.5.1':
+ dependencies:
+ fast-wrap-ansi: 0.2.2
+ sisteransi: 1.0.5
+
+ '@clack/prompts@1.8.1':
+ dependencies:
+ '@clack/core': 1.5.1
+ fast-string-width: 3.0.2
+ fast-wrap-ansi: 0.2.2
+ sisteransi: 1.0.5
+
+ '@emnapi/core@1.11.3':
+ dependencies:
+ '@emnapi/wasi-threads': 1.2.3
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.11.3':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.2.3':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.6.0
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.6.0': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.6.0
+
+ '@manypkg/find-root@3.1.0':
+ dependencies:
+ '@manypkg/tools': 2.1.2
+
+ '@manypkg/get-packages@3.1.0':
+ dependencies:
+ '@manypkg/find-root': 3.1.0
+ '@manypkg/tools': 2.1.2
+
+ '@manypkg/tools@2.1.2':
+ dependencies:
+ jju: 1.4.0
+ tinyglobby: 0.2.17
+ yaml: 2.9.1
+
+ '@module-federation/bridge-react-webpack-plugin@2.9.2':
+ dependencies:
+ '@module-federation/sdk': 2.9.2
+
+ '@module-federation/cli@2.9.2(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/dts-plugin': 2.9.2(typescript@7.0.2)
+ '@module-federation/sdk': 2.9.2
+ commander: 11.1.0
+ jiti: 2.4.2
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/dts-plugin@2.9.2(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/error-codes': 2.9.2
+ '@module-federation/managers': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ '@module-federation/third-party-dts-extractor': 2.9.2
+ adm-zip: 0.6.1
+ isomorphic-ws: 5.0.0(ws@8.21.3)
+ typescript: 7.0.2
+ undici: 7.29.1
+ ws: 8.21.3
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ '@module-federation/enhanced@2.9.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.9.2
+ '@module-federation/cli': 2.9.2(typescript@7.0.2)
+ '@module-federation/dts-plugin': 2.9.2(typescript@7.0.2)
+ '@module-federation/error-codes': 2.9.2
+ '@module-federation/inject-external-runtime-core-plugin': 2.9.2(@module-federation/runtime-tools@2.9.2)
+ '@module-federation/managers': 2.9.2
+ '@module-federation/manifest': 2.9.2(typescript@7.0.2)
+ '@module-federation/rspack': 2.9.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/runtime-tools': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ '@module-federation/webpack-bundler-runtime': 2.9.2
+ schema-utils: 4.3.0
+ tapable: 2.3.0
+ optionalDependencies:
+ typescript: 7.0.2
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - utf-8-validate
+
+ '@module-federation/error-codes@2.9.2': {}
+
+ '@module-federation/inject-external-runtime-core-plugin@2.9.2(@module-federation/runtime-tools@2.9.2)':
+ dependencies:
+ '@module-federation/runtime-tools': 2.9.2
+
+ '@module-federation/managers@2.9.2':
+ dependencies:
+ '@module-federation/sdk': 2.9.2
+
+ '@module-federation/manifest@2.9.2(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/dts-plugin': 2.9.2(typescript@7.0.2)
+ '@module-federation/managers': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/node@2.7.52(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/enhanced': 2.9.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/runtime': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ encoding: 0.1.13
+ node-fetch: 2.7.0(encoding@0.1.13)
+ tapable: 2.3.0
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/rsbuild-plugin@2.9.2(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/enhanced': 2.9.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/node': 2.7.52(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)
+ '@module-federation/sdk': 2.9.2
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+ - webpack
+
+ '@module-federation/rspack@2.9.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(typescript@7.0.2)':
+ dependencies:
+ '@module-federation/bridge-react-webpack-plugin': 2.9.2
+ '@module-federation/dts-plugin': 2.9.2(typescript@7.0.2)
+ '@module-federation/inject-external-runtime-core-plugin': 2.9.2(@module-federation/runtime-tools@2.9.2)
+ '@module-federation/managers': 2.9.2
+ '@module-federation/manifest': 2.9.2(typescript@7.0.2)
+ '@module-federation/runtime-tools': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ '@rspack/core': 2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)
+ optionalDependencies:
+ typescript: 7.0.2
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ '@module-federation/runtime-core@2.9.2':
+ dependencies:
+ '@module-federation/error-codes': 2.9.2
+ '@module-federation/sdk': 2.9.2
+
+ '@module-federation/runtime-tools@2.9.2':
+ dependencies:
+ '@module-federation/runtime': 2.9.2
+ '@module-federation/webpack-bundler-runtime': 2.9.2
+
+ '@module-federation/runtime@2.9.2':
+ dependencies:
+ '@module-federation/error-codes': 2.9.2
+ '@module-federation/runtime-core': 2.9.2
+ '@module-federation/sdk': 2.9.2
+
+ '@module-federation/sdk@2.9.2': {}
+
+ '@module-federation/third-party-dts-extractor@2.9.2': {}
+
+ '@module-federation/vite@1.23.3(typescript@7.0.2)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@module-federation/dts-plugin': 2.9.2(typescript@7.0.2)
+ '@module-federation/runtime': 2.9.2
+ '@module-federation/sdk': 2.9.2
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - vue-tsc
+
+ '@module-federation/webpack-bundler-runtime@2.9.2':
+ dependencies:
+ '@module-federation/error-codes': 2.9.2
+ '@module-federation/runtime': 2.9.2
+ '@module-federation/sdk': 2.9.2
+
+ '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)':
+ dependencies:
+ '@emnapi/core': 1.11.3
+ '@emnapi/runtime': 1.11.3
+ '@tybys/wasm-util': 0.10.4
+ optional: true
+
+ '@oozcitak/dom@2.0.2':
+ dependencies:
+ '@oozcitak/infra': 2.0.2
+ '@oozcitak/url': 3.0.0
+ '@oozcitak/util': 10.0.0
+
+ '@oozcitak/infra@2.0.2':
+ dependencies:
+ '@oozcitak/util': 10.0.0
+
+ '@oozcitak/url@3.0.0':
+ dependencies:
+ '@oozcitak/infra': 2.0.2
+ '@oozcitak/util': 10.0.0
+
+ '@oozcitak/util@10.0.0': {}
+
+ '@oxc-project/types@0.152.0': {}
+
+ '@pnpm/deps.graph-sequencer@1100.0.1': {}
+
+ '@rolldown/binding-android-arm-eabi@1.2.12':
+ optional: true
+
+ '@rolldown/binding-android-arm64@1.2.12':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.2.12':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.2.12':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-ppc64-gnu@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-s390x-gnu@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.2.12':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.2.12':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.2.12':
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.2.12':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.2.12':
+ optional: true
+
+ '@rolldown/pluginutils@1.0.1': {}
+
+ '@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2)':
+ dependencies:
+ '@rspack/core': 2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)
+ '@swc/helpers': 0.5.23
+ transitivePeerDependencies:
+ - '@module-federation/runtime-tools'
+
+ '@rsbuild/plugin-react@2.1.1(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))':
+ dependencies:
+ '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-refresh@0.19.0)
+ react-refresh: 0.19.0
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ transitivePeerDependencies:
+ - '@rspack/core'
+
+ '@rslib/core@1.0.3(@module-federation/runtime-tools@2.9.2)(typescript@7.0.2)':
+ dependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ rsbuild-plugin-dts: 1.0.3(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(typescript@7.0.2)
+ optionalDependencies:
+ typescript: 7.0.2
+ transitivePeerDependencies:
+ - '@module-federation/runtime-tools'
+ - core-js
+
+ '@rspack/binding-darwin-arm64@2.2.8':
+ optional: true
+
+ '@rspack/binding-darwin-x64@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-arm64-gnu@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-arm64-musl@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-ppc64-gnu@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-riscv64-gnu@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-riscv64-musl@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-s390x-gnu@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-x64-gnu@2.2.8':
+ optional: true
+
+ '@rspack/binding-linux-x64-musl@2.2.8':
+ optional: true
+
+ '@rspack/binding-wasm32-wasi@2.2.8':
+ dependencies:
+ '@emnapi/core': 1.11.3
+ '@emnapi/runtime': 1.11.3
+ '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)
+ optional: true
+
+ '@rspack/binding-win32-arm64-msvc@2.2.8':
+ optional: true
+
+ '@rspack/binding-win32-ia32-msvc@2.2.8':
+ optional: true
+
+ '@rspack/binding-win32-x64-msvc@2.2.8':
+ optional: true
+
+ '@rspack/binding@2.2.8':
+ optionalDependencies:
+ '@rspack/binding-darwin-arm64': 2.2.8
+ '@rspack/binding-darwin-x64': 2.2.8
+ '@rspack/binding-linux-arm64-gnu': 2.2.8
+ '@rspack/binding-linux-arm64-musl': 2.2.8
+ '@rspack/binding-linux-ppc64-gnu': 2.2.8
+ '@rspack/binding-linux-riscv64-gnu': 2.2.8
+ '@rspack/binding-linux-riscv64-musl': 2.2.8
+ '@rspack/binding-linux-s390x-gnu': 2.2.8
+ '@rspack/binding-linux-x64-gnu': 2.2.8
+ '@rspack/binding-linux-x64-musl': 2.2.8
+ '@rspack/binding-wasm32-wasi': 2.2.8
+ '@rspack/binding-win32-arm64-msvc': 2.2.8
+ '@rspack/binding-win32-ia32-msvc': 2.2.8
+ '@rspack/binding-win32-x64-msvc': 2.2.8
+
+ '@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)':
+ dependencies:
+ '@rspack/binding': 2.2.8
+ optionalDependencies:
+ '@module-federation/runtime-tools': 2.9.2
+ '@swc/helpers': 0.5.23
+
+ '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-refresh@0.19.0)':
+ dependencies:
+ react-refresh: 0.19.0
+ optionalDependencies:
+ '@rspack/core': 2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)
+
+ '@swc/helpers@0.5.23':
+ dependencies:
+ tslib: 2.8.1
+
+ '@tanstack/history@1.162.4': {}
+
+ '@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
+ dependencies:
+ '@tanstack/history': 1.162.4
+ '@tanstack/react-store': 0.11.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/router-core': 1.171.34
+ isbot: 5.2.2
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+
+ '@tanstack/react-start-client@1.168.39(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
+ dependencies:
+ '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/start-client-core': 1.170.34
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+
+ '@tanstack/react-start-rsc@0.1.59(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/router-utils': 1.162.3
+ '@tanstack/start-client-core': 1.170.34
+ '@tanstack/start-fn-stubs': 1.162.0
+ '@tanstack/start-plugin-core': 1.171.49(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@tanstack/start-storage-context': 1.167.36
+ pathe: 2.0.3
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+ optionalDependencies:
+ '@rspack/core': 2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)
+ transitivePeerDependencies:
+ - '@farmfe/core'
+ - '@rsbuild/core'
+ - bun-types-no-globals
+ - crossws
+ - esbuild
+ - rolldown
+ - rollup
+ - supports-color
+ - unloader
+ - vite
+ - vite-plugin-solid
+ - webpack
+
+ '@tanstack/react-start-server@1.167.46(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
+ dependencies:
+ '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/start-server-core': 1.169.39
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+ transitivePeerDependencies:
+ - crossws
+
+ '@tanstack/react-start@1.168.60(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start-client': 1.168.39(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/react-start-rsc': 0.1.59(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@tanstack/react-start-server': 1.167.46(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ '@tanstack/router-utils': 1.162.3
+ '@tanstack/start-client-core': 1.170.34
+ '@tanstack/start-plugin-core': 1.171.49(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@tanstack/start-server-core': 1.169.39
+ pathe: 2.0.3
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+ transitivePeerDependencies:
+ - '@farmfe/core'
+ - '@rspack/core'
+ - bun-types-no-globals
+ - crossws
+ - esbuild
+ - react-server-dom-rspack
+ - rolldown
+ - rollup
+ - supports-color
+ - unloader
+ - vite-plugin-solid
+ - webpack
+
+ '@tanstack/react-store@0.11.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
+ dependencies:
+ '@tanstack/store': 0.11.2
+ react: 19.3.0
+ react-dom: 19.3.0(react@19.3.0)
+ use-sync-external-store: 1.7.0(react@19.3.0)
+
+ '@tanstack/router-core@1.171.34':
+ dependencies:
+ '@tanstack/history': 1.162.4
+ cookie-es: 3.1.1
+ seroval: 1.6.8
+ seroval-plugins: 1.6.8(seroval@1.6.8)
+
+ '@tanstack/router-generator@1.167.40':
+ dependencies:
+ '@babel/types': 7.29.8
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/router-utils': 1.162.3
+ '@tanstack/virtual-file-routes': 1.162.0
+ jiti: 2.7.0
+ magic-string: 0.30.21
+ prettier: 3.9.9
+ zod: 4.6.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/router-plugin@1.168.42(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.8
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/router-generator': 1.167.40
+ '@tanstack/router-utils': 1.162.3
+ chokidar: 5.0.0
+ unplugin: 3.4.0(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ zod: 4.6.5
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+ transitivePeerDependencies:
+ - '@farmfe/core'
+ - '@rspack/core'
+ - bun-types-no-globals
+ - esbuild
+ - rolldown
+ - rollup
+ - supports-color
+ - unloader
+
+ '@tanstack/router-utils@1.162.3':
+ dependencies:
+ '@babel/generator': 7.29.8
+ '@babel/parser': 7.29.9
+ '@babel/types': 7.29.8
+ ansis: 4.4.0
+ babel-dead-code-elimination: 1.0.12
+ diff: 8.0.4
+ pathe: 2.0.3
+ tinyglobby: 0.2.17
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tanstack/start-client-core@1.170.34':
+ dependencies:
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/start-fn-stubs': 1.162.0
+ '@tanstack/start-storage-context': 1.167.36
+ seroval: 1.6.8
+
+ '@tanstack/start-fn-stubs@1.162.0': {}
+
+ '@tanstack/start-plugin-core@1.171.49(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/core': 7.29.7
+ '@babel/types': 7.29.8
+ '@jridgewell/remapping': 2.3.5
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/router-generator': 1.167.40
+ '@tanstack/router-plugin': 1.168.42(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ '@tanstack/router-utils': 1.162.3
+ '@tanstack/start-server-core': 1.169.39
+ exsolve: 1.1.3
+ lightningcss: 1.33.0
+ pathe: 2.0.3
+ picomatch: 4.0.7
+ seroval: 1.6.8
+ source-map: 0.7.6
+ srvx: 0.11.22
+ tinyglobby: 0.2.17
+ ufo: 1.6.4
+ vitefu: 1.1.3(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))
+ xmlbuilder2: 4.0.3
+ zod: 4.6.5
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+ transitivePeerDependencies:
+ - '@farmfe/core'
+ - '@rspack/core'
+ - '@tanstack/react-router'
+ - bun-types-no-globals
+ - crossws
+ - esbuild
+ - rolldown
+ - rollup
+ - supports-color
+ - unloader
+ - vite-plugin-solid
+ - webpack
+
+ '@tanstack/start-server-core@1.169.39':
+ dependencies:
+ '@tanstack/history': 1.162.4
+ '@tanstack/router-core': 1.171.34
+ '@tanstack/start-client-core': 1.170.34
+ '@tanstack/start-storage-context': 1.167.36
+ fetchdts: 0.1.7
+ h3-v2: h3@2.0.1-rc.20
+ seroval: 1.6.8
+ transitivePeerDependencies:
+ - crossws
+
+ '@tanstack/start-storage-context@1.167.36':
+ dependencies:
+ '@tanstack/router-core': 1.171.34
+
+ '@tanstack/store@0.11.2': {}
+
+ '@tanstack/virtual-file-routes@1.162.0': {}
+
+ '@turbo/darwin-64@2.11.7':
+ optional: true
+
+ '@turbo/darwin-arm64@2.11.7':
+ optional: true
+
+ '@turbo/linux-64@2.11.7':
+ optional: true
+
+ '@turbo/linux-arm64@2.11.7':
+ optional: true
+
+ '@turbo/windows-64@2.11.7':
+ optional: true
+
+ '@turbo/windows-arm64@2.11.7':
+ optional: true
+
+ '@tybys/wasm-util@0.10.4':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/node@26.6.4':
+ dependencies:
+ undici-types: 8.9.0
+
+ '@types/react-dom@19.3.0(@types/react@19.3.0)':
+ dependencies:
+ '@types/react': 19.3.0
+
+ '@types/react@19.3.0':
+ dependencies:
+ csstype: 3.2.3
+
+ '@typescript/typescript-aix-ppc64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-darwin-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-darwin-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-freebsd-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-freebsd-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-arm@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-loong64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-mips64el@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-ppc64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-riscv64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-s390x@7.0.2':
+ optional: true
+
+ '@typescript/typescript-linux-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-netbsd-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-netbsd-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-openbsd-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-openbsd-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-sunos-x64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-win32-arm64@7.0.2':
+ optional: true
+
+ '@typescript/typescript-win32-x64@7.0.2':
+ optional: true
+
+ '@vitejs/plugin-react@6.1.2(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1))':
+ dependencies:
+ '@rolldown/pluginutils': 1.0.1
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ adm-zip@0.6.1: {}
+
+ ajv-formats@2.1.1:
+ dependencies:
+ ajv: 8.20.0
+
+ ajv-keywords@5.1.0(ajv@8.20.0):
+ dependencies:
+ ajv: 8.20.0
+ fast-deep-equal: 3.1.3
+
+ ajv@8.20.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-uri: 3.1.8
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+
+ ansis@4.4.0: {}
+
+ argparse@2.0.1: {}
+
+ babel-dead-code-elimination@1.0.12:
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/parser': 7.29.9
+ '@babel/traverse': 7.29.8
+ '@babel/types': 7.29.8
+ transitivePeerDependencies:
+ - supports-color
+
+ baseline-browser-mapping@2.11.27: {}
+
+ browserslist@4.29.3:
+ dependencies:
+ baseline-browser-mapping: 2.11.27
+ caniuse-lite: 1.0.30001814
+ electron-to-chromium: 1.5.444
+ node-releases: 2.0.57
+ update-browserslist-db: 1.3.3(browserslist@4.29.3)
+
+ cac@7.0.0: {}
+
+ caniuse-lite@1.0.30001814: {}
+
+ chokidar@5.0.0:
+ dependencies:
+ readdirp: 5.1.1
+
+ commander@11.1.0: {}
+
+ convert-source-map@2.0.0: {}
+
+ cookie-es@3.1.1: {}
+
+ csstype@3.2.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ detect-libc@2.1.2: {}
+
+ diff@8.0.4: {}
+
+ electron-to-chromium@1.5.444: {}
+
+ encoding@0.1.13:
+ dependencies:
+ iconv-lite: 0.6.3
+
+ escalade@3.2.0: {}
+
+ exsolve@1.1.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-string-truncated-width@3.0.3: {}
+
+ fast-string-width@3.0.2:
+ dependencies:
+ fast-string-truncated-width: 3.0.3
+
+ fast-uri@3.1.8: {}
+
+ fast-wrap-ansi@0.2.2:
+ dependencies:
+ fast-string-width: 3.0.2
+
+ fdir@6.5.0(picomatch@4.0.7):
+ optionalDependencies:
+ picomatch: 4.0.7
+
+ fetchdts@0.1.7: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ h3@2.0.1-rc.20:
+ dependencies:
+ rou3: 0.8.1
+ srvx: 0.11.22
+
+ human-id@4.2.2: {}
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ import-meta-resolve@4.2.0: {}
+
+ isbot@5.2.2: {}
+
+ isomorphic-ws@5.0.0(ws@8.21.3):
+ dependencies:
+ ws: 8.21.3
+
+ jiti@2.4.2: {}
+
+ jiti@2.7.0: {}
+
+ jju@1.4.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.3.2:
+ dependencies:
+ argparse: 2.0.1
+
+ jsesc@3.1.0: {}
+
+ json-schema-traverse@1.0.0: {}
+
+ json5@2.2.3: {}
+
+ jsonc-parser@3.3.1: {}
+
+ launch-editor@2.14.1:
+ dependencies:
+ picocolors: 1.1.1
+ shell-quote: 1.12.0
+
+ lightningcss-android-arm64@1.33.0:
+ optional: true
+
+ lightningcss-darwin-arm64@1.33.0:
+ optional: true
+
+ lightningcss-darwin-x64@1.33.0:
+ optional: true
+
+ lightningcss-freebsd-x64@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.33.0:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.33.0:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.33.0:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.33.0:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.33.0:
+ optional: true
+
+ lightningcss@1.33.0:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.33.0
+ lightningcss-darwin-arm64: 1.33.0
+ lightningcss-darwin-x64: 1.33.0
+ lightningcss-freebsd-x64: 1.33.0
+ lightningcss-linux-arm-gnueabihf: 1.33.0
+ lightningcss-linux-arm64-gnu: 1.33.0
+ lightningcss-linux-arm64-musl: 1.33.0
+ lightningcss-linux-x64-gnu: 1.33.0
+ lightningcss-linux-x64-musl: 1.33.0
+ lightningcss-win32-arm64-msvc: 1.33.0
+ lightningcss-win32-x64-msvc: 1.33.0
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.6.0
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.20: {}
+
+ node-fetch@2.7.0(encoding@0.1.13):
+ dependencies:
+ whatwg-url: 5.0.0
+ optionalDependencies:
+ encoding: 0.1.13
+
+ node-releases@2.0.57: {}
+
+ package-manager-detector@1.9.0: {}
+
+ pathe@2.0.3: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.7: {}
+
+ playwright-core@1.63.0: {}
+
+ playwright@1.63.0:
+ dependencies:
+ playwright-core: 1.63.0
+
+ postcss@8.5.29:
+ dependencies:
+ nanoid: 3.3.20
+ picocolors: 1.1.1
+ source-map-js: 1.2.2
+
+ prettier@3.9.9: {}
+
+ react-dom@19.3.0(react@19.3.0):
+ dependencies:
+ react: 19.3.0
+ scheduler: 0.28.0
+
+ react-refresh@0.19.0: {}
+
+ react@19.3.0: {}
+
+ readdirp@5.1.1: {}
+
+ require-from-string@2.0.2: {}
+
+ rolldown@1.2.12:
+ dependencies:
+ '@oxc-project/types': 0.152.0
+ '@rolldown/pluginutils': 1.0.1
+ optionalDependencies:
+ '@rolldown/binding-android-arm-eabi': 1.2.12
+ '@rolldown/binding-android-arm64': 1.2.12
+ '@rolldown/binding-darwin-arm64': 1.2.12
+ '@rolldown/binding-darwin-x64': 1.2.12
+ '@rolldown/binding-freebsd-x64': 1.2.12
+ '@rolldown/binding-linux-arm-gnueabihf': 1.2.12
+ '@rolldown/binding-linux-arm64-gnu': 1.2.12
+ '@rolldown/binding-linux-arm64-musl': 1.2.12
+ '@rolldown/binding-linux-ppc64-gnu': 1.2.12
+ '@rolldown/binding-linux-s390x-gnu': 1.2.12
+ '@rolldown/binding-linux-x64-gnu': 1.2.12
+ '@rolldown/binding-linux-x64-musl': 1.2.12
+ '@rolldown/binding-openharmony-arm64': 1.2.12
+ '@rolldown/binding-win32-arm64-msvc': 1.2.12
+ '@rolldown/binding-win32-x64-msvc': 1.2.12
+
+ rou3@0.8.1: {}
+
+ rsbuild-plugin-dts@1.0.3(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(typescript@7.0.2):
+ dependencies:
+ '@ast-grep/napi': 0.45.3
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ optionalDependencies:
+ typescript: 7.0.2
+
+ safer-buffer@2.1.2: {}
+
+ scheduler@0.28.0: {}
+
+ schema-utils@4.3.0:
+ dependencies:
+ '@types/json-schema': 7.0.15
+ ajv: 8.20.0
+ ajv-formats: 2.1.1
+ ajv-keywords: 5.1.0(ajv@8.20.0)
+
+ semver@6.3.1: {}
+
+ semver@7.8.5: {}
+
+ seroval-plugins@1.6.8(seroval@1.6.8):
+ dependencies:
+ seroval: 1.6.8
+
+ seroval@1.6.8: {}
+
+ shell-quote@1.12.0: {}
+
+ sisteransi@1.0.5: {}
+
+ source-map-js@1.2.2: {}
+
+ source-map@0.7.6: {}
+
+ srvx@0.11.22: {}
+
+ tapable@2.3.0: {}
+
+ tinyexec@1.3.1: {}
+
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.7)
+ picomatch: 4.0.7
+
+ tr46@0.0.3: {}
+
+ tslib@2.8.1: {}
+
+ turbo@2.11.7:
+ optionalDependencies:
+ '@turbo/darwin-64': 2.11.7
+ '@turbo/darwin-arm64': 2.11.7
+ '@turbo/linux-64': 2.11.7
+ '@turbo/linux-arm64': 2.11.7
+ '@turbo/windows-64': 2.11.7
+ '@turbo/windows-arm64': 2.11.7
+
+ typescript@7.0.2:
+ optionalDependencies:
+ '@typescript/typescript-aix-ppc64': 7.0.2
+ '@typescript/typescript-darwin-arm64': 7.0.2
+ '@typescript/typescript-darwin-x64': 7.0.2
+ '@typescript/typescript-freebsd-arm64': 7.0.2
+ '@typescript/typescript-freebsd-x64': 7.0.2
+ '@typescript/typescript-linux-arm': 7.0.2
+ '@typescript/typescript-linux-arm64': 7.0.2
+ '@typescript/typescript-linux-loong64': 7.0.2
+ '@typescript/typescript-linux-mips64el': 7.0.2
+ '@typescript/typescript-linux-ppc64': 7.0.2
+ '@typescript/typescript-linux-riscv64': 7.0.2
+ '@typescript/typescript-linux-s390x': 7.0.2
+ '@typescript/typescript-linux-x64': 7.0.2
+ '@typescript/typescript-netbsd-arm64': 7.0.2
+ '@typescript/typescript-netbsd-x64': 7.0.2
+ '@typescript/typescript-openbsd-arm64': 7.0.2
+ '@typescript/typescript-openbsd-x64': 7.0.2
+ '@typescript/typescript-sunos-x64': 7.0.2
+ '@typescript/typescript-win32-arm64': 7.0.2
+ '@typescript/typescript-win32-x64': 7.0.2
+
+ ufo@1.6.4: {}
+
+ undici-types@8.9.0: {}
+
+ undici@7.29.1: {}
+
+ unplugin@3.4.0(@rsbuild/core@2.2.11(@module-federation/runtime-tools@2.9.2))(@rspack/core@2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23))(rolldown@1.2.12)(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)):
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ picomatch: 4.0.7
+ webpack-virtual-modules: 0.6.2
+ optionalDependencies:
+ '@rsbuild/core': 2.2.11(@module-federation/runtime-tools@2.9.2)
+ '@rspack/core': 2.2.8(@module-federation/runtime-tools@2.9.2)(@swc/helpers@0.5.23)
+ rolldown: 1.2.12
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ update-browserslist-db@1.3.3(browserslist@4.29.3):
+ dependencies:
+ browserslist: 4.29.3
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ use-sync-external-store@1.7.0(react@19.3.0):
+ dependencies:
+ react: 19.3.0
+
+ vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1):
+ dependencies:
+ lightningcss: 1.33.0
+ picomatch: 4.0.7
+ postcss: 8.5.29
+ rolldown: 1.2.12
+ tinyglobby: 0.2.17
+ optionalDependencies:
+ '@types/node': 26.6.4
+ fsevents: 2.3.3
+ jiti: 2.7.0
+ yaml: 2.9.1
+
+ vitefu@1.1.3(vite@8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)):
+ optionalDependencies:
+ vite: 8.3.2(@types/node@26.6.4)(jiti@2.7.0)(yaml@2.9.1)
+
+ webidl-conversions@3.0.1: {}
+
+ webpack-virtual-modules@0.6.2: {}
+
+ whatwg-url@5.0.0:
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+
+ ws@8.21.3: {}
+
+ xmlbuilder2@4.0.3:
+ dependencies:
+ '@oozcitak/dom': 2.0.2
+ '@oozcitak/infra': 2.0.2
+ '@oozcitak/util': 10.0.0
+ js-yaml: 4.3.2
+
+ yallist@3.1.1: {}
+
+ yaml@2.9.1: {}
+
+ zod@4.6.5: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..1cc58b6
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,8 @@
+packages:
+ - apps/*
+ - packages/*
+
+autoInstallPeers: false
+minimumReleaseAgeExclude:
+ - "@module-federation/vite@1.23.3"
+preferFrozenLockfile: true
diff --git a/test/example-build.test.mjs b/test/example-build.test.mjs
new file mode 100644
index 0000000..d362d90
--- /dev/null
+++ b/test/example-build.test.mjs
@@ -0,0 +1,101 @@
+import assert from "node:assert/strict";
+import { existsSync, readFileSync } from "node:fs";
+import { dirname, join } from "node:path";
+import { fileURLToPath } from "node:url";
+import test from "node:test";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..");
+const viteHostDist = join(root, "apps", "vite-host", "dist");
+const viteRemoteDist = join(root, "apps", "vite-remote", "dist");
+const rsbuildHostDist = join(root, "apps", "rsbuild-host", "dist");
+const rsbuildRemoteDist = join(root, "apps", "rsbuild-remote", "dist");
+
+function readJson(path) {
+ return JSON.parse(readFileSync(path, "utf8"));
+}
+
+test("all TanStack Start apps produce client and server builds", () => {
+ for (const [name, dist] of [
+ ["Vite host", viteHostDist],
+ ["Vite remote", viteRemoteDist],
+ ["rsbuild host", rsbuildHostDist],
+ ["rsbuild remote", rsbuildRemoteDist],
+ ]) {
+ assert.ok(existsSync(join(dist, "client", "mf-manifest.json")), `${name} client`);
+ const serverEntry = name.startsWith("rsbuild") ? "index.js" : "server.js";
+ assert.ok(existsSync(join(dist, "server", serverEntry)), `${name} server`);
+ }
+});
+
+test("remote publishes browser and server federation entries", () => {
+ const client = join(viteRemoteDist, "client");
+ assert.ok(existsSync(join(client, "remoteEntry.js")));
+ assert.ok(existsSync(join(client, "remoteEntry.ssr.js")));
+
+ const manifest = readJson(join(client, "mf-manifest.json"));
+ assert.equal(manifest.name, "tanstack_vite_remote");
+ assert.equal(manifest.metaData.remoteEntry.name, "remoteEntry.js");
+ assert.equal(manifest.metaData.ssrRemoteEntry.name, "remoteEntry.ssr.js");
+
+ const statusCard = manifest.exposes.find(({ path }) => path === "./StatusCard");
+ assert.ok(statusCard, "StatusCard expose is listed");
+ assert.ok(statusCard.assets.css.sync.length > 0, "StatusCard CSS is published");
+
+ for (const dependency of ["react", "react-dom"]) {
+ const shared = manifest.shared.find(({ name }) => name === dependency);
+ assert.equal(shared?.singleton, true, `${dependency} is a singleton`);
+ }
+});
+
+test("Vite host records the TanStack remote and server-side loader", () => {
+ const manifest = readJson(join(viteHostDist, "client", "mf-manifest.json"));
+ const remote = manifest.remotes.find(({ alias }) => alias === "tanstack_vite_remote");
+ assert.equal(remote?.moduleName, "StatusCard");
+
+ const serverFiles = readFileSync(join(viteHostDist, "server", ".vite", "manifest.json"), "utf8");
+ assert.match(serverFiles, /ssrEntryLoader/);
+ assert.match(serverFiles, /tanstack_vite_remote/);
+});
+
+test("Vite and Rsbuild publish reciprocal client interoperability contracts", () => {
+ const viteHostManifest = readJson(join(viteHostDist, "client", "mf-manifest.json"));
+ const rsbuildHostManifest = readJson(join(rsbuildHostDist, "client", "mf-manifest.json"));
+ const rsbuildRemoteClient = readJson(join(rsbuildRemoteDist, "client", "mf-manifest.json"));
+
+ assert.equal(
+ viteHostManifest.remotes.find(({ alias }) => alias === "tanstack_rsbuild_remote")?.moduleName,
+ "StatusCard",
+ );
+ assert.equal(
+ rsbuildHostManifest.remotes.find(({ alias }) => alias === "tanstack_vite_remote")?.entry,
+ "http://127.0.0.1:3001/mf-manifest.json",
+ );
+ assert.equal(
+ rsbuildHostManifest.remotes.find(({ alias }) => alias === "tanstack_rsbuild_remote")?.entry,
+ "http://127.0.0.1:3002/mf-manifest.json",
+ );
+ assert.equal(rsbuildRemoteClient.metaData.remoteEntry.type, "global");
+ assert.equal(rsbuildRemoteClient.metaData.remoteEntry.name, "remoteEntry.js");
+ const statusCard = rsbuildRemoteClient.exposes.find(({ path }) => path === "./StatusCard");
+ assert.ok(statusCard?.assets.css.sync.length > 0, "Rsbuild StatusCard CSS is published");
+ assert.equal(
+ existsSync(join(rsbuildRemoteDist, "server", "serverRemoteEntry.cjs")),
+ false,
+ "client-only cross-bundler remote does not publish an unused SSR container",
+ );
+ assert.equal(
+ existsSync(join(rsbuildHostDist, "server", "mf-manifest.json")),
+ false,
+ "client-only cross-bundler host does not initialize remotes during SSR",
+ );
+
+ for (const manifest of [rsbuildRemoteClient]) {
+ for (const dependency of ["react", "react-dom"]) {
+ assert.equal(
+ manifest.shared.find(({ name }) => name === dependency)?.singleton,
+ true,
+ `${dependency} is a singleton`,
+ );
+ }
+ }
+});
diff --git a/test/example-production.test.mjs b/test/example-production.test.mjs
new file mode 100644
index 0000000..e2686d5
--- /dev/null
+++ b/test/example-production.test.mjs
@@ -0,0 +1,4 @@
+// Production builds served by `vite preview` and `rsbuild preview`.
+import { describeExamples } from "./support/examples.mjs";
+
+describeExamples("preview");
diff --git a/test/example-runtime.test.mjs b/test/example-runtime.test.mjs
new file mode 100644
index 0000000..2b0b102
--- /dev/null
+++ b/test/example-runtime.test.mjs
@@ -0,0 +1,4 @@
+// Development servers: Vite and Rsbuild dev servers with in-memory builds.
+import { describeExamples } from "./support/examples.mjs";
+
+describeExamples("start");
diff --git a/test/release-artifacts.test.mjs b/test/release-artifacts.test.mjs
new file mode 100644
index 0000000..f7399af
--- /dev/null
+++ b/test/release-artifacts.test.mjs
@@ -0,0 +1,73 @@
+import assert from "node:assert/strict";
+import { spawnSync } from "node:child_process";
+import { existsSync, readFileSync } from "node:fs";
+import { dirname, join } from "node:path";
+import { fileURLToPath } from "node:url";
+import test from "node:test";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..");
+const packageRoot = join(root, "packages", "tanstack");
+const dist = join(packageRoot, "dist");
+
+test("published declarations reference included source maps", () => {
+ for (const declarationName of [
+ "index.d.cts",
+ "index.d.ts",
+ "node-entry-loader.d.cts",
+ "node-entry-loader.d.ts",
+ "rsbuild.d.cts",
+ "rsbuild.d.ts",
+ "runtime.d.cts",
+ "runtime.d.ts",
+ "vite.d.cts",
+ "vite.d.ts",
+ ]) {
+ const declaration = readFileSync(join(dist, declarationName), "utf8");
+ const sourceMap = declaration.match(/\/\/[#@]\s*sourceMappingURL=([^\s]+)\s*$/m)?.[1];
+
+ assert.ok(sourceMap, `${declarationName} has no source map reference`);
+ assert.ok(
+ existsSync(join(dist, sourceMap)),
+ `${declarationName} references missing source map ${sourceMap}`,
+ );
+ }
+});
+
+test("npm package contains only runtime, metadata, and documentation files", () => {
+ const packed = spawnSync("npm", ["pack", "--dry-run", "--json", "--ignore-scripts"], {
+ cwd: packageRoot,
+ encoding: "utf8",
+ });
+
+ assert.equal(packed.status, 0, packed.stderr);
+ const [manifest] = JSON.parse(packed.stdout);
+ const files = manifest.files.map(({ path }) => path).sort();
+
+ const entries = [
+ "index",
+ "node-entry-loader",
+ "rsbuild",
+ "runtime",
+ "shared",
+ "vite",
+ "vite-compat",
+ ];
+ const runtimeFiles = entries.flatMap((entry) => {
+ const sourceMaps = entry === "index" ? [] : [`dist/${entry}.js.map`];
+ return [
+ `dist/${entry}.cjs`,
+ `dist/${entry}.cjs.map`,
+ `dist/${entry}.d.cts`,
+ `dist/${entry}.d.cts.map`,
+ `dist/${entry}.d.ts`,
+ `dist/${entry}.d.ts.map`,
+ `dist/${entry}.js`,
+ ...sourceMaps,
+ ];
+ });
+
+ assert.deepEqual(
+ files,
+ ["CHANGELOG.md", "LICENSE", "README.md", ...runtimeFiles, "package.json"].sort(),
+ );
+});
diff --git a/test/release-contracts.test.mjs b/test/release-contracts.test.mjs
new file mode 100644
index 0000000..90ba1f0
--- /dev/null
+++ b/test/release-contracts.test.mjs
@@ -0,0 +1,582 @@
+import assert from "node:assert/strict";
+import { spawnSync } from "node:child_process";
+import {
+ cpSync,
+ existsSync,
+ mkdirSync,
+ mkdtempSync,
+ readFileSync,
+ rmSync,
+ symlinkSync,
+ writeFileSync,
+} from "node:fs";
+import { createRequire } from "node:module";
+import { dirname, join } from "node:path";
+import { tmpdir } from "node:os";
+import { fileURLToPath, pathToFileURL } from "node:url";
+import test from "node:test";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..");
+const packageRoot = join(root, "packages", "tanstack");
+const packageRequire = createRequire(join(packageRoot, "package.json"));
+const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
+const rootPackageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
+const ciWorkflow = readFileSync(join(root, ".github", "workflows", "ci.yml"), "utf8");
+const previewWorkflow = readFileSync(join(root, ".github", "workflows", "pkg-pr-new.yml"), "utf8");
+const releaseWorkflow = readFileSync(join(root, ".github", "workflows", "release.yml"), "utf8");
+const { tanstackStartModuleFederation } = await import(
+ pathToFileURL(join(packageRoot, "dist", "index.js")).href
+);
+const { eagerShared, resolveShared } = await import(
+ pathToFileURL(join(packageRoot, "dist", "shared.js")).href
+);
+const { tanstackStartModuleFederation: tanstackStartRsbuildModuleFederation } = await import(
+ pathToFileURL(join(packageRoot, "dist", "rsbuild.js")).href
+);
+
+function upstreamOptions(options) {
+ const plugins = tanstackStartModuleFederation(options);
+ assert.ok(Array.isArray(plugins), "federation wrapper returns Vite plugins");
+ const upstream = plugins.filter((plugin) => plugin.name === "module-federation-vite");
+ assert.equal(upstream.length, 1, "wrapper delegates to one federation instance");
+ assert.ok(upstream[0]._options, "upstream plugin exposes normalized options");
+ return upstream[0]._options;
+}
+
+test("applies TanStack-safe defaults", () => {
+ const options = upstreamOptions({
+ name: "host",
+ filename: undefined,
+ manifest: undefined,
+ hostInitInjectLocation: undefined,
+ });
+ assert.equal(options.filename, "remoteEntry.js");
+ assert.equal(options.manifest, true);
+ assert.equal(options.hostInitInjectLocation, "entry");
+ assert.equal(options.shared.react.shareConfig.singleton, true);
+ assert.equal(options.shared.react.shareConfig.eager, false, "remote-only builds stay lazy");
+ assert.equal(options.shared["react-dom"].shareConfig.singleton, true);
+});
+
+test("Vite hosts provide their own React eagerly so remotes cannot replace it", () => {
+ const options = upstreamOptions({
+ name: "host",
+ remotes: { remote: { type: "module", name: "remote", entry: "remoteEntry.js" } },
+ });
+ for (const dependency of ["react", "react-dom"]) {
+ assert.equal(options.shared[dependency].shareConfig.singleton, true);
+ assert.equal(options.shared[dependency].shareConfig.eager, true, `${dependency} is eager`);
+ }
+
+ const overridden = upstreamOptions({
+ name: "host",
+ remotes: { remote: { type: "module", name: "remote", entry: "remoteEntry.js" } },
+ shared: { react: { singleton: true } },
+ });
+ assert.equal(overridden.shared.react.shareConfig.eager, false, "explicit entries win");
+});
+
+test("preserves explicit federation settings and shared entries", () => {
+ const options = upstreamOptions({
+ name: "remote",
+ filename: "custom-entry.js",
+ manifest: false,
+ hostInitInjectLocation: "html",
+ shared: {
+ react: { singleton: false, requiredVersion: "^19.0.0" },
+ lodash: { singleton: true },
+ },
+ });
+ assert.equal(options.filename, "custom-entry.js");
+ assert.equal(options.manifest, false);
+ assert.equal(options.hostInitInjectLocation, "html");
+ assert.equal(options.shared.react.shareConfig.singleton, false);
+ assert.equal(options.shared.react.shareConfig.requiredVersion, "^19.0.0");
+ assert.equal(options.shared.lodash.shareConfig.singleton, true);
+ assert.ok(options.shared["react-dom"], "unconfigured React DOM remains shared");
+});
+
+test("does not mutate the caller's options", () => {
+ const options = {
+ name: "host",
+ shared: { react: { singleton: false } },
+ remotes: { remote: { type: "module", name: "remote", entry: "remoteEntry.js" } },
+ };
+ const before = structuredClone(options);
+ upstreamOptions(options);
+ assert.deepEqual(options, before);
+});
+
+test("accepts the upstream array form", () => {
+ const options = upstreamOptions({ name: "remote", shared: ["lodash", "react"] });
+ assert.deepEqual(Object.keys(options.shared).sort(), ["lodash", "react", "react-dom"]);
+ assert.equal(options.shared.react.shareConfig.singleton, true);
+ assert.equal(options.shared["react-dom"].shareConfig.singleton, true);
+});
+
+test("leaves the build target to each TanStack environment", () => {
+ const options = upstreamOptions({ name: "host", target: "node" });
+ assert.equal(options.target, undefined);
+});
+
+function vitePlugin(name) {
+ const plugin = tanstackStartModuleFederation({ name: "host" }).find(
+ (candidate) => candidate.name === name,
+ );
+ assert.ok(plugin, `${name} is registered`);
+ return plugin;
+}
+
+test("the Vite adapter fails fast on Vite 7", () => {
+ const plugin = vitePlugin("tanstack-start-federation:vite-version");
+ assert.throws(
+ () => plugin.config.call({ meta: { viteVersion: "7.3.6" } }),
+ /requires Vite 8; this project runs Vite 7\.3\.6/,
+ );
+ assert.doesNotThrow(() => plugin.config.call({ meta: { viteVersion: "8.3.2" } }));
+});
+
+test("Rsbuild shared defaults never mutate caller overrides", () => {
+ const callerShared = { react: { eager: false, singleton: false } };
+ const before = structuredClone(callerShared);
+ const shared = resolveShared(callerShared, eagerShared);
+
+ assert.deepEqual(callerShared, before);
+ assert.deepEqual(shared.react, { eager: false, singleton: false });
+ assert.deepEqual(shared["react-dom"], { eager: true, singleton: true });
+});
+
+const rsbuildRemote = { name: "test_remote", exposes: { "./Card": "./src/Card.tsx" } };
+const rsbuildHost = {
+ name: "test_host",
+ remotes: { remote: "remote@http://remote/mf-manifest.json" },
+};
+
+test("Rsbuild hosts share eager React; remotes and server containers stay lazy", () => {
+ const [hostClient, hostServer] = federationOptions({ federation: rsbuildHost, server: true });
+ const [remoteClient, remoteContainer] = federationOptions({
+ federation: rsbuildRemote,
+ server: true,
+ });
+
+ for (const options of [hostClient, hostServer]) {
+ assert.deepEqual(options.shared.react, { eager: true, singleton: true });
+ assert.deepEqual(options.shared["react-dom"], { eager: true, singleton: true });
+ }
+ for (const options of [remoteClient, remoteContainer]) {
+ assert.deepEqual(options.shared.react, { singleton: true });
+ assert.deepEqual(options.shared["react-dom"], { singleton: true });
+ }
+});
+
+test("Rsbuild enables async startup unless the caller disables it", () => {
+ const [enabled] = federationOptions({ federation: rsbuildRemote });
+ assert.equal(enabled.experiments.asyncStartup, true);
+
+ const [disabled] = federationOptions({
+ federation: { ...rsbuildRemote, experiments: { asyncStartup: false } },
+ });
+ assert.equal(disabled.experiments.asyncStartup, false);
+});
+
+test("Rsbuild federation is browser-only by default", () => {
+ const pluginNames = (federation) =>
+ tanstackStartRsbuildModuleFederation({ federation }).map(({ name }) => name);
+ assert.deepEqual(pluginNames(rsbuildRemote), [
+ "rsbuild:module-federation-enhanced",
+ "tanstack-start-federation-client-compat",
+ ]);
+ assert.deepEqual(pluginNames(rsbuildHost), [
+ "rsbuild:module-federation-enhanced",
+ "tanstack-start-federation-remote-retry",
+ "tanstack-start-federation-client-compat",
+ ]);
+});
+
+test("Rsbuild remotes resolve browser chunks from their own origin", () => {
+ const remoteClient = { name: "client", output: { publicPath: "/" } };
+ runHooks(clientCompat(rsbuildRemote)).onBeforeCreateCompiler({ bundlerConfigs: [remoteClient] });
+ assert.equal(remoteClient.output.publicPath, "auto");
+
+ const cdnClient = { name: "client", output: { publicPath: "https://cdn.example/remote/" } };
+ runHooks(clientCompat(rsbuildRemote)).onBeforeCreateCompiler({ bundlerConfigs: [cdnClient] });
+ assert.equal(cdnClient.output.publicPath, "https://cdn.example/remote/");
+
+ const hostClient = { name: "client", output: { publicPath: "/" } };
+ runHooks(clientCompat(rsbuildHost)).onBeforeCreateCompiler({ bundlerConfigs: [hostClient] });
+ assert.deepEqual(hostClient.output, {
+ chunkFormat: "array-push",
+ chunkLoading: "jsonp",
+ chunkLoadingGlobal: "chunk_test_host",
+ module: false,
+ publicPath: "/",
+ uniqueName: "test_host",
+ });
+});
+
+test("Rsbuild hosts can load a remote again after it failed", () => {
+ const plugin = tanstackStartRsbuildModuleFederation({ federation: rsbuildHost }).find(
+ ({ name }) => name === "tanstack-start-federation-remote-retry",
+ );
+ let transform;
+ plugin.setup({ transform: (options, handler) => (transform = { handler, options }) });
+ const runtimeRoot = findPackageRoot(
+ createRequire(packageRequire.resolve("@module-federation/rsbuild-plugin")).resolve(
+ "@module-federation/webpack-bundler-runtime",
+ ),
+ );
+ for (const file of ["remotes.cjs", "remotes.js"]) {
+ const path = join(runtimeRoot, "dist", file);
+ assert.ok(transform.options.test.test(path), file);
+ const code = readFileSync(path, "utf8");
+ const patched = transform.handler({ code });
+ assert.equal(patched.split("\n").length, code.split("\n").length, `${file} keeps its lines`);
+ // Without strict handling, a module that threw stays cached with empty exports; Rspack's
+ // strict handling caches the error instead. The failed module must leave the cache.
+ assert.match(
+ patched,
+ /webpackRequire\.m\[id\] = \(\) => \{ if \(webpackRequire\.c\) delete webpackRequire\.c\[id\];\s*throw error;/,
+ file,
+ );
+ }
+});
+
+test("Rsbuild SSR remotes ship a Node container with the browser assets", async () => {
+ const plugins = tanstackStartRsbuildModuleFederation({ federation: rsbuildRemote, server: true });
+ assert.deepEqual(
+ plugins.map(({ name }) => name),
+ [
+ "rsbuild:module-federation-enhanced",
+ "tanstack-start-federation-client-compat",
+ "tanstack-start-federation-server-container",
+ "rsbuild:module-federation-enhanced",
+ ],
+ );
+
+ const hooks = runHooks(
+ plugins.find(({ name }) => name === "tanstack-start-federation-server-container"),
+ );
+ const rsbuildConfig = { environments: { client: {}, ssr: {} } };
+ assert.equal(hooks.modifyRsbuildConfig.order, "pre");
+ hooks.modifyRsbuildConfig.handler(rsbuildConfig);
+ assert.deepEqual(rsbuildConfig.environments["mf-server"], {
+ source: { entry: { "mf-server": "data:text/javascript," } },
+ output: { cleanDistPath: false, emitAssets: false, target: "node" },
+ });
+
+ // The container sits next to the manifest; its chunks load over HTTP from the same
+ // public path as the browser assets.
+ for (const publicPath of ["http://127.0.0.1:3004/", "auto"]) {
+ const client = { name: "client", output: { path: "/app/dist/client", publicPath } };
+ const container = { name: "mf-server", output: {} };
+ hooks.onBeforeCreateCompiler({ bundlerConfigs: [client, container] });
+ assert.deepEqual(container.output, {
+ chunkFilename: "ssr/[id].[contenthash:8].js",
+ filename: "ssr/[name].js",
+ path: "/app/dist/client",
+ publicPath,
+ });
+ }
+ assert.throws(
+ () => hooks.onBeforeCreateCompiler({ bundlerConfigs: [{ name: "mf-server", output: {} }] }),
+ /Register tanstackStart\(\) before tanstackStartModuleFederation\(\)/,
+ );
+
+ // The container is emitted as Module Federation builds it.
+ assert.equal(hooks.processAssets, undefined);
+
+ const [client, container] = federationOptions({ federation: rsbuildRemote, server: true });
+ assert.equal(container.filename, "remoteEntry.ssr.cjs");
+ assert.equal(container.manifest, false);
+ assert.equal(container.remotes, undefined);
+ const stats = await client.manifest.additionalData({ stats: { metaData: {} } });
+ assert.deepEqual(stats.metaData.ssrRemoteEntry, {
+ name: "remoteEntry.ssr.cjs",
+ path: "",
+ type: "commonjs-module",
+ });
+});
+
+test("Rsbuild SSR hosts load remotes from an async-node CommonJS server", () => {
+ const plugins = tanstackStartRsbuildModuleFederation({ federation: rsbuildHost, server: true });
+ assert.deepEqual(
+ plugins.map(({ name }) => name),
+ [
+ "rsbuild:module-federation-enhanced",
+ "tanstack-start-federation-remote-retry",
+ "tanstack-start-federation-client-compat",
+ "rsbuild:module-federation-enhanced",
+ "tanstack-start-federation-ssr-compat",
+ ],
+ );
+
+ const [, server] = federationOptions({ federation: rsbuildHost, server: true });
+ assert.equal(server.manifest, false);
+ assert.equal(server.exposes, undefined);
+ assert.ok(server.runtimePlugins.includes("@module-federation/tanstack/node-entry-loader"));
+
+ const hooks = runHooks(
+ plugins.find(({ name }) => name === "tanstack-start-federation-ssr-compat"),
+ );
+ const serverConfig = { name: "ssr", output: { chunkLoadingGlobal: "stale" } };
+ hooks.onBeforeCreateCompiler({ bundlerConfigs: [{ name: "client", output: {} }, serverConfig] });
+ assert.equal(serverConfig.target, "async-node");
+ assert.deepEqual(serverConfig.output, {
+ chunkFilename: "[id].test_host.cjs",
+ chunkFormat: "commonjs",
+ chunkLoading: "async-node",
+ filename: "[name].cjs",
+ library: { type: "commonjs2" },
+ module: false,
+ });
+
+ const environmentConfig = () => ({ dev: {}, output: { distPath: { root: "dist/server" } } });
+ const buildConfig = environmentConfig();
+ hooks.modifyEnvironmentConfig(buildConfig, { name: "ssr" });
+ assert.equal(buildConfig.dev.writeToDisk, true, "async-node chunks are read from disk");
+ assert.equal(buildConfig.output.distPath.root, "dist/server");
+
+ // A dev server writes its bundle elsewhere, so a production build in dist/server survives.
+ const devHooks = runHooks(
+ plugins.find(({ name }) => name === "tanstack-start-federation-ssr-compat"),
+ { action: "dev" },
+ );
+ const devConfig = environmentConfig();
+ devHooks.modifyEnvironmentConfig(devConfig, { name: "ssr" });
+ assert.equal(devConfig.dev.writeToDisk, true);
+ assert.equal(
+ devConfig.output.distPath.root,
+ join("/app", "node_modules", ".cache", "tanstack-start-federation", "ssr"),
+ );
+
+ const emitted = {};
+ hooks.processAssets.handler({
+ assets: { "index.cjs": {} },
+ compilation: { emitAsset: (name, source) => (emitted[name] = source.source()) },
+ sources: {
+ RawSource: class {
+ constructor(value) {
+ this.value = value;
+ }
+ source() {
+ return this.value;
+ }
+ },
+ },
+ });
+ assert.deepEqual(hooks.processAssets.options, { stage: "additional", environments: ["ssr"] });
+ assert.match(emitted["index.js"], /await createRequire\(import\.meta\.url\)\("\.\/index\.cjs"\)/);
+});
+
+test("Rsbuild ESM server output is left to TanStack Start", () => {
+ const plugins = tanstackStartRsbuildModuleFederation({
+ federation: rsbuildHost,
+ server: { forceCommonJsOutput: false },
+ });
+ const hooks = runHooks(
+ plugins.find(({ name }) => name === "tanstack-start-federation-ssr-compat"),
+ );
+ const serverConfig = { name: "ssr", output: { chunkFilename: "[id].js", filename: "[name].js" } };
+ hooks.onBeforeCreateCompiler({ bundlerConfigs: [serverConfig] });
+ assert.deepEqual(serverConfig, {
+ name: "ssr",
+ output: { chunkFilename: "[id].js", filename: "[name].js" },
+ });
+ assert.equal(hooks.processAssets, undefined);
+ assert.equal(hooks.modifyEnvironmentConfig, undefined);
+});
+
+function clientCompat(federation) {
+ return tanstackStartRsbuildModuleFederation({ federation }).find(
+ ({ name }) => name === "tanstack-start-federation-client-compat",
+ );
+}
+
+/** Returns the Module Federation options each enhanced plugin receives, in plugin order. */
+function federationOptions(options) {
+ return tanstackStartRsbuildModuleFederation(options)
+ .filter(({ name }) => name === "rsbuild:module-federation-enhanced")
+ .map((plugin) => {
+ let exposed;
+ plugin.setup(
+ new Proxy(
+ {},
+ {
+ get(_, key) {
+ if (key === "context") return { callerName: "rsbuild" };
+ if (key === "expose") return (_name, api) => (exposed = api);
+ if (key === "getRsbuildConfig") return () => ({});
+ return () => {};
+ },
+ },
+ ),
+ );
+ return exposed.getOptions();
+ });
+}
+
+/** Runs a plugin's setup against a recording API and returns the hooks it registered. */
+function runHooks(plugin, { action = "build" } = {}) {
+ const hooks = {};
+ plugin.setup({
+ context: { action, rootPath: "/app" },
+ modifyEnvironmentConfig: (handler) => (hooks.modifyEnvironmentConfig = handler),
+ modifyRsbuildConfig: (hook) => (hooks.modifyRsbuildConfig = hook),
+ onBeforeCreateCompiler: (handler) => (hooks.onBeforeCreateCompiler = handler),
+ processAssets: (options, handler) => (hooks.processAssets = { handler, options }),
+ });
+ return hooks;
+}
+
+test("published metadata selects ESM and CommonJS builds with matching types", () => {
+ assert.equal(packageJson.type, "module");
+ assert.equal(packageJson.exports["."].import.default, "./dist/index.js");
+ assert.equal(packageJson.exports["."].import.types, "./dist/index.d.ts");
+ assert.equal(packageJson.exports["."].require.default, "./dist/index.cjs");
+ assert.equal(packageJson.exports["."].require.types, "./dist/index.d.cts");
+ assert.equal(
+ packageRequire.resolve("@module-federation/tanstack"),
+ join(packageRoot, "dist", "index.cjs"),
+ );
+ for (const file of ["index.cjs", "index.js", "index.d.cts", "index.d.ts"]) {
+ assert.ok(existsSync(join(packageRoot, "dist", file)), `dist/${file} exists`);
+ }
+});
+
+test("clean consumers resolve CJS and ESM entrypoints without the other adapter", () => {
+ const viteConsumer = createConsumer(["@module-federation/vite"]);
+ const rsbuildConsumer = createConsumer(["@module-federation/rsbuild-plugin", "@rsbuild/core"]);
+
+ try {
+ const viteRequire = createRequire(join(viteConsumer, "consumer.cjs"));
+ const rsbuildRequire = createRequire(join(rsbuildConsumer, "consumer.cjs"));
+ const cjsRoot = viteRequire("@module-federation/tanstack");
+ const cjsRsbuild = rsbuildRequire("@module-federation/tanstack/rsbuild");
+
+ assert.equal(typeof cjsRoot.tanstackStartModuleFederation, "function");
+ assert.equal(typeof cjsRsbuild.tanstackStartModuleFederation, "function");
+ assertConsumerImport(viteConsumer, "@module-federation/tanstack");
+ assertConsumerImport(viteConsumer, "@module-federation/tanstack/vite");
+ assertConsumerImport(rsbuildConsumer, "@module-federation/tanstack/rsbuild");
+ } finally {
+ rmSync(viteConsumer, { force: true, recursive: true });
+ rmSync(rsbuildConsumer, { force: true, recursive: true });
+ }
+
+ assert.doesNotMatch(
+ readFileSync(join(packageRoot, "dist", "rsbuild.js"), "utf8"),
+ /@module-federation\/vite/,
+ );
+ assert.doesNotMatch(
+ readFileSync(join(packageRoot, "dist", "vite.js"), "utf8"),
+ /@module-federation\/rsbuild-plugin/,
+ );
+});
+
+test("runtime subpaths load without a bundler adapter", () => {
+ // Route code imports the runtime helpers, so React is always installed next to them.
+ const consumer = createConsumer(["react"]);
+ try {
+ const consumerRequire = createRequire(join(consumer, "consumer.cjs"));
+ const runtime = consumerRequire("@module-federation/tanstack/runtime");
+ const loader = consumerRequire("@module-federation/tanstack/node-entry-loader");
+ assert.equal(typeof runtime.getRemoteStylesheets, "function");
+ assert.equal(typeof runtime.lazyRemote, "function");
+ assert.equal(typeof loader.default, "function");
+ assert.equal(typeof loader.RemoteEntryError, "function");
+ } finally {
+ rmSync(consumer, { force: true, recursive: true });
+ }
+
+ // Route code imports the runtime helpers in the browser too.
+ for (const file of ["runtime.js", "runtime.cjs"]) {
+ assert.doesNotMatch(
+ readFileSync(join(packageRoot, "dist", file), "utf8"),
+ /node:|@module-federation\/(?:vite|rsbuild-plugin)|@rsbuild\/core/,
+ file,
+ );
+ }
+});
+
+function assertConsumerImport(consumer, specifier) {
+ const entry = join(consumer, "consumer.mjs");
+ writeFileSync(
+ entry,
+ `import { tanstackStartModuleFederation } from ${JSON.stringify(specifier)};\n` +
+ `if (typeof tanstackStartModuleFederation !== "function") process.exit(2);\n`,
+ );
+ const result = spawnSync(process.execPath, [entry], {
+ cwd: consumer,
+ encoding: "utf8",
+ });
+ assert.equal(result.status, 0, result.stderr);
+}
+
+function createConsumer(adapterPackages) {
+ const consumer = mkdtempSync(join(tmpdir(), "mf-tanstack-consumer-"));
+ const packageTarget = join(consumer, "node_modules", "@module-federation", "tanstack");
+ mkdirSync(dirname(packageTarget), { recursive: true });
+ cpSync(packageRoot, packageTarget, {
+ filter: (source) => !source.includes("/node_modules/") && !source.includes("/.turbo/"),
+ recursive: true,
+ });
+
+ for (const packageName of adapterPackages) {
+ const adapterRoot = findPackageRoot(packageRequire.resolve(packageName));
+ const adapterTarget = join(consumer, "node_modules", ...packageName.split("/"));
+ mkdirSync(dirname(adapterTarget), { recursive: true });
+ symlinkSync(adapterRoot, adapterTarget);
+ }
+
+ return consumer;
+}
+
+function findPackageRoot(entryPoint) {
+ let directory = dirname(entryPoint);
+ while (!existsSync(join(directory, "package.json"))) {
+ const parent = dirname(directory);
+ if (parent === directory) throw new Error(`Could not find package root for ${entryPoint}`);
+ directory = parent;
+ }
+ return directory;
+}
+
+test("CI uses Node versions supported by the package build toolchain", () => {
+ const supportedNode = "^22.18.0 || ^24.11.0 || >=26.0.0";
+ assert.equal(rootPackageJson.engines.node, supportedNode);
+ assert.equal(packageJson.engines.node, supportedNode);
+ assert.match(ciWorkflow, /node: \["22\.18\.0", "24", "26"\]/);
+ assert.doesNotMatch(ciWorkflow, /22\.12\.0/);
+});
+
+test("bundler adapters are isolated optional peers", () => {
+ for (const dependency of [
+ "@module-federation/rsbuild-plugin",
+ "@module-federation/vite",
+ "@rsbuild/core",
+ "vite",
+ ]) {
+ assert.ok(packageJson.peerDependencies[dependency], `${dependency} has a peer range`);
+ assert.equal(packageJson.peerDependenciesMeta[dependency]?.optional, true);
+ }
+ assert.equal(packageJson.optionalDependencies, undefined);
+});
+
+test("GitHub prereleases publish the version validated against their tag", () => {
+ assert.match(releaseWorkflow, /Tag\/version mismatch/);
+ assert.doesNotMatch(releaseWorkflow, /Set deterministic prerelease version/);
+ assert.doesNotMatch(
+ releaseWorkflow,
+ /github\.event\.release\.prerelease[\s\S]*npm pkg set version/,
+ );
+});
+
+test("npm publications share one package-wide concurrency queue", () => {
+ assert.match(releaseWorkflow, /group: publish-module-federation-tanstack/);
+ assert.doesNotMatch(releaseWorkflow, /group:.*github\.(?:ref|run)/);
+});
+
+test("first package preview does not require an existing npm release", () => {
+ assert.match(previewWorkflow, /pkg-pr-new@0\.0\.54 publish \.\/packages\/tanstack/);
+ assert.doesNotMatch(previewWorkflow, /--compact/);
+});
diff --git a/test/runtime.test.mjs b/test/runtime.test.mjs
new file mode 100644
index 0000000..9cd4e95
--- /dev/null
+++ b/test/runtime.test.mjs
@@ -0,0 +1,307 @@
+import assert from "node:assert/strict";
+import { execFile, spawnSync } from "node:child_process";
+import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
+import { createServer } from "node:http";
+import { createRequire } from "node:module";
+import { tmpdir } from "node:os";
+import { dirname, join } from "node:path";
+import { fileURLToPath, pathToFileURL } from "node:url";
+import { promisify } from "node:util";
+import { after, before, test } from "node:test";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..");
+const dist = join(root, "packages", "tanstack", "dist");
+const loaderUrl = pathToFileURL(join(dist, "node-entry-loader.js")).href;
+const { default: nodeEntryLoader, RemoteEntryError } = await import(loaderUrl);
+const { getRemoteStylesheets, lazyRemote } = await import(
+ pathToFileURL(join(dist, "runtime.js")).href
+);
+// The React copy the runtime resolves.
+const packageRequire = createRequire(join(root, "packages", "tanstack", "package.json"));
+const { createElement, Suspense } = packageRequire("react");
+const { renderToString } = packageRequire("react-dom/server");
+const { prerenderToNodeStream } = packageRequire("react-dom/static");
+
+const files = new Map();
+const requests = [];
+let server;
+let origin;
+
+before(async () => {
+ server = createServer((request, response) => {
+ requests.push(request.url);
+ const file = files.get(request.url);
+ if (!file) {
+ response.writeHead(404).end();
+ return;
+ }
+ response.writeHead(200, { "content-type": file.type }).end(file.body);
+ });
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
+ origin = `http://127.0.0.1:${server.address().port}`;
+});
+
+after(() => server.close());
+
+function serve(path, body, type = "text/javascript") {
+ files.set(path, { body, type });
+ return `${origin}${path}`;
+}
+
+function loadEntry(entry, type = "commonjs-module") {
+ const remoteInfo = { entry, entryGlobalName: "remote", name: "remote", type };
+ return nodeEntryLoader().loadEntry({ origin: {}, remoteInfo });
+}
+
+test("loads HTTP CommonJS containers as CommonJS modules", async () => {
+ // Rsbuild containers import Node built-ins through `new Function` at runtime.
+ const entry = serve(
+ "/cjs/remoteEntry.ssr.cjs",
+ `
+ const importNode = new Function("name", "return import(name)");
+ module.exports = {
+ init() {},
+ async get(request) {
+ const path = await importNode("node:path");
+ return () => ({ request, separator: path.sep, filename: __filename });
+ },
+ };
+ `,
+ );
+
+ const container = await loadEntry(entry);
+ const factory = await container.get("./Card");
+ assert.deepEqual(factory(), { request: "./Card", separator: "/", filename: entry });
+});
+
+test("reports which step failed and keeps the cause", async () => {
+ await assert.rejects(loadEntry(`${origin}/missing/remoteEntry.ssr.cjs`), (error) => {
+ assert.ok(error instanceof RemoteEntryError);
+ assert.equal(error.phase, "fetch");
+ assert.equal(error.remote, "remote");
+ assert.equal(error.url, `${origin}/missing/remoteEntry.ssr.cjs`);
+ assert.match(error.cause.message, /HTTP 404/);
+ return true;
+ });
+
+ const closed = createServer();
+ await new Promise((resolve) => closed.listen(0, "127.0.0.1", resolve));
+ const offline = `http://127.0.0.1:${closed.address().port}/remoteEntry.ssr.cjs`;
+ await new Promise((resolve) => closed.close(resolve));
+ await assert.rejects(loadEntry(offline), { name: "RemoteEntryError", phase: "fetch" });
+
+ const throwing = serve("/throws/remoteEntry.ssr.cjs", 'throw new Error("container failed");');
+ await assert.rejects(loadEntry(throwing), (error) => {
+ assert.equal(error.phase, "evaluate");
+ assert.equal(error.cause.message, "container failed");
+ return true;
+ });
+
+ const empty = serve("/empty/remoteEntry.ssr.cjs", "module.exports = {};");
+ await assert.rejects(loadEntry(empty), {
+ message: /did not export a federation container/,
+ phase: "evaluate",
+ });
+});
+
+test("leaves other entries to the federation runtime", async () => {
+ assert.equal(await loadEntry(`${origin}/remoteEntry.js`, "global"), undefined);
+ assert.equal(await loadEntry("/local/remoteEntry.ssr.cjs"), undefined);
+});
+
+test("Vite remotes ask for @module-federation/vite when the host lacks it", () => {
+ const app = mkdtempSync(join(tmpdir(), "mf-tanstack-host-"));
+ try {
+ const script = join(app, "server.mjs");
+ writeFileSync(
+ script,
+ `
+ const { default: loader } = await import(${JSON.stringify(loaderUrl)});
+ const remoteInfo = { entry: "http://127.0.0.1:9/remoteEntry.ssr.js", name: "vite_remote", type: "module" };
+ const origin = { name: "host", options: { shared: {} }, shareScopeMap: {} };
+ try {
+ await loader().loadEntry({ origin, remoteInfo });
+ } catch (error) {
+ console.log(JSON.stringify({ message: error.message, phase: error.phase }));
+ }
+ `,
+ );
+ const result = spawnSync(process.execPath, [script], { cwd: app, encoding: "utf8" });
+ assert.equal(result.status, 0, result.stderr);
+ const error = JSON.parse(result.stdout);
+ assert.equal(error.phase, "loader");
+ assert.match(error.message, /Add @module-federation\/vite to the host's dependencies/);
+ } finally {
+ rmSync(app, { force: true, recursive: true });
+ }
+});
+
+/**
+ * Runs `body` as an ES module in the Rsbuild SSR example host, which depends on
+ * @module-federation/vite and React, and returns the JSON it logs last. It runs in a child
+ * process so the loader's module registrations stay out of this one.
+ */
+async function runInHost(body) {
+ const app = join(root, "apps", "rsbuild-ssr-host");
+ const directory = mkdtempSync(join(tmpdir(), "mf-tanstack-host-"));
+ try {
+ const script = join(directory, "server.mjs");
+ writeFileSync(
+ script,
+ `const { default: loader } = await import(${JSON.stringify(loaderUrl)});\n${body}`,
+ );
+ // Asynchronous, so this process's test server can answer the child.
+ const { stdout } = await promisify(execFile)(process.execPath, [script], { cwd: app });
+ return JSON.parse(stdout.trim().split("\n").at(-1));
+ } finally {
+ rmSync(directory, { force: true, recursive: true });
+ }
+}
+
+test("Vite remotes resolve node_modules React to the host's own instance", async () => {
+ const outcome = await runInHost(`
+ import { createRequire } from "node:module";
+ const hostReact = { version: "host" };
+ const unused = { version: "not loaded" };
+ const origin = {
+ name: "host",
+ options: { shared: {} },
+ shareScopeMap: {
+ default: {
+ react: { "19.3.0": { from: "host", loaded: true, lib: () => hostReact } },
+ "react-dom": { "19.3.0": { from: "host", lib: () => unused } },
+ },
+ },
+ };
+ // A closed port: the load fails, after the host's modules are registered.
+ const remoteInfo = { entry: "http://127.0.0.1:9/remoteEntry.js", name: "vite_remote", type: "module" };
+ const phase = await loader().loadEntry({ origin, remoteInfo }).catch((error) => error.phase);
+ const appRequire = createRequire(process.cwd() + "/package.json");
+ console.log(JSON.stringify({
+ phase,
+ react: appRequire("react") === hostReact,
+ reactDom: appRequire("react-dom") === unused,
+ }));
+ `);
+ assert.deepEqual(outcome, { phase: "fetch", react: true, reactDom: false });
+});
+
+test("Vite remotes report a reachable remote without a server entry", async () => {
+ // A Vite remote built without a server entry: its manifest lists no ssrRemoteEntry.
+ const entry = serve("/no-ssr/remoteEntry.js", "export {};");
+ serve(
+ "/no-ssr/mf-manifest.json",
+ JSON.stringify({
+ exposes: [],
+ metaData: { remoteEntry: { name: "remoteEntry.js", path: "" } },
+ }),
+ "application/json",
+ );
+ const outcome = await runInHost(`
+ const origin = { name: "host", options: { shared: {} }, shareScopeMap: {} };
+ const remoteInfo = { entry: ${JSON.stringify(entry)}, name: "vite_remote", type: "module" };
+ const error = await loader().loadEntry({ origin, remoteInfo }).catch((error) => error);
+ console.log(JSON.stringify({ message: error.message, phase: error.phase }));
+ `);
+ assert.equal(outcome.phase, "loader");
+ assert.match(outcome.message, /could not load the server entry of remote "vite_remote"/);
+});
+
+test("getRemoteStylesheets resolves an expose's CSS from its manifest", async () => {
+ const manifest = (publicPath) =>
+ JSON.stringify({
+ exposes: [
+ {
+ assets: { css: { async: ["assets/lazy.css"], sync: ["assets/card.css"] } },
+ name: "Card",
+ path: "./Card",
+ },
+ ],
+ metaData: { publicPath },
+ });
+
+ const auto = serve("/auto/mf-manifest.json", manifest("auto"), "application/json");
+ assert.deepEqual(await getRemoteStylesheets(auto, "./Card"), [
+ `${origin}/auto/assets/card.css`,
+ `${origin}/auto/assets/lazy.css`,
+ ]);
+ assert.deepEqual(await getRemoteStylesheets(auto, "Card"), [
+ `${origin}/auto/assets/card.css`,
+ `${origin}/auto/assets/lazy.css`,
+ ]);
+ await assert.rejects(getRemoteStylesheets(auto, "./Missing"), /does not expose "\.\/Missing"/);
+
+ const cdn = serve(
+ "/cdn/mf-manifest.json",
+ manifest("https://cdn.test/remote/"),
+ "application/json",
+ );
+ assert.deepEqual(await getRemoteStylesheets(cdn, "./Card"), [
+ "https://cdn.test/remote/assets/card.css",
+ "https://cdn.test/remote/assets/lazy.css",
+ ]);
+});
+
+test("getRemoteStylesheets reuses manifests briefly and retries failures", async () => {
+ const path = "/cache/mf-manifest.json";
+ const url = `${origin}${path}`;
+ const fetches = () => requests.filter((request) => request === path).length;
+
+ await assert.rejects(getRemoteStylesheets(url, "./Card"), /HTTP 404/);
+ serve(path, JSON.stringify({ exposes: [{ name: "Card", path: "./Card" }] }), "application/json");
+ assert.deepEqual(await getRemoteStylesheets(url, "./Card"), []);
+ assert.deepEqual(await getRemoteStylesheets(url, "./Card"), []);
+ assert.equal(fetches(), 2, "the failure was retried, the success reused");
+
+ assert.deepEqual(await getRemoteStylesheets(url, "./Card", { maxAgeMs: 0 }), []);
+ assert.equal(fetches(), 3, "an expired manifest is fetched again");
+});
+
+/** Server-renders `element` to HTML once every Suspense boundary has settled. */
+async function prerender(element) {
+ const errors = [];
+ const { prelude } = await prerenderToNodeStream(
+ createElement(Suspense, { fallback: "fallback" }, element),
+ { onError: (error) => void errors.push(error.message) },
+ );
+ let html = "";
+ for await (const chunk of prelude) html += chunk;
+ return { errors, html };
+}
+
+test("lazyRemote renders the remote, and loads again only after retryAfterMs", async () => {
+ let online = false;
+ let loads = 0;
+ const Card = ({ label }) => createElement("p", null, `card ${label}`);
+ const RemoteCard = lazyRemote(
+ async () => {
+ loads++;
+ if (!online) throw new Error("remote offline");
+ return { default: Card };
+ },
+ { retryAfterMs: 100 },
+ );
+
+ const offline = await prerender(createElement(RemoteCard, { label: "one" }));
+ assert.deepEqual(offline.errors, ["remote offline"]);
+ assert.doesNotMatch(offline.html, /card/);
+ assert.equal(loads, 1);
+
+ // The remote is back, but the failure stands until retryAfterMs passes.
+ online = true;
+ const tooSoon = await prerender(createElement(RemoteCard, { label: "two" }));
+ assert.deepEqual(tooSoon.errors, ["remote offline"]);
+ assert.equal(loads, 1);
+
+ await new Promise((resolve) => setTimeout(resolve, 120));
+ const recovered = await prerender(createElement(RemoteCard, { label: "three" }));
+ assert.deepEqual(recovered.errors, []);
+ assert.match(recovered.html, /card three/);
+ assert.equal(loads, 2);
+
+ // A loaded remote is never loaded again.
+ online = false;
+ await new Promise((resolve) => setTimeout(resolve, 120));
+ assert.match(renderToString(createElement(RemoteCard, { label: "four" })), /card four/);
+ assert.equal(loads, 2);
+});
diff --git a/test/support/examples.mjs b/test/support/examples.mjs
new file mode 100644
index 0000000..94057a3
--- /dev/null
+++ b/test/support/examples.mjs
@@ -0,0 +1,430 @@
+import assert from "node:assert/strict";
+import { spawn } from "node:child_process";
+import { existsSync, readFileSync } from "node:fs";
+import { dirname, join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { after, before, test } from "node:test";
+import { chromium } from "playwright";
+import { getRemoteStylesheets } from "../../packages/tanstack/dist/runtime.js";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
+
+export const apps = {
+ viteHost: { name: "tanstack-start-vite-host", url: "http://127.0.0.1:3000/" },
+ viteRemote: { name: "tanstack-start-vite-remote", url: "http://127.0.0.1:3001/" },
+ rsbuildRemote: { name: "tanstack-start-rsbuild-remote", url: "http://127.0.0.1:3002/" },
+ rsbuildHost: { name: "tanstack-start-rsbuild-host", url: "http://127.0.0.1:3003/" },
+ rsbuildSsrRemote: { name: "tanstack-start-rsbuild-ssr-remote", url: "http://127.0.0.1:3004/" },
+ rsbuildSsrHost: { name: "tanstack-start-rsbuild-ssr-host", url: "http://127.0.0.1:3005/" },
+};
+
+const remotes = ["viteRemote", "rsbuildRemote", "rsbuildSsrRemote"];
+const hosts = ["viteHost", "rsbuildHost", "rsbuildSsrHost"];
+
+const cards = {
+ vite: "Owned by the remote app",
+ rsbuild: "Federated from Rsbuild",
+ rsbuildSsr: "Federated SSR from Rsbuild",
+};
+
+// The remotes each SSR host renders on the server, across both bundlers.
+const serverRendered = {
+ viteHost: ["viteRemote", "rsbuildSsrRemote"],
+ rsbuildSsrHost: ["rsbuildSsrRemote", "viteRemote"],
+};
+
+const remoteCards = { viteRemote: cards.vite, rsbuildSsrRemote: cards.rsbuildSsr };
+
+/**
+ * Starts the six example apps with `script` ("start" for development servers, "preview"
+ * for production builds) and registers the shared federation scenarios against them.
+ */
+export function describeExamples(script) {
+ const processes = {};
+ let browser;
+
+ const start = async (key) => {
+ processes[key] = startApp(apps[key].name, script);
+ // A missing route renders TanStack's not-found page without touching any remote.
+ await waitForResponse(`${apps[key].url}__ready`, processes[key], ({ status }) => status < 500);
+ };
+
+ // Production server entries of the Rsbuild SSR host, read before its dev server starts.
+ const serverBuild = join(root, "apps", "rsbuild-ssr-host", "dist", "server", "index.cjs");
+ let productionServerEntry;
+
+ before(async () => {
+ if (existsSync(serverBuild)) productionServerEntry = readFileSync(serverBuild, "utf8");
+ await Promise.all(remotes.map(start));
+ await Promise.all(hosts.map(start));
+ browser = await chromium.launch();
+ });
+
+ after(async () => {
+ await browser?.close();
+ await Promise.all(Object.values(processes).map(stopApp));
+ });
+
+ test("SSR hosts render Vite and Rsbuild remote markup for concurrent first requests", async () => {
+ for (const [host, remoteKeys] of Object.entries(serverRendered)) {
+ const responses = await Promise.all(
+ Array.from({ length: 8 }, () =>
+ fetch(apps[host].url, { signal: AbortSignal.timeout(60_000) }).then(readResponse),
+ ),
+ );
+ for (const { body, status } of responses) {
+ assert.equal(status, 200, host);
+ for (const remote of remoteKeys) {
+ assert.ok(body.includes(remoteCards[remote]), `${host} initial HTML contains ${remote}`);
+ }
+ assert.equal(
+ body.match(/Rendered on the server/g)?.length,
+ remoteKeys.length,
+ `${host} renders every remote on the server`,
+ );
+ }
+ }
+ });
+
+ test("server-rendered remotes are styled before JavaScript runs", async () => {
+ for (const [host, remoteKeys] of Object.entries(serverRendered)) {
+ const stylesheets = Object.fromEntries(
+ await Promise.all(
+ remoteKeys.map(async (remote) => [
+ remote,
+ await getRemoteStylesheets(
+ new URL("mf-manifest.json", apps[remote].url).href,
+ "./StatusCard",
+ ),
+ ]),
+ ),
+ );
+ // A Vite dev server injects CSS from JavaScript, so its manifest lists none. Builds
+ // must list every remote's stylesheet.
+ const styled = remoteKeys.filter((remote) => stylesheets[remote].length > 0);
+ if (script === "preview") assert.deepEqual(styled, remoteKeys, host);
+
+ const context = await browser.newContext({ javaScriptEnabled: false });
+ try {
+ const page = await context.newPage();
+ // Without JavaScript, streamed Suspense content stays hidden, so warm the host up
+ // first: once its remotes are loaded, it renders them inline.
+ await fetch(apps[host].url, { signal: AbortSignal.timeout(60_000) });
+ await page.goto(apps[host].url);
+ const loaded = await page.evaluate(() => [...document.styleSheets].map(({ href }) => href));
+
+ for (const remote of styled) {
+ for (const href of stylesheets[remote]) {
+ assert.ok(loaded.includes(href), `${host} loads ${href}`);
+ }
+ const background = await page
+ .locator("article", { hasText: remoteCards[remote] })
+ .evaluate((card) => getComputedStyle(card).backgroundColor);
+ assert.notEqual(background, "rgba(0, 0, 0, 0)", `${host} styles ${remote}`);
+ }
+ } finally {
+ await context.close();
+ }
+ }
+ });
+
+ if (script === "start") {
+ test("development servers leave production server builds alone", (t) => {
+ if (productionServerEntry === undefined) {
+ t.skip("needs a production build from before the development servers started");
+ return;
+ }
+ // `rsbuild preview` serves dist/server, so a dev server must not write its bundle there.
+ assert.equal(readFileSync(serverBuild, "utf8"), productionServerEntry);
+ });
+ }
+
+ test("remote manifests reference reachable assets", async () => {
+ for (const key of remotes) {
+ const manifestUrl = new URL("mf-manifest.json", apps[key].url).href;
+ const manifest = await (await fetch(manifestUrl)).json();
+ const assets = manifestAssets(manifest);
+ assert.ok(assets.length > 0, `${key} lists assets`);
+ for (const asset of assets) {
+ const url = new URL(asset, manifestUrl).href;
+ const { status } = await fetch(url);
+ assert.equal(status, 200, url);
+ }
+ }
+ });
+
+ test("Vite host hydrates the Vite and Rsbuild remotes with one React instance", async () => {
+ await withPage(apps.viteHost.url, async (page) => {
+ await page.getByText("Hydrated on the host").first().waitFor({ timeout: 20_000 });
+ for (const card of [cards.vite, cards.rsbuildSsr, cards.rsbuild]) {
+ await assertInteractive(page, card);
+ }
+ await assertHostContext(page, [cards.vite, cards.rsbuildSsr, cards.rsbuild], "Vite host");
+ });
+ });
+
+ test("Rsbuild host loads the Vite and Rsbuild remotes with one React instance", async () => {
+ await withPage(apps.rsbuildHost.url, async (page) => {
+ await assertInteractive(page, cards.vite);
+ await assertInteractive(page, cards.rsbuild);
+ await assertHostContext(page, [cards.vite, cards.rsbuild], "Rsbuild host");
+ });
+ });
+
+ test("Rsbuild SSR host hydrates the server-rendered Rsbuild and Vite remotes", async () => {
+ await withPage(apps.rsbuildSsrHost.url, async (page) => {
+ await page.getByText("Hydrated on the host").first().waitFor({ timeout: 20_000 });
+ await assertInteractive(page, cards.rsbuildSsr);
+ await assertInteractive(page, cards.vite);
+ await assertHostContext(page, [cards.rsbuildSsr, cards.vite], "Rsbuild SSR host");
+ });
+ });
+
+ test("remotes work as standalone TanStack Start apps", async () => {
+ for (const [key, card] of [
+ ["viteRemote", cards.vite],
+ ["rsbuildRemote", cards.rsbuild],
+ ["rsbuildSsrRemote", cards.rsbuildSsr],
+ ]) {
+ await withPage(apps[key].url, async (page) => {
+ await assertInteractive(page, card);
+ await assertHostContext(page, [card], "standalone");
+ });
+ }
+ });
+
+ // The last two scenarios stop remotes, then start them again.
+ test("hosts fall back while remotes are offline and recover when they return", async () => {
+ await Promise.all(remotes.map((key) => stopApp(processes[key])));
+
+ for (const [host, expected] of [
+ [
+ "viteHost",
+ [
+ "Vite remote is unavailable",
+ "Rsbuild SSR remote is unavailable",
+ "Rsbuild remote is unavailable",
+ ],
+ ],
+ ["rsbuildHost", ["Remote unavailable"]],
+ ["rsbuildSsrHost", ["Rsbuild SSR remote is unavailable", "Vite remote is unavailable"]],
+ ]) {
+ const { status } = await fetch(apps[host].url);
+ assert.equal(status, 200, `${host} still serves its page`);
+ await withPage(
+ apps[host].url,
+ async (page) => {
+ for (const fallback of expected) {
+ await page.getByText(fallback).first().waitFor({ timeout: 20_000 });
+ }
+ },
+ // React reports the failed server render as recoverable and renders the
+ // boundary on the client, which is the fallback under test.
+ { allowErrors: true },
+ );
+ }
+
+ await Promise.all(remotes.map(start));
+ await assertServerRendersRemotes("again");
+ await withPage(apps.rsbuildHost.url, async (page) => {
+ await assertInteractive(page, cards.vite);
+ await assertInteractive(page, cards.rsbuild);
+ });
+ await withPage(apps.viteHost.url, async (page) => {
+ await page.getByText("Hydrated on the host").first().waitFor({ timeout: 20_000 });
+ for (const card of [cards.vite, cards.rsbuildSsr, cards.rsbuild]) {
+ await assertInteractive(page, card);
+ }
+ });
+ await withPage(apps.rsbuildSsrHost.url, async (page) => {
+ await assertInteractive(page, cards.rsbuildSsr);
+ await assertInteractive(page, cards.vite);
+ });
+ });
+
+ test("SSR hosts that start during an outage render the remotes once they return", async () => {
+ await Promise.all(remotes.map((key) => stopApp(processes[key])));
+ const ssrHosts = Object.keys(serverRendered);
+ await Promise.all(ssrHosts.map((key) => stopApp(processes[key])));
+ await Promise.all(ssrHosts.map(start));
+
+ // The first requests fail to load every remote.
+ for (const host of ssrHosts) {
+ const { body, status } = await readResponse(
+ await fetch(apps[host].url, { signal: AbortSignal.timeout(60_000) }),
+ );
+ assert.equal(status, 200, `${host} serves its page while remotes are offline`);
+ assert.equal(body.includes("Rendered on the server"), false, host);
+ }
+
+ await Promise.all(remotes.map(start));
+ await assertServerRendersRemotes("after starting during an outage");
+ await withPage(apps.viteHost.url, async (page) => {
+ await page.getByText("Hydrated on the host").first().waitFor({ timeout: 20_000 });
+ for (const card of [cards.vite, cards.rsbuildSsr, cards.rsbuild]) {
+ await assertInteractive(page, card);
+ }
+ await assertHostContext(page, [cards.vite, cards.rsbuildSsr, cards.rsbuild], "Vite host");
+ });
+ await withPage(apps.rsbuildSsrHost.url, async (page) => {
+ await assertInteractive(page, cards.rsbuildSsr);
+ await assertInteractive(page, cards.vite);
+ await assertHostContext(page, [cards.rsbuildSsr, cards.vite], "Rsbuild SSR host");
+ });
+ });
+
+ /** Waits until every SSR host renders all of its remotes on the server. */
+ async function assertServerRendersRemotes(when) {
+ for (const [host, remoteKeys] of Object.entries(serverRendered)) {
+ const { body } = await waitForResponse(apps[host].url, processes[host], ({ body }) =>
+ remoteKeys.every((remote) => body.includes(remoteCards[remote])),
+ );
+ assert.equal(
+ body.match(/Rendered on the server/g)?.length,
+ remoteKeys.length,
+ `${host} renders its remotes on the server ${when}`,
+ );
+ }
+ }
+
+ /** Opens a page, runs `check`, and fails on uncaught errors or console errors and warnings. */
+ async function withPage(url, check, { allowErrors = false } = {}) {
+ const page = await browser.newPage();
+ const errors = [];
+ if (!allowErrors) {
+ page.on("pageerror", (error) => errors.push(error.stack ?? error.message));
+ page.on("console", (message) => {
+ if (["error", "warning"].includes(message.type())) {
+ errors.push(`${message.type()}: ${message.text()}`);
+ }
+ });
+ }
+ try {
+ await page.goto(url);
+ await check(page);
+ assert.deepEqual(errors, [], url);
+ } finally {
+ await page.close();
+ }
+ }
+}
+
+/** Lists every file a manifest points to, relative to the manifest URL. */
+function manifestAssets(manifest) {
+ const { metaData } = manifest;
+ const entries = [metaData.remoteEntry, metaData.ssrRemoteEntry]
+ .filter(Boolean)
+ .map(({ path, name }) => (path ? `${path.replace(/^\/|\/$/g, "")}/${name}` : name));
+ const files = [...manifest.exposes, ...manifest.shared].flatMap(({ assets }) => [
+ ...assets.js.sync,
+ ...assets.js.async,
+ ...assets.css.sync,
+ ...assets.css.async,
+ ]);
+ return [...new Set([...entries, ...files])];
+}
+
+/** Proves each remote card reads the context its host provides through a shared module. */
+async function assertHostContext(page, cardTexts, hostName) {
+ for (const cardText of cardTexts) {
+ const card = page.locator("article", { hasText: cardText });
+ await card.getByText(`Host: ${hostName}`).waitFor({ timeout: 5_000 });
+ }
+}
+
+/** Clicks a remote card's counter and proves the remote's state updates on the host. */
+async function assertInteractive(page, cardText) {
+ const button = page
+ .locator("article", { hasText: cardText })
+ .getByRole("button", { name: /Remote count/ });
+ await button.waitFor({ timeout: 20_000 });
+ const count = async () => Number((await button.textContent()).match(/\d+/)?.[0]);
+
+ // A server-rendered button ignores clicks until React hydrates it.
+ const deadline = Date.now() + 20_000;
+ while ((await count()) === 0) {
+ assert.ok(Date.now() < deadline, `${cardText} never became interactive`);
+ await button.click();
+ await page.waitForTimeout(100);
+ }
+
+ const before = await count();
+ await button.click();
+ await page.waitForFunction(
+ ([text, expected]) =>
+ [...document.querySelectorAll("article")]
+ .find((article) => article.textContent.includes(text))
+ ?.querySelector("button")
+ ?.textContent.includes(String(expected)),
+ [cardText, before + 1],
+ { timeout: 5_000 },
+ );
+}
+
+function startApp(name, script) {
+ const child = spawn("pnpm", ["--filter", name, script], {
+ cwd: root,
+ detached: true,
+ env: { ...process.env, NODE_ENV: script === "start" ? "development" : "production" },
+ stdio: ["ignore", "pipe", "pipe"],
+ });
+ child.output = "";
+
+ for (const stream of [child.stdout, child.stderr]) {
+ stream.on("data", (chunk) => {
+ child.output = `${child.output}${chunk}`.slice(-12_000);
+ });
+ }
+
+ return child;
+}
+
+async function readResponse(response) {
+ return { body: await response.text(), status: response.status };
+}
+
+async function waitForResponse(url, child, predicate = () => true) {
+ const deadline = Date.now() + 60_000;
+ let lastError;
+ let lastResponse;
+
+ while (Date.now() < deadline) {
+ if (child.exitCode !== null || child.signalCode !== null) {
+ assert.fail(`server stopped while waiting for ${url}\n${child.output}`);
+ }
+
+ try {
+ lastResponse = await readResponse(await fetch(url, { signal: AbortSignal.timeout(5_000) }));
+ if (predicate(lastResponse)) return lastResponse;
+ } catch (error) {
+ lastError = error;
+ }
+
+ await new Promise((resolve) => setTimeout(resolve, 250));
+ }
+
+ assert.fail(
+ [
+ `timed out waiting for ${url}`,
+ lastResponse ? `last status: ${lastResponse.status}` : undefined,
+ lastError ? `last error: ${lastError.message}` : undefined,
+ child.output,
+ ]
+ .filter(Boolean)
+ .join("\n"),
+ );
+}
+
+async function stopApp(child) {
+ if (!child || child.exitCode !== null || child.signalCode !== null) return;
+ process.kill(-child.pid, "SIGTERM");
+
+ await Promise.race([
+ new Promise((resolve) => child.once("exit", resolve)),
+ new Promise((resolve) => setTimeout(resolve, 3_000)),
+ ]);
+
+ if (child.exitCode === null && child.signalCode === null) {
+ process.kill(-child.pid, "SIGKILL");
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..3c0eb91
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "files": [],
+ "references": [
+ {
+ "path": "./packages/tanstack/tsconfig.json"
+ },
+ {
+ "path": "./apps/vite-host/tsconfig.json"
+ },
+ {
+ "path": "./apps/vite-remote/tsconfig.json"
+ },
+ {
+ "path": "./apps/rsbuild-host/tsconfig.json"
+ },
+ {
+ "path": "./apps/rsbuild-remote/tsconfig.json"
+ },
+ {
+ "path": "./apps/rsbuild-ssr-host/tsconfig.json"
+ },
+ {
+ "path": "./apps/rsbuild-ssr-remote/tsconfig.json"
+ }
+ ]
+}
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..f26e535
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://turborepo.com/schema.json",
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": [".output/**", "dist/**"]
+ },
+ "dev": {
+ "cache": false,
+ "persistent": true
+ },
+ "start": {
+ "cache": false,
+ "persistent": true
+ },
+ "typecheck": {
+ "dependsOn": ["^build", "^typecheck"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": []
+ },
+ "preview": {
+ "cache": false,
+ "persistent": true
+ }
+ }
+}