react-router 8.2.0 → 8.3.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.
Files changed (169) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/development/dom-export.js +1 -1
  3. package/dist/development/index-react-server-client.js +1 -1
  4. package/dist/development/index-react-server.d.ts +106 -17
  5. package/dist/development/index-react-server.js +168 -42
  6. package/dist/development/index.js +1 -1
  7. package/dist/development/lib/actions.js +1 -1
  8. package/dist/development/lib/components.js +1 -1
  9. package/dist/development/lib/context.js +1 -1
  10. package/dist/development/lib/dom/dom.d.ts +24 -24
  11. package/dist/development/lib/dom/dom.js +25 -25
  12. package/dist/development/lib/dom/lib.d.ts +2 -1
  13. package/dist/development/lib/dom/lib.js +5 -4
  14. package/dist/development/lib/dom/server.js +1 -1
  15. package/dist/development/lib/dom/ssr/components.js +1 -1
  16. package/dist/development/lib/dom/ssr/data.js +1 -1
  17. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  18. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  19. package/dist/development/lib/dom/ssr/fog-of-war.js +26 -21
  20. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  21. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  22. package/dist/development/lib/dom/ssr/links.js +1 -1
  23. package/dist/development/lib/dom/ssr/markup.js +1 -1
  24. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  25. package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  26. package/dist/development/lib/dom/ssr/routes-test-stub.js +14 -1
  27. package/dist/development/lib/dom/ssr/routes.js +1 -1
  28. package/dist/development/lib/dom/ssr/server.js +1 -1
  29. package/dist/development/lib/dom/ssr/single-fetch.js +1 -1
  30. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  31. package/dist/development/lib/dom-export/hydrated-router.js +1 -1
  32. package/dist/development/lib/errors.js +1 -1
  33. package/dist/development/lib/hooks.js +1 -1
  34. package/dist/development/lib/href.d.ts +24 -8
  35. package/dist/development/lib/href.js +28 -11
  36. package/dist/development/lib/router/history.d.ts +6 -0
  37. package/dist/development/lib/router/history.js +7 -1
  38. package/dist/development/lib/router/instrumentation.js +1 -1
  39. package/dist/development/lib/router/router.js +1 -1
  40. package/dist/development/lib/router/url.js +1 -1
  41. package/dist/development/lib/router/utils.d.ts +12 -0
  42. package/dist/development/lib/router/utils.js +57 -3
  43. package/dist/development/lib/rsc/browser.js +34 -24
  44. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  45. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  46. package/dist/development/lib/rsc/html-stream/server.js +29 -10
  47. package/dist/development/lib/rsc/route-modules.js +1 -1
  48. package/dist/development/lib/rsc/server.rsc.d.ts +5 -1
  49. package/dist/development/lib/rsc/server.ssr.d.ts +29 -6
  50. package/dist/development/lib/rsc/server.ssr.js +27 -12
  51. package/dist/development/lib/server-runtime/cookies.d.ts +28 -2
  52. package/dist/development/lib/server-runtime/cookies.js +17 -3
  53. package/dist/development/lib/server-runtime/crypto.js +1 -1
  54. package/dist/development/lib/server-runtime/data.js +1 -1
  55. package/dist/development/lib/server-runtime/dev.js +1 -1
  56. package/dist/development/lib/server-runtime/entry.js +1 -1
  57. package/dist/development/lib/server-runtime/errors.js +1 -1
  58. package/dist/development/lib/server-runtime/headers.js +1 -1
  59. package/dist/development/lib/server-runtime/invariant.js +1 -1
  60. package/dist/development/lib/server-runtime/mode.js +1 -1
  61. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  62. package/dist/development/lib/server-runtime/routes.js +1 -1
  63. package/dist/development/lib/server-runtime/server.d.ts +12 -0
  64. package/dist/development/lib/server-runtime/server.js +13 -1
  65. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  66. package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  67. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +9 -1
  68. package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  69. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +12 -6
  70. package/dist/development/lib/server-runtime/sessions.d.ts +31 -2
  71. package/dist/development/lib/server-runtime/sessions.js +20 -3
  72. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  73. package/dist/development/lib/server-runtime/urls.js +1 -1
  74. package/dist/development/lib/server-runtime/warnings.js +1 -1
  75. package/dist/development/lib/types/internal.js +1 -1
  76. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  77. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  78. package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
  79. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  80. package/dist/production/dom-export.js +1 -1
  81. package/dist/production/index-react-server-client.js +1 -1
  82. package/dist/production/index-react-server.d.ts +106 -17
  83. package/dist/production/index-react-server.js +168 -42
  84. package/dist/production/index.js +1 -1
  85. package/dist/production/lib/actions.js +1 -1
  86. package/dist/production/lib/components.js +1 -1
  87. package/dist/production/lib/context.js +1 -1
  88. package/dist/production/lib/dom/dom.d.ts +24 -24
  89. package/dist/production/lib/dom/dom.js +25 -25
  90. package/dist/production/lib/dom/lib.d.ts +2 -1
  91. package/dist/production/lib/dom/lib.js +5 -4
  92. package/dist/production/lib/dom/server.js +1 -1
  93. package/dist/production/lib/dom/ssr/components.js +1 -1
  94. package/dist/production/lib/dom/ssr/data.js +1 -1
  95. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  96. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  97. package/dist/production/lib/dom/ssr/fog-of-war.js +26 -21
  98. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  99. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  100. package/dist/production/lib/dom/ssr/links.js +1 -1
  101. package/dist/production/lib/dom/ssr/markup.js +1 -1
  102. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  103. package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +13 -0
  104. package/dist/production/lib/dom/ssr/routes-test-stub.js +14 -1
  105. package/dist/production/lib/dom/ssr/routes.js +1 -1
  106. package/dist/production/lib/dom/ssr/server.js +1 -1
  107. package/dist/production/lib/dom/ssr/single-fetch.js +1 -1
  108. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  109. package/dist/production/lib/dom-export/hydrated-router.js +1 -1
  110. package/dist/production/lib/errors.js +1 -1
  111. package/dist/production/lib/hooks.js +1 -1
  112. package/dist/production/lib/href.d.ts +24 -8
  113. package/dist/production/lib/href.js +28 -11
  114. package/dist/production/lib/router/history.d.ts +6 -0
  115. package/dist/production/lib/router/history.js +7 -1
  116. package/dist/production/lib/router/instrumentation.js +1 -1
  117. package/dist/production/lib/router/router.js +1 -1
  118. package/dist/production/lib/router/url.js +1 -1
  119. package/dist/production/lib/router/utils.d.ts +12 -0
  120. package/dist/production/lib/router/utils.js +57 -3
  121. package/dist/production/lib/rsc/browser.js +34 -24
  122. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  123. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  124. package/dist/production/lib/rsc/html-stream/server.js +29 -10
  125. package/dist/production/lib/rsc/route-modules.js +1 -1
  126. package/dist/production/lib/rsc/server.rsc.d.ts +5 -1
  127. package/dist/production/lib/rsc/server.ssr.d.ts +29 -6
  128. package/dist/production/lib/rsc/server.ssr.js +27 -12
  129. package/dist/production/lib/server-runtime/cookies.d.ts +28 -2
  130. package/dist/production/lib/server-runtime/cookies.js +17 -3
  131. package/dist/production/lib/server-runtime/crypto.js +1 -1
  132. package/dist/production/lib/server-runtime/data.js +1 -1
  133. package/dist/production/lib/server-runtime/dev.js +1 -1
  134. package/dist/production/lib/server-runtime/entry.js +1 -1
  135. package/dist/production/lib/server-runtime/errors.js +1 -1
  136. package/dist/production/lib/server-runtime/headers.js +1 -1
  137. package/dist/production/lib/server-runtime/invariant.js +1 -1
  138. package/dist/production/lib/server-runtime/mode.js +1 -1
  139. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  140. package/dist/production/lib/server-runtime/routes.js +1 -1
  141. package/dist/production/lib/server-runtime/server.d.ts +12 -0
  142. package/dist/production/lib/server-runtime/server.js +13 -1
  143. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  144. package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
  145. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +9 -1
  146. package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
  147. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +12 -6
  148. package/dist/production/lib/server-runtime/sessions.d.ts +31 -2
  149. package/dist/production/lib/server-runtime/sessions.js +20 -3
  150. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  151. package/dist/production/lib/server-runtime/urls.js +1 -1
  152. package/dist/production/lib/server-runtime/warnings.js +1 -1
  153. package/dist/production/lib/types/internal.js +1 -1
  154. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  155. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  156. package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
  157. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  158. package/docs/explanation/sessions-and-cookies.md +13 -13
  159. package/docs/explanation/state-management.md +2 -2
  160. package/docs/how-to/presets.md +2 -2
  161. package/docs/how-to/react-server-components.md +53 -1
  162. package/docs/how-to/security.md +8 -1
  163. package/docs/how-to/server-bundles.md +2 -2
  164. package/docs/start/data/route-object.md +2 -2
  165. package/docs/start/data/routing.md +1 -1
  166. package/docs/start/framework/pending-ui.md +1 -1
  167. package/docs/start/framework/route-module.md +8 -8
  168. package/docs/start/framework/routing.md +1 -1
  169. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -9,7 +9,7 @@
9
9
  * @license MIT
10
10
  */
11
11
  import { PROTOCOL_RELATIVE_URL_REGEX } from "../router/url.js";
12
- import { createBrowserHistory, invariant } from "../router/history.js";
12
+ import { createBrowserHistory, createPath, invariant } from "../router/history.js";
13
13
  import { ErrorResponseImpl, createContext, resolvePath } from "../router/utils.js";
14
14
  import { createRouter, hasInvalidProtocol, isMutationMethod } from "../router/router.js";
15
15
  import { RSCRouterContext } from "../context.js";
@@ -17,7 +17,7 @@ import { RouterProvider } from "../components.js";
17
17
  import { createRequestInit } from "../dom/ssr/data.js";
18
18
  import { getSingleFetchDataStrategyImpl, singleFetchUrl, stripIndexParam } from "../dom/ssr/single-fetch.js";
19
19
  import { noActionDefinedError, shouldHydrateRouteLoader } from "../dom/ssr/routes.js";
20
- import { getPathsWithAncestors } from "../dom/ssr/fog-of-war.js";
20
+ import { getPathsWithAncestors, handleClientVersionMismatch } from "../dom/ssr/fog-of-war.js";
21
21
  import { FrameworkContext, setIsHydrated } from "../dom/ssr/components.js";
22
22
  import { RSCRouterGlobalErrorBoundary } from "./errorBoundaries.js";
23
23
  import { populateRSCRouteModules } from "./route-modules.js";
@@ -133,6 +133,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
133
133
  routeModules: globalVar.__reactRouterRouteModules
134
134
  };
135
135
  if (payload.type !== "render") throw new Error("Invalid payload type");
136
+ let { clientVersion } = payload;
136
137
  globalVar.__reactRouterRouteModules = globalVar.__reactRouterRouteModules ?? {};
137
138
  populateRSCRouteModules(globalVar.__reactRouterRouteModules, payload.matches);
138
139
  let routes = payload.matches.reduceRight((previous, match) => {
@@ -167,7 +168,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
167
168
  basename: payload.basename,
168
169
  isSpaMode: false
169
170
  }),
170
- async patchRoutesOnNavigation({ path, signal }) {
171
+ async patchRoutesOnNavigation({ path, signal, fetcherKey }) {
171
172
  if (payload.routeDiscovery.mode === "initial") {
172
173
  if (!applyPatchesPromise) applyPatchesPromise = (async () => {
173
174
  if (!payload.patches) return;
@@ -182,9 +183,10 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
182
183
  return;
183
184
  }
184
185
  if (discoveredPaths.has(path)) return;
185
- await fetchAndApplyManifestPatches([path], createFromReadableStream, fetchImplementation, signal);
186
+ let { state } = globalVar.__reactRouterDataRouter;
187
+ await fetchAndApplyManifestPatches([path], createFromReadableStream, fetchImplementation, clientVersion, fetcherKey ? window.location.href : createPath(state.navigation.location || state.location), signal);
186
188
  },
187
- dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation)
189
+ dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation, clientVersion)
188
190
  });
189
191
  if (globalVar.__reactRouterDataRouter.state.initialized) {
190
192
  globalVar.__routerInitialized = true;
@@ -237,19 +239,16 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
237
239
  };
238
240
  }
239
241
  const renderedRoutesContext = createContext();
240
- function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation) {
242
+ function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation, clientVersion) {
241
243
  let dataStrategy = getSingleFetchDataStrategyImpl(getRouter, (match) => {
242
244
  let M = match;
243
245
  return {
244
246
  hasLoader: M.route.hasLoader,
245
- hasClientLoader: M.route.hasClientLoader,
246
- hasComponent: M.route.hasComponent,
247
- hasAction: M.route.hasAction,
248
- hasClientAction: M.route.hasClientAction
247
+ hasClientLoader: M.route.hasClientLoader
249
248
  };
250
- }, getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation), ssr, (match) => {
249
+ }, getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion), ssr, (match) => {
251
250
  let M = match;
252
- return M.route.hasComponent && !M.route.element;
251
+ return !M.route.hasComponent || M.route.element != null;
253
252
  });
254
253
  return async (args) => args.runClientMiddleware(async () => {
255
254
  args.context.set(renderedRoutesContext, []);
@@ -268,7 +267,7 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream,
268
267
  return results;
269
268
  });
270
269
  }
271
- function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation) {
270
+ function getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion) {
272
271
  return async (args, targetRoutes) => {
273
272
  let { request, context } = args;
274
273
  let url = singleFetchUrl(request.url, "rsc");
@@ -292,6 +291,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
292
291
  } }
293
292
  };
294
293
  if (payload.type !== "render") throw new Error("Unexpected payload type");
294
+ if (clientVersion !== void 0 && await handleClientVersionMismatch(payload.clientVersion !== clientVersion, clientVersion, createPath(getRouter().state.navigation.location || getRouter().state.location))) return new Promise(() => {});
295
295
  context.get(renderedRoutesContext).push(...payload.matches);
296
296
  let results = { routes: {} };
297
297
  const dataKey = isMutationMethod(request.method) ? "actionData" : "loaderData";
@@ -347,7 +347,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
347
347
  */
348
348
  function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementation = fetch, payload, getContext }) {
349
349
  if (payload.type !== "render") throw new Error("Invalid payload type");
350
- let { routeDiscovery } = payload;
350
+ let { routeDiscovery, clientVersion } = payload;
351
351
  let { router, routeModules } = React$1.useMemo(() => createRouterFromPayload({
352
352
  payload,
353
353
  fetchImplementation,
@@ -413,7 +413,7 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
413
413
  });
414
414
  if (paths.length === 0) return;
415
415
  try {
416
- await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation);
416
+ await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, null);
417
417
  } catch (e) {
418
418
  console.error("Failed to fetch manifest patches", e);
419
419
  }
@@ -433,7 +433,8 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
433
433
  }, [
434
434
  routeDiscovery,
435
435
  createFromReadableStream,
436
- fetchImplementation
436
+ fetchImplementation,
437
+ clientVersion
437
438
  ]);
438
439
  const frameworkContext = {
439
440
  future: {},
@@ -506,6 +507,7 @@ function createRouteFromServerManifest(match, payload) {
506
507
  shouldRevalidate: match.shouldRevalidate,
507
508
  hasLoader: true,
508
509
  hasClientLoader: match.clientLoader != null,
510
+ hasComponent: match.hasComponent,
509
511
  hasAction: match.hasAction,
510
512
  hasClientAction: match.clientAction != null
511
513
  };
@@ -526,23 +528,31 @@ function preventInvalidServerHandlerCall(type, routeId, hasHandler) {
526
528
  const nextPaths = /* @__PURE__ */ new Set();
527
529
  const discoveredPathsMaxSize = 1e3;
528
530
  const discoveredPaths = /* @__PURE__ */ new Set();
529
- function getManifestUrl(paths) {
531
+ function getManifestUrl(paths, clientVersion) {
530
532
  if (paths.length === 0) return null;
531
- if (paths.length === 1) return new URL(`${paths[0]}.manifest`, window.location.origin);
532
- let basename = (window.__reactRouterDataRouter.basename ?? "").replace(/^\/|\/$/g, "");
533
- let url = new URL(`${basename}/.manifest`, window.location.origin);
534
- url.searchParams.set("paths", paths.sort().join(","));
533
+ let url;
534
+ if (paths.length === 1) url = new URL(`${paths[0]}.manifest`, window.location.origin);
535
+ else {
536
+ let basename = (window.__reactRouterDataRouter.basename ?? "").replace(/^\/|\/$/g, "");
537
+ url = new URL(`${basename}/.manifest`, window.location.origin);
538
+ url.searchParams.set("paths", paths.sort().join(","));
539
+ }
540
+ if (clientVersion !== void 0) url.searchParams.set("version", clientVersion);
535
541
  return url;
536
542
  }
537
- async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, signal) {
543
+ async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, errorReloadPath, signal) {
538
544
  paths = getPathsWithAncestors(paths);
539
- let url = getManifestUrl(paths);
545
+ let url = getManifestUrl(paths, clientVersion);
540
546
  if (url == null) return;
541
547
  if (url.toString().length > 7680) {
542
548
  nextPaths.clear();
543
549
  return;
544
550
  }
545
551
  let response = await fetchImplementation(new Request(url, { signal }));
552
+ if (clientVersion !== void 0 && response.status === 204 && response.headers.has("X-Remix-Reload-Document")) {
553
+ await handleClientVersionMismatch(true, clientVersion, errorReloadPath);
554
+ return;
555
+ }
546
556
  if (!response.body || response.status < 200 || response.status >= 300) throw new Error("Unable to fetch new route matches from the server");
547
557
  let payload = await createFromReadableStream(response.body, { temporaryReferences: void 0 });
548
558
  if (payload.type !== "manifest") throw new Error("Failed to patch routes");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -11,11 +11,13 @@
11
11
  //#region lib/rsc/html-stream/server.ts
12
12
  const encoder = new TextEncoder();
13
13
  const trailer = "</body></html>";
14
- function injectRSCPayload(rscStream) {
14
+ function injectRSCPayload(rscStream, { nonce } = {}) {
15
15
  let decoder = new TextDecoder();
16
16
  let resolveFlightDataPromise;
17
17
  let flightDataPromise = new Promise((resolve) => resolveFlightDataPromise = resolve);
18
18
  let startedRSC = false;
19
+ let cancelled = false;
20
+ let rscReader = null;
19
21
  let buffered = [];
20
22
  let timeout = null;
21
23
  function flushBufferedChunks(controller) {
@@ -32,10 +34,12 @@ function injectRSCPayload(rscStream) {
32
34
  buffered.push(chunk);
33
35
  if (timeout) return;
34
36
  timeout = setTimeout(async () => {
37
+ if (cancelled) return;
35
38
  flushBufferedChunks(controller);
36
39
  if (!startedRSC) {
37
40
  startedRSC = true;
38
- writeRSCStream(rscStream, controller).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
41
+ rscReader = rscStream.getReader();
42
+ writeRSCStream(rscReader, controller, () => cancelled, nonce).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
39
43
  }
40
44
  }, 0);
41
45
  },
@@ -46,30 +50,45 @@ function injectRSCPayload(rscStream) {
46
50
  flushBufferedChunks(controller);
47
51
  }
48
52
  controller.enqueue(encoder.encode("</body></html>"));
53
+ },
54
+ async cancel(reason) {
55
+ cancelled = true;
56
+ if (timeout) {
57
+ clearTimeout(timeout);
58
+ timeout = null;
59
+ }
60
+ buffered.length = 0;
61
+ if (rscReader) await rscReader.cancel(reason).catch(() => {});
62
+ else await rscStream.cancel(reason).catch(() => {});
63
+ resolveFlightDataPromise();
49
64
  }
50
65
  });
51
66
  }
52
- async function writeRSCStream(rscStream, controller) {
67
+ async function writeRSCStream(reader, controller, isCancelled, nonce) {
53
68
  let decoder = new TextDecoder("utf-8", { fatal: true });
54
- const reader = rscStream.getReader();
55
69
  try {
56
70
  let read;
57
71
  while ((read = await reader.read()) && !read.done) {
72
+ if (isCancelled()) return;
58
73
  const chunk = read.value;
59
74
  try {
60
- writeChunk(JSON.stringify(decoder.decode(chunk, { stream: true })), controller);
75
+ writeChunk(JSON.stringify(decoder.decode(chunk, { stream: true })), controller, nonce);
61
76
  } catch (e) {
62
- writeChunk(`Uint8Array.from(atob(${JSON.stringify(btoa(String.fromCodePoint(...chunk)))}), m => m.codePointAt(0))`, controller);
77
+ writeChunk(`Uint8Array.from(atob(${JSON.stringify(btoa(String.fromCodePoint(...chunk)))}), m => m.codePointAt(0))`, controller, nonce);
63
78
  }
64
79
  }
65
80
  } finally {
66
81
  reader.releaseLock();
67
82
  }
68
83
  let remaining = decoder.decode();
69
- if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
84
+ if (remaining.length && !isCancelled()) writeChunk(JSON.stringify(remaining), controller, nonce);
85
+ }
86
+ function writeChunk(chunk, controller, nonce) {
87
+ let nonceAttr = nonce == null ? "" : ` nonce="${escapeAttribute(nonce)}"`;
88
+ controller.enqueue(encoder.encode(`<script${nonceAttr}>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}<\/script>`));
70
89
  }
71
- function writeChunk(chunk, controller) {
72
- controller.enqueue(encoder.encode(`<script>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}<\/script>`));
90
+ function escapeAttribute(value) {
91
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
73
92
  }
74
93
  function escapeScript(script) {
75
94
  return script.replace(/<!--/g, "<\\!--").replace(/<\/(script)/gi, "</\\$1");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -65,13 +65,13 @@ type RSCRenderPayload = {
65
65
  type: "render";
66
66
  actionData: Record<string, any> | null;
67
67
  basename: string | undefined;
68
+ clientVersion?: string;
68
69
  errors: Record<string, any> | null;
69
70
  loaderData: Record<string, any>;
70
71
  location: Location;
71
72
  routeDiscovery: RouteDiscovery;
72
73
  matches: RSCRouteMatch[];
73
74
  patches?: Promise<RSCRouteManifest[]>;
74
- nonce?: string;
75
75
  formState?: ReactFormState;
76
76
  };
77
77
  type RSCManifestPayload = {
@@ -168,6 +168,8 @@ type RouteDiscovery = {
168
168
  * encoding the {@link unstable_RSCPayload}.
169
169
  * @param opts.loadServerAction Your `react-server-dom-xyz/server`'s
170
170
  * `loadServerAction` function, used to load a server action by ID.
171
+ * @param opts.clientVersion A version derived from the client build output used
172
+ * to detect stale clients during lazy route discovery.
171
173
  * @param opts.onError An optional error handler that will be called with any
172
174
  * errors that occur during the request processing.
173
175
  * @param opts.request The [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
@@ -191,6 +193,7 @@ declare function matchRSCServerRequest({
191
193
  loadServerAction,
192
194
  decodeAction,
193
195
  decodeFormState,
196
+ clientVersion,
194
197
  onError,
195
198
  request,
196
199
  routes,
@@ -204,6 +207,7 @@ declare function matchRSCServerRequest({
204
207
  decodeFormState?: DecodeFormStateFunction;
205
208
  requestContext?: RouterContextProvider;
206
209
  loadServerAction?: LoadServerActionFunction;
210
+ clientVersion?: string;
207
211
  onError?: (error: unknown) => void;
208
212
  request: Request;
209
213
  routes: RSCRouteConfigEntry[];
@@ -26,12 +26,17 @@ type SSRCreateFromReadableStreamFunction = (body: ReadableStream<Uint8Array>) =>
26
26
  * request,
27
27
  * serverResponse,
28
28
  * createFromReadableStream,
29
- * async renderHTML(getPayload) {
29
+ * nonce,
30
+ * async renderHTML(getPayload, options) {
30
31
  * const payload = getPayload();
31
32
  *
32
33
  * return await renderHTMLToReadableStream(
33
- * <RSCStaticRouter getPayload={getPayload} />,
34
+ * <RSCStaticRouter
35
+ * getPayload={getPayload}
36
+ * nonce={options.nonce}
37
+ * />,
34
38
  * {
39
+ * ...options,
35
40
  * bootstrapScriptContent,
36
41
  * formState: await payload.formState,
37
42
  * }
@@ -49,6 +54,8 @@ type SSRCreateFromReadableStreamFunction = (body: ReadableStream<Uint8Array>) =>
49
54
  * @param opts.serverResponse A Response or partial response generated by the [RSC](https://react.dev/reference/rsc/server-components) handler containing a serialized {@link unstable_RSCPayload}.
50
55
  * @param opts.hydrate Whether to hydrate the server response with the RSC payload.
51
56
  * Defaults to `true`.
57
+ * @param opts.nonce An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
58
+ * for inline scripts generated while rendering the HTML document.
52
59
  * @param opts.renderHTML A function that renders the {@link unstable_RSCPayload} to
53
60
  * HTML, usually using a {@link unstable_RSCStaticRouter | `<RSCStaticRouter>`}.
54
61
  * @param opts.request The request to route.
@@ -61,16 +68,19 @@ declare function routeRSCServerRequest({
61
68
  serverResponse,
62
69
  createFromReadableStream,
63
70
  renderHTML,
64
- hydrate
71
+ hydrate,
72
+ nonce
65
73
  }: {
66
74
  request: Request;
67
75
  serverResponse: Response;
68
76
  createFromReadableStream: SSRCreateFromReadableStreamFunction;
69
77
  renderHTML: (getPayload: () => DecodedPayload, options: {
78
+ nonce?: string;
70
79
  onError(error: unknown): string | undefined;
71
80
  onHeaders(headers: Headers): void;
72
81
  }) => ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>;
73
82
  hydrate?: boolean;
83
+ nonce?: string;
74
84
  }): Promise<Response>;
75
85
  /**
76
86
  * Props for the {@link unstable_RSCStaticRouter} component.
@@ -84,6 +94,12 @@ interface RSCStaticRouterProps {
84
94
  * through from {@link unstable_routeRSCServerRequest}'s `renderHTML`.
85
95
  */
86
96
  getPayload: () => DecodedPayload;
97
+ /**
98
+ * An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
99
+ * used as the default for nonce-aware components such as `<Links>` and
100
+ * `<ScrollRestoration>`.
101
+ */
102
+ nonce?: string;
87
103
  }
88
104
  /**
89
105
  * Pre-renders an {@link unstable_RSCPayload} to HTML. Usually used in
@@ -101,12 +117,17 @@ interface RSCStaticRouterProps {
101
117
  * request,
102
118
  * serverResponse,
103
119
  * createFromReadableStream,
104
- * async renderHTML(getPayload) {
120
+ * nonce,
121
+ * async renderHTML(getPayload, options) {
105
122
  * const payload = getPayload();
106
123
  *
107
124
  * return await renderHTMLToReadableStream(
108
- * <RSCStaticRouter getPayload={getPayload} />,
125
+ * <RSCStaticRouter
126
+ * getPayload={getPayload}
127
+ * nonce={options.nonce}
128
+ * />,
109
129
  * {
130
+ * ...options,
110
131
  * bootstrapScriptContent,
111
132
  * formState: await payload.formState,
112
133
  * }
@@ -120,10 +141,12 @@ interface RSCStaticRouterProps {
120
141
  * @mode data
121
142
  * @param props Props
122
143
  * @param {unstable_RSCStaticRouterProps.getPayload} props.getPayload n/a
144
+ * @param {unstable_RSCStaticRouterProps.nonce} props.nonce n/a
123
145
  * @returns A React component that renders the {@link unstable_RSCPayload} as HTML.
124
146
  */
125
147
  declare function RSCStaticRouter({
126
- getPayload
148
+ getPayload,
149
+ nonce
127
150
  }: RSCStaticRouterProps): React$1.JSX.Element | null;
128
151
  //#endregion
129
152
  export { RSCStaticRouter, RSCStaticRouterProps, SSRCreateFromReadableStreamFunction, routeRSCServerRequest };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -40,12 +40,17 @@ const defaultManifestPath = "/__manifest";
40
40
  * request,
41
41
  * serverResponse,
42
42
  * createFromReadableStream,
43
- * async renderHTML(getPayload) {
43
+ * nonce,
44
+ * async renderHTML(getPayload, options) {
44
45
  * const payload = getPayload();
45
46
  *
46
47
  * return await renderHTMLToReadableStream(
47
- * <RSCStaticRouter getPayload={getPayload} />,
48
+ * <RSCStaticRouter
49
+ * getPayload={getPayload}
50
+ * nonce={options.nonce}
51
+ * />,
48
52
  * {
53
+ * ...options,
49
54
  * bootstrapScriptContent,
50
55
  * formState: await payload.formState,
51
56
  * }
@@ -63,6 +68,8 @@ const defaultManifestPath = "/__manifest";
63
68
  * @param opts.serverResponse A Response or partial response generated by the [RSC](https://react.dev/reference/rsc/server-components) handler containing a serialized {@link unstable_RSCPayload}.
64
69
  * @param opts.hydrate Whether to hydrate the server response with the RSC payload.
65
70
  * Defaults to `true`.
71
+ * @param opts.nonce An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
72
+ * for inline scripts generated while rendering the HTML document.
66
73
  * @param opts.renderHTML A function that renders the {@link unstable_RSCPayload} to
67
74
  * HTML, usually using a {@link unstable_RSCStaticRouter | `<RSCStaticRouter>`}.
68
75
  * @param opts.request The request to route.
@@ -70,7 +77,7 @@ const defaultManifestPath = "/__manifest";
70
77
  * that either contains the [RSC](https://react.dev/reference/rsc/server-components)
71
78
  * payload for data requests, or renders the HTML for document requests.
72
79
  */
73
- async function routeRSCServerRequest({ request, serverResponse, createFromReadableStream, renderHTML, hydrate = true }) {
80
+ async function routeRSCServerRequest({ request, serverResponse, createFromReadableStream, renderHTML, hydrate = true, nonce }) {
74
81
  const url = new URL(request.url);
75
82
  if (isReactServerRequest(url) || isManifestRequest(url) || request.headers.has("rsc-action-id") || serverResponse.headers.get("React-Router-Resource") === "true") return serverResponse;
76
83
  if (!serverResponse.body) throw new Error("Missing body in server response");
@@ -140,6 +147,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
140
147
  let status = serverResponse.status;
141
148
  let statusText = serverResponse.statusText;
142
149
  let html = await renderHTML(getPayload, {
150
+ nonce,
143
151
  onError(error) {
144
152
  if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
145
153
  renderRedirect = decodeRedirectErrorDigest(error.digest);
@@ -180,7 +188,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
180
188
  headers
181
189
  });
182
190
  if (!serverResponseB?.body) throw new Error("Failed to clone server response");
183
- const body = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(redirectTransform);
191
+ const body = html.pipeThrough(injectRSCPayload(serverResponseB.body, { nonce })).pipeThrough(redirectTransform);
184
192
  return new Response(body, {
185
193
  status,
186
194
  statusText,
@@ -219,6 +227,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
219
227
  } }
220
228
  });
221
229
  }, {
230
+ nonce,
222
231
  onError(error) {
223
232
  if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
224
233
  retryRedirect = decodeRedirectErrorDigest(error.digest);
@@ -258,7 +267,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
258
267
  headers
259
268
  });
260
269
  if (!serverResponseB?.body) throw new Error("Failed to clone server response");
261
- const body = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(retryRedirectTransform);
270
+ const body = html.pipeThrough(injectRSCPayload(serverResponseB.body, { nonce })).pipeThrough(retryRedirectTransform);
262
271
  return new Response(body, {
263
272
  status,
264
273
  statusText,
@@ -284,12 +293,17 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
284
293
  * request,
285
294
  * serverResponse,
286
295
  * createFromReadableStream,
287
- * async renderHTML(getPayload) {
296
+ * nonce,
297
+ * async renderHTML(getPayload, options) {
288
298
  * const payload = getPayload();
289
299
  *
290
300
  * return await renderHTMLToReadableStream(
291
- * <RSCStaticRouter getPayload={getPayload} />,
301
+ * <RSCStaticRouter
302
+ * getPayload={getPayload}
303
+ * nonce={options.nonce}
304
+ * />,
292
305
  * {
306
+ * ...options,
293
307
  * bootstrapScriptContent,
294
308
  * formState: await payload.formState,
295
309
  * }
@@ -303,9 +317,10 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
303
317
  * @mode data
304
318
  * @param props Props
305
319
  * @param {unstable_RSCStaticRouterProps.getPayload} props.getPayload n/a
320
+ * @param {unstable_RSCStaticRouterProps.nonce} props.nonce n/a
306
321
  * @returns A React component that renders the {@link unstable_RSCPayload} as HTML.
307
322
  */
308
- function RSCStaticRouter({ getPayload }) {
323
+ function RSCStaticRouter({ getPayload, nonce }) {
309
324
  const decoded = getPayload();
310
325
  const payload = React$1.use(decoded);
311
326
  if (payload.type === "redirect") {
@@ -385,13 +400,13 @@ function RSCStaticRouter({ getPayload }) {
385
400
  mode: "lazy",
386
401
  manifestPath: payload.routeDiscovery.manifestPath || defaultManifestPath
387
402
  },
388
- routeModules: createRSCRouteModules(payload)
403
+ routeModules: createRSCRouteModules(payload),
404
+ nonce
389
405
  };
390
406
  return /* @__PURE__ */ React$1.createElement(RSCRouterContext.Provider, { value: true }, /* @__PURE__ */ React$1.createElement(RSCRouterGlobalErrorBoundary, { location: payload.location }, /* @__PURE__ */ React$1.createElement(FrameworkContext.Provider, { value: frameworkContext }, /* @__PURE__ */ React$1.createElement(StaticRouterProvider, {
391
407
  context,
392
408
  router,
393
- hydrate: false,
394
- nonce: payload.nonce
409
+ hydrate: false
395
410
  }))));
396
411
  }
397
412
  function isReactServerRequest(url) {
@@ -53,13 +53,39 @@ interface Cookie {
53
53
  }
54
54
  /**
55
55
  * Creates a logical container for managing a browser cookie from the server.
56
+ *
57
+ * @public
58
+ * @category Utils
59
+ * @mode framework
60
+ * @mode data
61
+ * @param name The name of the cookie.
62
+ * @param cookieOptions Options for parsing and serializing the cookie.
63
+ * @returns A {@link Cookie} object for parsing and serializing the cookie.
56
64
  */
57
65
  declare const createCookie: (name: string, cookieOptions?: CookieOptions) => Cookie;
66
+ /**
67
+ * A function that determines whether a value is a React Router {@link Cookie}
68
+ * object.
69
+ *
70
+ * @public
71
+ * @category Utils
72
+ * @mode framework
73
+ * @mode data
74
+ * @param object The value to check.
75
+ * @returns `true` if the value is a React Router {@link Cookie} object;
76
+ * otherwise, `false`.
77
+ */
58
78
  type IsCookieFunction = (object: any) => object is Cookie;
59
79
  /**
60
- * Returns true if an object is a Remix cookie container.
80
+ * Returns `true` if a value is a React Router {@link Cookie} object.
61
81
  *
62
- * @see https://remix.run/utils/cookies#iscookie
82
+ * @public
83
+ * @category Utils
84
+ * @mode framework
85
+ * @mode data
86
+ * @param object The value to check.
87
+ * @returns `true` if the value is a React Router {@link Cookie} object;
88
+ * otherwise, `false`.
63
89
  */
64
90
  declare const isCookie: IsCookieFunction;
65
91
  //#endregion
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -14,6 +14,14 @@ import { parse, serialize } from "cookie-es";
14
14
  //#region lib/server-runtime/cookies.ts
15
15
  /**
16
16
  * Creates a logical container for managing a browser cookie from the server.
17
+ *
18
+ * @public
19
+ * @category Utils
20
+ * @mode framework
21
+ * @mode data
22
+ * @param name The name of the cookie.
23
+ * @param cookieOptions Options for parsing and serializing the cookie.
24
+ * @returns A {@link Cookie} object for parsing and serializing the cookie.
17
25
  */
18
26
  const createCookie = (name, cookieOptions = {}) => {
19
27
  let { secrets = [], ...options } = {
@@ -53,9 +61,15 @@ const createCookie = (name, cookieOptions = {}) => {
53
61
  };
54
62
  };
55
63
  /**
56
- * Returns true if an object is a Remix cookie container.
64
+ * Returns `true` if a value is a React Router {@link Cookie} object.
57
65
  *
58
- * @see https://remix.run/utils/cookies#iscookie
66
+ * @public
67
+ * @category Utils
68
+ * @mode framework
69
+ * @mode data
70
+ * @param object The value to check.
71
+ * @returns `true` if the value is a React Router {@link Cookie} object;
72
+ * otherwise, `false`.
59
73
  */
60
74
  const isCookie = (object) => {
61
75
  return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * react-router v8.2.0
2
+ * react-router v8.3.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *