@c0va23/react-router-dev 7.9.6 → 7.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,129 @@
1
1
  # `@react-router/dev`
2
2
 
3
+ ## 7.13.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Bump @remix-run/node-fetch-server dep ([#14704](https://github.com/remix-run/react-router/pull/14704))
8
+ - Updated dependencies:
9
+ - `react-router@7.13.0`
10
+ - `@react-router/node@7.13.0`
11
+ - `@react-router/serve@7.13.0`
12
+
13
+ ## 7.12.0
14
+
15
+ ### Minor Changes
16
+
17
+ - Add additional layer of CSRF protection by rejecting submissions to UI routes from external origins. If you need to permit access to specific external origins, you can specify them in the `react-router.config.ts` config `allowedActionOrigins` field. ([#14708](https://github.com/remix-run/react-router/pull/14708))
18
+
19
+ ### Patch Changes
20
+
21
+ - Fix `Maximum call stack size exceeded` errors when HMR is triggered against code with cyclic imports ([#14522](https://github.com/remix-run/react-router/pull/14522))
22
+
23
+ - fix(vite): Skip SSR middleware in preview server for SPA mode ([#14673](https://github.com/remix-run/react-router/pull/14673))
24
+
25
+ - \[UNSTABLE] Add a new `future.unstable_trailingSlashAwareDataRequests` flag to provide consistent behavior of `request.pathname` inside `middleware`, `loader`, and `action` functions on document and data requests when a trailing slash is present in the browser URL. ([#14644](https://github.com/remix-run/react-router/pull/14644))
26
+
27
+ Currently, your HTTP and `request` pathnames would be as follows for `/a/b/c` and `/a/b/c/`
28
+
29
+ | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
30
+ | ------------ | ----------------- | ------------------------ |
31
+ | **Document** | `/a/b/c` | `/a/b/c` ✅ |
32
+ | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
33
+
34
+ | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
35
+ | ------------- | ----------------- | ------------------------ |
36
+ | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
37
+ | **Data** | `/a/b/c.data` | `/a/b/c` ⚠️ |
38
+
39
+ With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests:
40
+
41
+ | URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
42
+ | ------------ | ----------------- | ------------------------ |
43
+ | **Document** | `/a/b/c` | `/a/b/c` ✅ |
44
+ | **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
45
+
46
+ | URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
47
+ | ------------- | ------------------ | ------------------------ |
48
+ | **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
49
+ | **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
50
+
51
+ This a bug fix but we are putting it behind an opt-in flag because it has the potential to be a "breaking bug fix" if you are relying on the URL format for any other application or caching logic.
52
+
53
+ Enabling this flag also changes the format of client side `.data` requests from `/_root.data` to `/_.data` when navigating to `/` to align with the new format. This does not impact the `request` pathname which is still `/` in all cases.
54
+
55
+ - Updated dependencies:
56
+ - `react-router@7.12.0`
57
+ - `@react-router/node@7.12.0`
58
+ - `@react-router/serve@7.12.0`
59
+
60
+ ## 7.11.0
61
+
62
+ ### Minor Changes
63
+
64
+ - feat: add `vite preview` support ([#14507](https://github.com/remix-run/react-router/pull/14507))
65
+
66
+ ### Patch Changes
67
+
68
+ - rsc framework mode manual chunking for react and react-router deps ([#14655](https://github.com/remix-run/react-router/pull/14655))
69
+ - add support for throwing redirect Response's at RSC render time ([#14596](https://github.com/remix-run/react-router/pull/14596))
70
+ - support custom entrypoints for RSC framework mode ([#14643](https://github.com/remix-run/react-router/pull/14643))
71
+ - `routeRSCServerRequest` replace `fetchServer` with `serverResponse` ([#14597](https://github.com/remix-run/react-router/pull/14597))
72
+ - rsc framewlrk mode - optimize react-server-dom-webpack if in project package.json ([#14656](https://github.com/remix-run/react-router/pull/14656))
73
+ - Updated dependencies:
74
+ - `react-router@7.11.0`
75
+ - `@react-router/serve@7.11.0`
76
+ - `@react-router/node@7.11.0`
77
+
78
+ ## 7.10.1
79
+
80
+ ### Patch Changes
81
+
82
+ - Import ESM package `pkg-types` with a dynamic `import()` to fix issues on Node 20.18 ([#14624](https://github.com/remix-run/react-router/pull/14624))
83
+ - Update `valibot` dependency to `^1.2.0` to address [GHSA-vqpr-j7v3-hqw9](https://github.com/advisories/GHSA-vqpr-j7v3-hqw9) ([#14608](https://github.com/remix-run/react-router/pull/14608))
84
+ - Updated dependencies:
85
+ - `react-router@7.10.1`
86
+ - `@react-router/node@7.10.1`
87
+ - `@react-router/serve@7.10.1`
88
+
89
+ ## 7.10.0
90
+
91
+ ### Minor Changes
92
+
93
+ - Stabilize `future.v8_splitRouteModules`, replacing `future.unstable_splitRouteModules` ([#14595](https://github.com/remix-run/react-router/pull/14595))
94
+ - ⚠️ This is a breaking change if you have begun using `future.unstable_splitRouteModules`. Please update your `react-router.config.ts`.
95
+
96
+ - Stabilize `future.v8_viteEnvironmentApi`, replacing `future.unstable_viteEnvironmentApi` ([#14595](https://github.com/remix-run/react-router/pull/14595))
97
+ - ⚠️ This is a breaking change if you have begun using `future.unstable_viteEnvironmentApi`. Please update your `react-router.config.ts`.
98
+
99
+ ### Patch Changes
100
+
101
+ - Load environment variables before evaluating `routes.ts` ([#14446](https://github.com/remix-run/react-router/pull/14446))
102
+
103
+ For example, you can now compute your routes based on [`VITE_`-prefixed environment variables](https://vite.dev/guide/env-and-mode#env-variables):
104
+
105
+ ```txt
106
+ # .env
107
+ VITE_ENV_ROUTE=my-route
108
+ ```
109
+
110
+ ```ts
111
+ // app/routes.ts
112
+ import { type RouteConfig, route } from "@react-router/dev/routes";
113
+
114
+ const routes: RouteConfig = [];
115
+ if (import.meta.env.VITE_ENV_ROUTE === "my-route") {
116
+ routes.push(route("my-route", "routes/my-route.tsx"));
117
+ }
118
+
119
+ export default routes;
120
+ ```
121
+
122
+ - Updated dependencies:
123
+ - `react-router@7.10.0`
124
+ - `@react-router/node@7.10.0`
125
+ - `@react-router/serve@7.10.0`
126
+
3
127
  ## 7.9.6
4
128
 
5
129
  ### Patch Changes
@@ -180,6 +304,7 @@
180
304
  - Stabilize middleware and context APIs. ([#14215](https://github.com/remix-run/react-router/pull/14215))
181
305
 
182
306
  We have removed the `unstable_` prefix from the following APIs and they are now considered stable and ready for production use:
307
+
183
308
  - [`RouterContextProvider`](https://reactrouter.com/api/utils/RouterContextProvider)
184
309
  - [`createContext`](https://reactrouter.com/api/utils/createContext)
185
310
  - `createBrowserRouter` [`getContext`](https://reactrouter.com/api/data-routers/createBrowserRouter#optsgetcontext) option
@@ -922,6 +1047,7 @@
922
1047
  ```
923
1048
 
924
1049
  This initial implementation targets type inference for:
1050
+
925
1051
  - `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
926
1052
  - `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
927
1053
  - `ActionData` : Action data from `action` and/or `clientAction` within your route module
@@ -936,6 +1062,7 @@
936
1062
  ```
937
1063
 
938
1064
  Check out our docs for more:
1065
+
939
1066
  - [_Explanations > Type Safety_](https://reactrouter.com/dev/guides/explanation/type-safety)
940
1067
  - [_How-To > Setting up type safety_](https://reactrouter.com/dev/guides/how-to/setting-up-type-safety)
941
1068
 
@@ -1135,6 +1262,7 @@
1135
1262
  - Vite: Provide `Unstable_ServerBundlesFunction` and `Unstable_VitePluginConfig` types ([#8654](https://github.com/remix-run/remix/pull/8654))
1136
1263
 
1137
1264
  - Vite: add `--sourcemapClient` and `--sourcemapServer` flags to `remix vite:build` ([#8613](https://github.com/remix-run/remix/pull/8613))
1265
+
1138
1266
  - `--sourcemapClient`
1139
1267
 
1140
1268
  - `--sourcemapClient=inline`
@@ -1471,6 +1599,7 @@
1471
1599
  - Add support for `clientLoader`/`clientAction`/`HydrateFallback` route exports ([RFC](https://github.com/remix-run/remix/discussions/7634)) ([#8173](https://github.com/remix-run/remix/pull/8173))
1472
1600
 
1473
1601
  Remix now supports loaders/actions that run on the client (in addition to, or instead of the loader/action that runs on the server). While we still recommend server loaders/actions for the majority of your data needs in a Remix app - these provide some levers you can pull for more advanced use-cases such as:
1602
+
1474
1603
  - Leveraging a data source local to the browser (i.e., `localStorage`)
1475
1604
  - Managing a client-side cache of server data (like `IndexedDB`)
1476
1605
  - Bypassing the Remix server in a BFF setup and hitting your API directly from the browser
@@ -1874,6 +2003,7 @@
1874
2003
  - Output esbuild metafiles for bundle analysis ([#6772](https://github.com/remix-run/remix/pull/6772))
1875
2004
 
1876
2005
  Written to server build directory (`build/` by default):
2006
+
1877
2007
  - `metafile.css.json`
1878
2008
  - `metafile.js.json` (browser JS)
1879
2009
  - `metafile.server.json` (server JS)
@@ -1971,6 +2101,7 @@
1971
2101
  - built-in tls support ([#6483](https://github.com/remix-run/remix/pull/6483))
1972
2102
 
1973
2103
  New options:
2104
+
1974
2105
  - `--tls-key` / `tlsKey`: TLS key
1975
2106
  - `--tls-cert` / `tlsCert`: TLS Certificate
1976
2107
 
@@ -2241,6 +2372,7 @@
2241
2372
  ```
2242
2373
 
2243
2374
  The dev server will:
2375
+
2244
2376
  - force `NODE_ENV=development` and warn you if it was previously set to something else
2245
2377
  - rebuild your app whenever your Remix app code changes
2246
2378
  - restart your app server whenever rebuilds succeed
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v7.9.6
3
+ * @react-router/dev v7.13.0
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -492,13 +492,26 @@ async function resolveConfig({
492
492
  );
493
493
  }
494
494
  }
495
+ let futureConfig = userAndPresetConfigs.future;
496
+ if (futureConfig?.unstable_splitRouteModules !== void 0) {
497
+ return err(
498
+ 'The "future.unstable_splitRouteModules" flag has been stabilized as "future.v8_splitRouteModules"'
499
+ );
500
+ }
501
+ if (futureConfig?.unstable_viteEnvironmentApi !== void 0) {
502
+ return err(
503
+ 'The "future.unstable_viteEnvironmentApi" flag has been stabilized as "future.v8_viteEnvironmentApi"'
504
+ );
505
+ }
495
506
  let future = {
496
- v8_middleware: userAndPresetConfigs.future?.v8_middleware ?? false,
497
507
  unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false,
498
- unstable_splitRouteModules: userAndPresetConfigs.future?.unstable_splitRouteModules ?? false,
499
508
  unstable_subResourceIntegrity: userAndPresetConfigs.future?.unstable_subResourceIntegrity ?? false,
500
- unstable_viteEnvironmentApi: userAndPresetConfigs.future?.unstable_viteEnvironmentApi ?? false
509
+ unstable_trailingSlashAwareDataRequests: userAndPresetConfigs.future?.unstable_trailingSlashAwareDataRequests ?? false,
510
+ v8_middleware: userAndPresetConfigs.future?.v8_middleware ?? false,
511
+ v8_splitRouteModules: userAndPresetConfigs.future?.v8_splitRouteModules ?? false,
512
+ v8_viteEnvironmentApi: userAndPresetConfigs.future?.v8_viteEnvironmentApi ?? false
501
513
  };
514
+ let allowedActionOrigins = userAndPresetConfigs.allowedActionOrigins ?? false;
502
515
  let reactRouterConfig = deepFreeze({
503
516
  appDirectory,
504
517
  basename: basename3,
@@ -512,6 +525,7 @@ async function resolveConfig({
512
525
  serverBundles,
513
526
  serverModuleFormat,
514
527
  ssr,
528
+ allowedActionOrigins,
515
529
  unstable_routeConfig: routeConfig
516
530
  });
517
531
  for (let preset of reactRouterUserConfig.presets ?? []) {
@@ -718,13 +732,12 @@ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /
718
732
  }
719
733
  return false;
720
734
  }
721
- var import_node_fs, import_node_child_process, import_package_json, import_pathe3, import_chokidar, import_picocolors, import_pick2, import_omit, import_cloneDeep, import_isEqual, excludedConfigPresetKeys, mergeReactRouterConfig, deepFreeze, entryExts;
735
+ var import_node_fs, import_node_child_process, import_pathe3, import_chokidar, import_picocolors, import_pick2, import_omit, import_cloneDeep, import_isEqual, excludedConfigPresetKeys, mergeReactRouterConfig, deepFreeze, entryExts;
722
736
  var init_config = __esm({
723
737
  "config/config.ts"() {
724
738
  "use strict";
725
739
  import_node_fs = __toESM(require("fs"));
726
740
  import_node_child_process = require("child_process");
727
- import_package_json = __toESM(require("@npmcli/package-json"));
728
741
  init_vite_node();
729
742
  import_pathe3 = __toESM(require("pathe"));
730
743
  import_chokidar = __toESM(require("chokidar"));
@@ -946,6 +959,7 @@ function generateServerBuild(ctx) {
946
959
  export const routeDiscovery: ServerBuild["routeDiscovery"];
947
960
  export const routes: ServerBuild["routes"];
948
961
  export const ssr: ServerBuild["ssr"];
962
+ export const allowedActionOrigins: ServerBuild["allowedActionOrigins"];
949
963
  export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
950
964
  }
951
965
  `;
@@ -1363,11 +1377,9 @@ var init_has_rsc_plugin = __esm({
1363
1377
  });
1364
1378
 
1365
1379
  // vite/node-adapter.ts
1366
- var import_node_fetch_server;
1367
1380
  var init_node_adapter = __esm({
1368
1381
  "vite/node-adapter.ts"() {
1369
1382
  "use strict";
1370
- import_node_fetch_server = require("@remix-run/node-fetch-server");
1371
1383
  init_invariant();
1372
1384
  }
1373
1385
  });
@@ -1673,8 +1685,8 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
1673
1685
  return mergeEnvironmentOptions(getBaseOptions({ viteUserConfig }), {
1674
1686
  resolve: {
1675
1687
  external: (
1676
- // If `unstable_viteEnvironmentApi` is `true`, `resolve.external` is set in the `configEnvironment` hook
1677
- ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? void 0 : ssrExternals
1688
+ // If `v8_viteEnvironmentApi` is `true`, `resolve.external` is set in the `configEnvironment` hook
1689
+ ctx.reactRouterConfig.future.v8_viteEnvironmentApi ? void 0 : ssrExternals
1678
1690
  ),
1679
1691
  conditions: [...baseConditions, ...maybeDefaultServerConditions],
1680
1692
  externalConditions: [...baseConditions, ...defaultExternalConditions]
@@ -1689,7 +1701,7 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
1689
1701
  copyPublicDir: false,
1690
1702
  // The client only uses assets in the public directory
1691
1703
  rollupOptions: {
1692
- input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id,
1704
+ input: (ctx.reactRouterConfig.future.v8_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id,
1693
1705
  output: {
1694
1706
  entryFileNames: serverBuildFile,
1695
1707
  format: serverModuleFormat
@@ -1714,14 +1726,14 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
1714
1726
  let code = (0, import_node_fs3.readFileSync)(routeFilePath, "utf-8");
1715
1727
  return [
1716
1728
  `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
1717
- ...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
1729
+ ...ctx.reactRouterConfig.future.v8_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
1718
1730
  (exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
1719
1731
  ) : []
1720
1732
  ].filter(isNonNullable);
1721
1733
  }
1722
1734
  )
1723
1735
  ],
1724
- output: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.rollupOptions?.output : viteUserConfig?.build?.rollupOptions?.output) ?? {
1736
+ output: (ctx.reactRouterConfig.future.v8_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.rollupOptions?.output : viteUserConfig?.build?.rollupOptions?.output) ?? {
1725
1737
  entryFileNames: ({ moduleIds }) => {
1726
1738
  let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
1727
1739
  let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId)?.replace(
@@ -1729,7 +1741,7 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
1729
1741
  ""
1730
1742
  ) : null;
1731
1743
  let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
1732
- let assetsDir = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : null) ?? viteUserConfig?.build?.assetsDir ?? "assets";
1744
+ let assetsDir = (ctx.reactRouterConfig.future.v8_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : null) ?? viteUserConfig?.build?.assetsDir ?? "assets";
1733
1745
  return path7.posix.join(
1734
1746
  assetsDir,
1735
1747
  `[name]${routeChunkSuffix}-[hash].js`
@@ -1780,7 +1792,7 @@ function resolveEnvironmentsOptions(environmentResolvers, resolverOptions) {
1780
1792
  function isNonNullable(x) {
1781
1793
  return x != null;
1782
1794
  }
1783
- var import_node_crypto, import_node_fs3, import_promises2, path7, url, babel2, import_node_fetch_server2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors5, import_kebabCase, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_ROUTE_EXPORTS, BUILD_CLIENT_ROUTE_QUERY_STRING, SSR_BUNDLE_PREFIX, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
1795
+ var import_node_crypto, import_node_fs3, import_promises2, path7, url, babel2, import_react_router2, import_es_module_lexer, import_pick3, import_jsesc, import_picocolors5, import_kebabCase, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_ROUTE_EXPORTS, BUILD_CLIENT_ROUTE_QUERY_STRING, SSR_BUNDLE_PREFIX, virtualHmrRuntime, virtualInjectHmrRuntime, virtual, getServerBuildDirectory, getClientBuildDirectory, defaultEntriesDir, defaultEntries, REACT_REFRESH_HEADER;
1784
1796
  var init_plugin = __esm({
1785
1797
  "vite/plugin.ts"() {
1786
1798
  "use strict";
@@ -1790,7 +1802,6 @@ var init_plugin = __esm({
1790
1802
  path7 = __toESM(require("path"));
1791
1803
  url = __toESM(require("url"));
1792
1804
  babel2 = __toESM(require("@babel/core"));
1793
- import_node_fetch_server2 = require("@remix-run/node-fetch-server");
1794
1805
  import_react_router2 = require("react-router");
1795
1806
  import_es_module_lexer = require("es-module-lexer");
1796
1807
  import_pick3 = __toESM(require("lodash/pick"));
@@ -1902,12 +1913,12 @@ async function build(root, viteBuildOptions) {
1902
1913
  }
1903
1914
  let config = configResult.value;
1904
1915
  let viteMajor = parseInt(vite2.version.split(".")[0], 10);
1905
- if (config.future.unstable_viteEnvironmentApi && viteMajor === 5) {
1916
+ if (config.future.v8_viteEnvironmentApi && viteMajor === 5) {
1906
1917
  throw new Error(
1907
- "The future.unstable_viteEnvironmentApi option is not supported in Vite 5"
1918
+ "The future.v8_viteEnvironmentApi option is not supported in Vite 5"
1908
1919
  );
1909
1920
  }
1910
- const useViteEnvironmentApi = config.future.unstable_viteEnvironmentApi || await hasReactRouterRscPlugin({ root, viteBuildOptions });
1921
+ const useViteEnvironmentApi = config.future.v8_viteEnvironmentApi || await hasReactRouterRscPlugin({ root, viteBuildOptions });
1911
1922
  return await (useViteEnvironmentApi ? viteAppBuild(root, viteBuildOptions) : viteBuild(root, viteBuildOptions));
1912
1923
  }
1913
1924
  async function viteAppBuild(root, {
@@ -2142,7 +2153,6 @@ var import_picocolors9 = __toESM(require("picocolors"));
2142
2153
  var import_node_fs4 = require("fs");
2143
2154
  var import_promises3 = require("fs/promises");
2144
2155
  var path8 = __toESM(require("path"));
2145
- var import_package_json2 = __toESM(require("@npmcli/package-json"));
2146
2156
  var import_exit_hook = __toESM(require("exit-hook"));
2147
2157
  var import_picocolors8 = __toESM(require("picocolors"));
2148
2158
  var import_react_router3 = require("react-router");
@@ -2308,8 +2318,9 @@ async function generateEntry(entry, rootDirectory, flags = {}) {
2308
2318
  );
2309
2319
  return;
2310
2320
  }
2311
- let pkgJson = await import_package_json2.default.load(rootDirectory);
2312
- let deps = pkgJson.content.dependencies ?? {};
2321
+ let { readPackageJSON } = await import("pkg-types");
2322
+ let pkgJson = await readPackageJSON(rootDirectory);
2323
+ let deps = pkgJson.dependencies ?? {};
2313
2324
  if (!deps["@react-router/node"]) {
2314
2325
  console.error(import_picocolors8.default.red(`No default server entry detected.`));
2315
2326
  return;
@@ -6,22 +6,36 @@ import {
6
6
  loadServerAction,
7
7
  renderToReadableStream,
8
8
  } from "@vitejs/plugin-rsc/rsc";
9
- import { unstable_matchRSCServerRequest as matchRSCServerRequest } from "react-router";
9
+ import {
10
+ RouterContextProvider,
11
+ unstable_matchRSCServerRequest as matchRSCServerRequest,
12
+ } from "react-router";
10
13
 
14
+ // Import the routes generated by routes.ts
11
15
  import routes from "virtual:react-router/unstable_rsc/routes";
12
16
  import basename from "virtual:react-router/unstable_rsc/basename";
13
17
  import unstable_reactRouterServeConfig from "virtual:react-router/unstable_rsc/react-router-serve-config";
14
18
 
15
- export async function fetchServer(request: Request) {
16
- return await matchRSCServerRequest({
19
+ export { unstable_reactRouterServeConfig };
20
+
21
+ export function fetchServer(
22
+ request: Request,
23
+ requestContext?: RouterContextProvider,
24
+ ) {
25
+ return matchRSCServerRequest({
26
+ basename,
27
+ // Provide the React Server touchpoints.
17
28
  createTemporaryReferenceSet,
18
29
  decodeAction,
19
30
  decodeFormState,
20
31
  decodeReply,
21
32
  loadServerAction,
33
+ // The incoming request.
22
34
  request,
35
+ requestContext,
36
+ // The app routes.
23
37
  routes,
24
- basename,
38
+ // Encode the match with the React Server implementation.
25
39
  generateResponse(match, options) {
26
40
  return new Response(renderToReadableStream(match.payload, options), {
27
41
  status: match.statusCode,
@@ -31,14 +45,22 @@ export async function fetchServer(request: Request) {
31
45
  });
32
46
  }
33
47
 
34
- export { unstable_reactRouterServeConfig };
48
+ export default {
49
+ async fetch(request: Request, requestContext?: RouterContextProvider) {
50
+ if (requestContext && !(requestContext instanceof RouterContextProvider)) {
51
+ requestContext = undefined;
52
+ }
35
53
 
36
- export default async function handler(request: Request) {
37
- const ssr = await import.meta.viteRsc.loadModule<
38
- typeof import("./entry.ssr")
39
- >("ssr", "index");
40
- return ssr.default(request, fetchServer);
41
- }
54
+ const ssr = await import.meta.viteRsc.loadModule<
55
+ typeof import("./entry.ssr.tsx")
56
+ >("ssr", "index");
57
+
58
+ return await ssr.generateHTML(
59
+ request,
60
+ await fetchServer(request, requestContext),
61
+ );
62
+ },
63
+ };
42
64
 
43
65
  if (import.meta.hot) {
44
66
  import.meta.hot.accept();
@@ -1,31 +1,38 @@
1
1
  import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr";
2
- // @ts-expect-error
3
- import * as ReactDomServer from "react-dom/server.edge";
2
+ // @ts-expect-error - no types for this, can import from root once on latest 19
3
+ import { renderToReadableStream } from "react-dom/server.edge";
4
4
  import {
5
- unstable_RSCStaticRouter as RSCStaticRouter,
6
5
  unstable_routeRSCServerRequest as routeRSCServerRequest,
6
+ unstable_RSCStaticRouter as RSCStaticRouter,
7
7
  } from "react-router";
8
8
 
9
- export default async function handler(
9
+ export async function generateHTML(
10
10
  request: Request,
11
- fetchServer: (request: Request) => Promise<Response>,
12
- ) {
13
- const bootstrapScriptContent =
14
- await import.meta.viteRsc.loadBootstrapScriptContent("index");
15
-
16
- return routeRSCServerRequest({
11
+ serverResponse: Response,
12
+ ): Promise<Response> {
13
+ return await routeRSCServerRequest({
14
+ // The incoming request.
17
15
  request,
18
- fetchServer,
16
+ // The response from the RSC server.
17
+ serverResponse,
18
+ // Provide the React Server touchpoints.
19
19
  createFromReadableStream,
20
- async renderHTML(getPayload) {
21
- const payload = getPayload();
20
+ // Render the router to HTML.
21
+ async renderHTML(getPayload, options) {
22
+ const payload = await getPayload();
23
+ const formState =
24
+ payload.type === "render" ? await payload.formState : undefined;
25
+
26
+ const bootstrapScriptContent =
27
+ await import.meta.viteRsc.loadBootstrapScriptContent("index");
22
28
 
23
- return ReactDomServer.renderToReadableStream(
29
+ return await renderToReadableStream(
24
30
  <RSCStaticRouter getPayload={getPayload} />,
25
31
  {
32
+ ...options,
26
33
  bootstrapScriptContent,
34
+ formState,
27
35
  signal: request.signal,
28
- formState: await payload.formState,
29
36
  },
30
37
  );
31
38
  },
package/dist/config.d.ts CHANGED
@@ -37,20 +37,21 @@ type ServerBundlesBuildManifest = BaseBuildManifest & {
37
37
  };
38
38
  type ServerModuleFormat = "esm" | "cjs";
39
39
  interface FutureConfig {
40
+ unstable_optimizeDeps: boolean;
41
+ unstable_subResourceIntegrity: boolean;
42
+ unstable_trailingSlashAwareDataRequests: boolean;
40
43
  /**
41
44
  * Enable route middleware
42
45
  */
43
46
  v8_middleware: boolean;
44
- unstable_optimizeDeps: boolean;
45
47
  /**
46
48
  * Automatically split route modules into multiple chunks when possible.
47
49
  */
48
- unstable_splitRouteModules: boolean | "enforce";
49
- unstable_subResourceIntegrity: boolean;
50
+ v8_splitRouteModules: boolean | "enforce";
50
51
  /**
51
- * Use Vite Environment API (experimental)
52
+ * Use Vite Environment API
52
53
  */
53
- unstable_viteEnvironmentApi: boolean;
54
+ v8_viteEnvironmentApi: boolean;
54
55
  }
55
56
  type BuildManifest = DefaultBuildManifest | ServerBundlesBuildManifest;
56
57
  type BuildEndHook = (args: {
@@ -147,6 +148,47 @@ type ReactRouterConfig = {
147
148
  * SPA without server-rendering. Default's to `true`.
148
149
  */
149
150
  ssr?: boolean;
151
+ /**
152
+ * An array of allowed origin hosts for action submissions to UI routes (does not apply
153
+ * to resource routes). Supports micromatch glob patterns (`*` to match one segment,
154
+ * `**` to match multiple).
155
+ *
156
+ * ```tsx
157
+ * export default {
158
+ * allowedActionOrigins: [
159
+ * "example.com",
160
+ * "*.example.com", // sub.example.com
161
+ * "**.example.com", // sub.domain.example.com
162
+ * ],
163
+ * } satisfies Config;
164
+ * ```
165
+ *
166
+ * If you need to set this value at runtime, you can do in by setting the value
167
+ * on the server build in your custom server. For example, when using `express`:
168
+ *
169
+ * ```ts
170
+ * import express from "express";
171
+ * import { createRequestHandler } from "@react-router/express";
172
+ * import type { ServerBuild } from "react-router";
173
+ *
174
+ * export const app = express();
175
+ *
176
+ * async function getBuild() {
177
+ * let build: ServerBuild = await import(
178
+ * "virtual:react-router/server-build"
179
+ * );
180
+ * return {
181
+ * ...build,
182
+ * allowedActionOrigins:
183
+ * process.env.NODE_ENV === "development"
184
+ * ? undefined
185
+ * : ["staging.example.com", "www.example.com"],
186
+ * };
187
+ * }
188
+ *
189
+ * app.use(createRequestHandler({ build: getBuild }));
190
+ */
191
+ allowedActionOrigins?: string[];
150
192
  };
151
193
  type ResolvedReactRouterConfig = Readonly<{
152
194
  /**
@@ -212,6 +254,11 @@ type ResolvedReactRouterConfig = Readonly<{
212
254
  * SPA without server-rendering. Default's to `true`.
213
255
  */
214
256
  ssr: boolean;
257
+ /**
258
+ * The allowed origins for actions / mutations. Does not apply to routes
259
+ * without a component. micromatch glob patterns are supported.
260
+ */
261
+ allowedActionOrigins: string[] | false;
215
262
  /**
216
263
  * The resolved array of route config entries exported from `routes.ts`
217
264
  */
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.9.6
2
+ * @react-router/dev v7.13.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.9.6
2
+ * @react-router/dev v7.13.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *