@bleedingdev/modern-js-runtime 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

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 (203) hide show
  1. package/dist/cjs/boundary-debugger/index.js +4 -0
  2. package/dist/cjs/cli/index.js +11 -0
  3. package/dist/cjs/{router/runtime/tanstack/rsc/ClientSlot.js → core/context/extensions.js} +33 -21
  4. package/dist/cjs/{router/runtime/tanstack/rsc/SlotContext.js → core/context/helmetContext.js} +16 -20
  5. package/dist/cjs/core/context/index.js +65 -0
  6. package/dist/cjs/core/react/wrapper.js +6 -4
  7. package/dist/cjs/core/server/helmet.js +2 -1
  8. package/dist/cjs/core/server/requestHandler.js +42 -29
  9. package/dist/cjs/core/server/routerCleanup.js +110 -0
  10. package/dist/cjs/core/server/scriptOrder.js +75 -4
  11. package/dist/cjs/core/server/stream/afterTemplate.js +6 -18
  12. package/dist/cjs/core/server/stream/deferredScript.js +4 -1
  13. package/dist/cjs/core/server/string/index.js +1 -7
  14. package/dist/cjs/core/server/string/loadable.js +13 -40
  15. package/dist/cjs/core/server/string/ssrData.js +1 -1
  16. package/dist/cjs/core/server/utils.js +31 -8
  17. package/dist/cjs/exports/head.js +135 -74
  18. package/dist/cjs/exports/tanstack-router.js +36 -305
  19. package/dist/cjs/module-federation/index.js +178 -0
  20. package/dist/cjs/router/cli/code/index.js +1 -47
  21. package/dist/cjs/router/cli/code/templates.js +1 -14
  22. package/dist/cjs/router/cli/handler.js +1 -1
  23. package/dist/cjs/router/cli/index.js +2 -23
  24. package/dist/cjs/router/runtime/DeferredDataScripts.node.js +16 -4
  25. package/dist/cjs/router/runtime/PrefetchLink.js +2 -3
  26. package/dist/cjs/router/runtime/internal.js +20 -13
  27. package/dist/cjs/router/runtime/lifecycle.js +37 -22
  28. package/dist/cjs/router/runtime/plugin.js +2 -9
  29. package/dist/cjs/router/runtime/plugin.node.js +2 -7
  30. package/dist/cjs/router/runtime/provider.js +107 -0
  31. package/dist/cjs/router/runtime/utils.js +35 -9
  32. package/dist/esm/boundary-debugger/index.mjs +4 -0
  33. package/dist/esm/cli/index.mjs +4 -2
  34. package/dist/esm/core/context/extensions.mjs +28 -0
  35. package/dist/esm/core/context/helmetContext.mjs +13 -0
  36. package/dist/esm/core/context/index.mjs +5 -0
  37. package/dist/esm/core/react/wrapper.mjs +6 -4
  38. package/dist/esm/core/server/helmet.mjs +2 -1
  39. package/dist/esm/core/server/requestHandler.mjs +43 -30
  40. package/dist/esm/core/server/routerCleanup.mjs +66 -0
  41. package/dist/esm/core/server/scriptOrder.mjs +60 -1
  42. package/dist/esm/core/server/stream/afterTemplate.mjs +8 -20
  43. package/dist/esm/core/server/stream/deferredScript.mjs +4 -1
  44. package/dist/esm/core/server/string/index.mjs +3 -9
  45. package/dist/esm/core/server/string/loadable.mjs +11 -38
  46. package/dist/esm/core/server/string/ssrData.mjs +2 -2
  47. package/dist/esm/core/server/utils.mjs +31 -8
  48. package/dist/esm/exports/head.mjs +135 -74
  49. package/dist/esm/exports/tanstack-router.mjs +30 -4
  50. package/dist/esm/module-federation/index.mjs +109 -0
  51. package/dist/esm/router/cli/code/index.mjs +1 -47
  52. package/dist/esm/router/cli/code/templates.mjs +1 -14
  53. package/dist/esm/router/cli/handler.mjs +1 -1
  54. package/dist/esm/router/cli/index.mjs +3 -24
  55. package/dist/esm/router/runtime/DeferredDataScripts.node.mjs +16 -4
  56. package/dist/esm/router/runtime/PrefetchLink.mjs +2 -3
  57. package/dist/esm/router/runtime/internal.mjs +16 -15
  58. package/dist/esm/router/runtime/lifecycle.mjs +22 -13
  59. package/dist/esm/router/runtime/plugin.mjs +4 -11
  60. package/dist/esm/router/runtime/plugin.node.mjs +4 -9
  61. package/dist/esm/router/runtime/provider.mjs +57 -0
  62. package/dist/esm/router/runtime/utils.mjs +35 -9
  63. package/dist/esm-node/boundary-debugger/index.mjs +4 -0
  64. package/dist/esm-node/cli/index.mjs +4 -2
  65. package/dist/esm-node/core/context/extensions.mjs +29 -0
  66. package/dist/esm-node/core/context/helmetContext.mjs +14 -0
  67. package/dist/esm-node/core/context/index.mjs +5 -0
  68. package/dist/esm-node/core/react/wrapper.mjs +6 -4
  69. package/dist/esm-node/core/server/helmet.mjs +2 -1
  70. package/dist/esm-node/core/server/requestHandler.mjs +43 -30
  71. package/dist/esm-node/core/server/routerCleanup.mjs +67 -0
  72. package/dist/esm-node/core/server/scriptOrder.mjs +60 -1
  73. package/dist/esm-node/core/server/stream/afterTemplate.mjs +8 -20
  74. package/dist/esm-node/core/server/stream/deferredScript.mjs +4 -1
  75. package/dist/esm-node/core/server/string/index.mjs +3 -9
  76. package/dist/esm-node/core/server/string/loadable.mjs +11 -38
  77. package/dist/esm-node/core/server/string/ssrData.mjs +2 -2
  78. package/dist/esm-node/core/server/utils.mjs +31 -8
  79. package/dist/esm-node/exports/head.mjs +135 -74
  80. package/dist/esm-node/exports/tanstack-router.mjs +30 -4
  81. package/dist/esm-node/module-federation/index.mjs +110 -0
  82. package/dist/esm-node/router/cli/code/index.mjs +1 -47
  83. package/dist/esm-node/router/cli/code/templates.mjs +1 -14
  84. package/dist/esm-node/router/cli/handler.mjs +1 -1
  85. package/dist/esm-node/router/cli/index.mjs +3 -24
  86. package/dist/esm-node/router/runtime/DeferredDataScripts.node.mjs +16 -4
  87. package/dist/esm-node/router/runtime/PrefetchLink.mjs +2 -3
  88. package/dist/esm-node/router/runtime/internal.mjs +16 -15
  89. package/dist/esm-node/router/runtime/lifecycle.mjs +22 -13
  90. package/dist/esm-node/router/runtime/plugin.mjs +4 -11
  91. package/dist/esm-node/router/runtime/plugin.node.mjs +4 -9
  92. package/dist/esm-node/router/runtime/provider.mjs +58 -0
  93. package/dist/esm-node/router/runtime/utils.mjs +35 -9
  94. package/dist/types/cli/index.d.ts +3 -1
  95. package/dist/types/core/context/extensions.d.ts +37 -0
  96. package/dist/types/core/context/helmetContext.d.ts +10 -0
  97. package/dist/types/core/context/index.d.ts +6 -0
  98. package/dist/types/core/context/runtime.d.ts +1 -11
  99. package/dist/types/core/server/routerCleanup.d.ts +28 -0
  100. package/dist/types/core/server/scriptOrder.d.ts +24 -0
  101. package/dist/types/core/server/string/loadable.d.ts +1 -7
  102. package/dist/types/core/server/utils.d.ts +1 -0
  103. package/dist/types/exports/tanstack-router.d.ts +88 -7
  104. package/dist/types/module-federation/index.d.ts +65 -0
  105. package/dist/types/router/cli/code/index.d.ts +1 -3
  106. package/dist/types/router/cli/handler.d.ts +0 -3
  107. package/dist/types/router/runtime/internal.d.ts +1 -0
  108. package/dist/types/router/runtime/lifecycle.d.ts +2 -0
  109. package/dist/types/router/runtime/plugin.d.ts +1 -1
  110. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  111. package/dist/types/router/runtime/provider.d.ts +61 -0
  112. package/package.json +15 -11
  113. package/rstest.config.mts +2 -4
  114. package/dist/cjs/router/cli/code/tanstackTypes.js +0 -447
  115. package/dist/cjs/router/runtime/tanstack/basepathRewrite.js +0 -66
  116. package/dist/cjs/router/runtime/tanstack/dataMutation.js +0 -349
  117. package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +0 -48
  118. package/dist/cjs/router/runtime/tanstack/outlet.js +0 -58
  119. package/dist/cjs/router/runtime/tanstack/plugin.js +0 -342
  120. package/dist/cjs/router/runtime/tanstack/plugin.node.js +0 -272
  121. package/dist/cjs/router/runtime/tanstack/prefetchLink.js +0 -59
  122. package/dist/cjs/router/runtime/tanstack/routeTree.js +0 -525
  123. package/dist/cjs/router/runtime/tanstack/rsc/CompositeComponent.js +0 -79
  124. package/dist/cjs/router/runtime/tanstack/rsc/ReplayableStream.js +0 -146
  125. package/dist/cjs/router/runtime/tanstack/rsc/RscNodeRenderer.js +0 -69
  126. package/dist/cjs/router/runtime/tanstack/rsc/client.js +0 -97
  127. package/dist/cjs/router/runtime/tanstack/rsc/createRscProxy.js +0 -145
  128. package/dist/cjs/router/runtime/tanstack/rsc/index.js +0 -46
  129. package/dist/cjs/router/runtime/tanstack/rsc/server.js +0 -250
  130. package/dist/cjs/router/runtime/tanstack/rsc/slotUsageSanitizer.js +0 -69
  131. package/dist/cjs/router/runtime/tanstack/rsc/symbols.js +0 -77
  132. package/dist/cjs/ssr/index.node.js +0 -125
  133. package/dist/cjs/ssr/serverRender/renderToStream/buildTemplate.after.js +0 -88
  134. package/dist/cjs/ssr/serverRender/renderToString/entry.js +0 -200
  135. package/dist/cjs/ssr/serverRender/types.js +0 -40
  136. package/dist/esm/router/cli/code/tanstackTypes.mjs +0 -396
  137. package/dist/esm/router/runtime/tanstack/basepathRewrite.mjs +0 -28
  138. package/dist/esm/router/runtime/tanstack/dataMutation.mjs +0 -305
  139. package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +0 -10
  140. package/dist/esm/router/runtime/tanstack/outlet.mjs +0 -17
  141. package/dist/esm/router/runtime/tanstack/plugin.mjs +0 -304
  142. package/dist/esm/router/runtime/tanstack/plugin.node.mjs +0 -234
  143. package/dist/esm/router/runtime/tanstack/prefetchLink.mjs +0 -18
  144. package/dist/esm/router/runtime/tanstack/routeTree.mjs +0 -481
  145. package/dist/esm/router/runtime/tanstack/rsc/ClientSlot.mjs +0 -19
  146. package/dist/esm/router/runtime/tanstack/rsc/CompositeComponent.mjs +0 -41
  147. package/dist/esm/router/runtime/tanstack/rsc/ReplayableStream.mjs +0 -104
  148. package/dist/esm/router/runtime/tanstack/rsc/RscNodeRenderer.mjs +0 -31
  149. package/dist/esm/router/runtime/tanstack/rsc/SlotContext.mjs +0 -17
  150. package/dist/esm/router/runtime/tanstack/rsc/client.mjs +0 -53
  151. package/dist/esm/router/runtime/tanstack/rsc/createRscProxy.mjs +0 -107
  152. package/dist/esm/router/runtime/tanstack/rsc/index.mjs +0 -1
  153. package/dist/esm/router/runtime/tanstack/rsc/server.mjs +0 -200
  154. package/dist/esm/router/runtime/tanstack/rsc/slotUsageSanitizer.mjs +0 -31
  155. package/dist/esm/router/runtime/tanstack/rsc/symbols.mjs +0 -17
  156. package/dist/esm/ssr/index.node.mjs +0 -44
  157. package/dist/esm/ssr/serverRender/renderToStream/buildTemplate.after.mjs +0 -50
  158. package/dist/esm/ssr/serverRender/renderToString/entry.mjs +0 -151
  159. package/dist/esm/ssr/serverRender/types.mjs +0 -1
  160. package/dist/esm-node/router/cli/code/tanstackTypes.mjs +0 -397
  161. package/dist/esm-node/router/runtime/tanstack/basepathRewrite.mjs +0 -29
  162. package/dist/esm-node/router/runtime/tanstack/dataMutation.mjs +0 -306
  163. package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +0 -11
  164. package/dist/esm-node/router/runtime/tanstack/outlet.mjs +0 -18
  165. package/dist/esm-node/router/runtime/tanstack/plugin.mjs +0 -305
  166. package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +0 -235
  167. package/dist/esm-node/router/runtime/tanstack/prefetchLink.mjs +0 -19
  168. package/dist/esm-node/router/runtime/tanstack/routeTree.mjs +0 -482
  169. package/dist/esm-node/router/runtime/tanstack/rsc/ClientSlot.mjs +0 -20
  170. package/dist/esm-node/router/runtime/tanstack/rsc/CompositeComponent.mjs +0 -42
  171. package/dist/esm-node/router/runtime/tanstack/rsc/ReplayableStream.mjs +0 -105
  172. package/dist/esm-node/router/runtime/tanstack/rsc/RscNodeRenderer.mjs +0 -32
  173. package/dist/esm-node/router/runtime/tanstack/rsc/SlotContext.mjs +0 -18
  174. package/dist/esm-node/router/runtime/tanstack/rsc/client.mjs +0 -54
  175. package/dist/esm-node/router/runtime/tanstack/rsc/createRscProxy.mjs +0 -108
  176. package/dist/esm-node/router/runtime/tanstack/rsc/index.mjs +0 -2
  177. package/dist/esm-node/router/runtime/tanstack/rsc/server.mjs +0 -201
  178. package/dist/esm-node/router/runtime/tanstack/rsc/slotUsageSanitizer.mjs +0 -32
  179. package/dist/esm-node/router/runtime/tanstack/rsc/symbols.mjs +0 -18
  180. package/dist/esm-node/ssr/index.node.mjs +0 -45
  181. package/dist/esm-node/ssr/serverRender/renderToStream/buildTemplate.after.mjs +0 -51
  182. package/dist/esm-node/ssr/serverRender/renderToString/entry.mjs +0 -152
  183. package/dist/esm-node/ssr/serverRender/types.mjs +0 -2
  184. package/dist/types/router/cli/code/tanstackTypes.d.ts +0 -10
  185. package/dist/types/router/runtime/tanstack/basepathRewrite.d.ts +0 -8
  186. package/dist/types/router/runtime/tanstack/dataMutation.d.ts +0 -29
  187. package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +0 -2
  188. package/dist/types/router/runtime/tanstack/outlet.d.ts +0 -2
  189. package/dist/types/router/runtime/tanstack/plugin.d.ts +0 -6
  190. package/dist/types/router/runtime/tanstack/plugin.node.d.ts +0 -6
  191. package/dist/types/router/runtime/tanstack/prefetchLink.d.ts +0 -11
  192. package/dist/types/router/runtime/tanstack/routeTree.d.ts +0 -8
  193. package/dist/types/router/runtime/tanstack/rsc/ClientSlot.d.ts +0 -5
  194. package/dist/types/router/runtime/tanstack/rsc/CompositeComponent.d.ts +0 -3
  195. package/dist/types/router/runtime/tanstack/rsc/ReplayableStream.d.ts +0 -24
  196. package/dist/types/router/runtime/tanstack/rsc/RscNodeRenderer.d.ts +0 -5
  197. package/dist/types/router/runtime/tanstack/rsc/SlotContext.d.ts +0 -11
  198. package/dist/types/router/runtime/tanstack/rsc/client.d.ts +0 -11
  199. package/dist/types/router/runtime/tanstack/rsc/createRscProxy.d.ts +0 -7
  200. package/dist/types/router/runtime/tanstack/rsc/index.d.ts +0 -2
  201. package/dist/types/router/runtime/tanstack/rsc/server.d.ts +0 -14
  202. package/dist/types/router/runtime/tanstack/rsc/slotUsageSanitizer.d.ts +0 -2
  203. package/dist/types/router/runtime/tanstack/rsc/symbols.d.ts +0 -46
@@ -1,25 +1,26 @@
1
1
  import { merge } from "@modern-js/runtime-utils/merge";
2
- import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
3
- import { modifyRoutes as external_plugin_mjs_modifyRoutes, routerPlugin } from "./plugin.mjs";
4
- import { tanstackRouterPlugin } from "./tanstack/plugin.mjs";
2
+ import { modifyRoutes, routerPlugin } from "./plugin.mjs";
3
+ import { registerRouterProvider, reportUnsupportedProviderRegistryHooks, resolveRouterProvider, routerProviderRegistryHooks } from "./provider.mjs";
4
+ registerRouterProvider('react-router', routerPlugin, {
5
+ isDefault: true
6
+ });
5
7
  const internal_routerPlugin = (userConfig = {})=>({
6
8
  name: '@modern-js/plugin-router',
7
- registryHooks: {
8
- onAfterCreateRouter: onAfterCreateRouter,
9
- onAfterHydrateRouter: onAfterHydrateRouter,
10
- onBeforeCreateRouter: onBeforeCreateRouter,
11
- modifyRoutes: modifyRoutes,
12
- onBeforeCreateRoutes: onBeforeCreateRoutes,
13
- onBeforeHydrateRouter: onBeforeHydrateRouter
14
- },
9
+ registryHooks: routerProviderRegistryHooks,
15
10
  setup: (api)=>{
16
11
  const mergedConfig = merge(api.getRuntimeConfig().router || {}, userConfig);
17
- const framework = mergedConfig.framework || 'react-router';
18
- const pluginFactory = 'tanstack' === framework ? tanstackRouterPlugin : routerPlugin;
19
- pluginFactory(userConfig).setup?.(api);
12
+ const pluginFactory = resolveRouterProvider(mergedConfig.framework, {
13
+ localDefault: {
14
+ name: 'react-router',
15
+ factory: routerPlugin
16
+ }
17
+ });
18
+ const providerPlugin = pluginFactory(userConfig);
19
+ reportUnsupportedProviderRegistryHooks(providerPlugin);
20
+ providerPlugin.setup?.(api);
20
21
  }
21
22
  });
22
23
  const internal = internal_routerPlugin;
23
24
  export { renderRoutes } from "./utils.mjs";
24
25
  export default internal;
25
- export { external_plugin_mjs_modifyRoutes as modifyRoutes, internal_routerPlugin as routerPlugin };
26
+ export { internal_routerPlugin as routerPlugin, modifyRoutes, registerRouterProvider, resolveRouterProvider };
@@ -1,3 +1,12 @@
1
+ import { createRuntimeContextExtension } from "../../core/context/extensions.mjs";
2
+ const routerRuntimeStateExtension = createRuntimeContextExtension('@modern-js/runtime:router-runtime-state');
3
+ const routerServerSnapshotExtension = createRuntimeContextExtension('@modern-js/runtime:router-server-snapshot');
4
+ function getRouterRuntimeState(runtimeContext) {
5
+ return routerRuntimeStateExtension.get(runtimeContext);
6
+ }
7
+ function getRouterServerSnapshot(runtimeContext) {
8
+ return routerServerSnapshotExtension.get(runtimeContext);
9
+ }
1
10
  function toHydrationScripts(state) {
2
11
  if (state.hydrationScripts?.length) return state.hydrationScripts;
3
12
  return state.hydrationScript ? [
@@ -61,12 +70,8 @@ function createRouterRuntimeState(state) {
61
70
  }
62
71
  function applyRouterRuntimeState(runtimeContext, state) {
63
72
  const normalized = createRouterRuntimeState(state);
64
- runtimeContext.routerFramework = normalized.framework;
65
- runtimeContext.routerInstance = normalized.instance;
66
- runtimeContext.routerHydrationScript = normalized.hydrationScript;
67
- runtimeContext.routerMatchedRouteIds = normalized.matchedRouteIds;
68
- runtimeContext.routerRuntime = normalized;
69
- if (normalized.serverSnapshot) runtimeContext.routerServerSnapshot = normalized.serverSnapshot;
73
+ routerRuntimeStateExtension.set(runtimeContext, normalized);
74
+ if (normalized.serverSnapshot) routerServerSnapshotExtension.set(runtimeContext, normalized.serverSnapshot);
70
75
  return runtimeContext;
71
76
  }
72
77
  function applyRouterServerPrepareResult(runtimeContext, result) {
@@ -79,18 +84,22 @@ function applyRouterServerPrepareResult(runtimeContext, result) {
79
84
  return runtimeContext;
80
85
  }
81
86
  function getRouterHydrationScripts(runtimeContext) {
82
- return runtimeContext.routerServerSnapshot?.hydrationScripts ?? toHydrationScripts({
83
- hydrationScript: runtimeContext.routerServerSnapshot?.hydrationScript
84
- }) ?? runtimeContext.routerRuntime?.hydrationScripts ?? toHydrationScripts({
85
- hydrationScript: runtimeContext.routerRuntime?.hydrationScript ?? runtimeContext.routerHydrationScript
87
+ const serverSnapshot = getRouterServerSnapshot(runtimeContext);
88
+ const runtimeState = getRouterRuntimeState(runtimeContext);
89
+ return serverSnapshot?.hydrationScripts ?? toHydrationScripts({
90
+ hydrationScript: serverSnapshot?.hydrationScript
91
+ }) ?? runtimeState?.hydrationScripts ?? toHydrationScripts({
92
+ hydrationScript: runtimeState?.hydrationScript
86
93
  }) ?? [];
87
94
  }
88
95
  function getRouterMatchedRouteIds(runtimeContext) {
89
- return runtimeContext.routerServerSnapshot?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(runtimeContext.routerServerSnapshot?.matches) ?? runtimeContext.routerRuntime?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(runtimeContext.routerRuntime?.matches) ?? runtimeContext.routerMatchedRouteIds;
96
+ const serverSnapshot = getRouterServerSnapshot(runtimeContext);
97
+ const runtimeState = getRouterRuntimeState(runtimeContext);
98
+ return serverSnapshot?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(serverSnapshot?.matches) ?? runtimeState?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(runtimeState?.matches);
90
99
  }
91
100
  async function cleanupRouterRuntimeState(runtimeContext) {
92
101
  try {
93
- await runtimeContext.routerRuntime?.cleanup?.();
102
+ await getRouterRuntimeState(runtimeContext)?.cleanup?.();
94
103
  } catch {}
95
104
  }
96
- export { applyRouterRuntimeState, applyRouterServerPrepareResult, cleanupRouterRuntimeState, createRouterRuntimeState, createRouterServerSnapshot, getRouterHydrationScripts, getRouterMatchedRouteIds };
105
+ export { applyRouterRuntimeState, applyRouterServerPrepareResult, cleanupRouterRuntimeState, createRouterRuntimeState, createRouterServerSnapshot, getRouterHydrationScripts, getRouterMatchedRouteIds, getRouterRuntimeState, getRouterServerSnapshot };
@@ -4,15 +4,15 @@ import { RouterProvider, createBrowserRouter, createHashRouter, createRoutesFrom
4
4
  import { normalizePathname } from "@modern-js/runtime-utils/url";
5
5
  import * as __rspack_external_react from "react";
6
6
  import { InternalRuntimeContext, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
7
- import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
8
7
  import { applyRouterRuntimeState } from "./lifecycle.mjs";
8
+ import { routerProviderRegistryHooks } from "./provider.mjs";
9
9
  import { createClientRouterFromPayload } from "./rsc-router.mjs";
10
10
  import { createRouteObjectsFromConfig, deserializeErrors, renderRoutes, urlJoin } from "./utils.mjs";
11
11
  let finalRouteConfig = {
12
12
  routes: []
13
13
  };
14
14
  let beforeCreateRouter = true;
15
- function plugin_modifyRoutes(modifyFunction) {
15
+ function modifyRoutes(modifyFunction) {
16
16
  if (beforeCreateRouter) {
17
17
  const { routes: originRoutes } = finalRouteConfig;
18
18
  const newRoutes = modifyFunction(originRoutes);
@@ -21,14 +21,7 @@ function plugin_modifyRoutes(modifyFunction) {
21
21
  }
22
22
  const routerPlugin = (userConfig = {})=>({
23
23
  name: '@modern-js/plugin-router',
24
- registryHooks: {
25
- onAfterCreateRouter: onAfterCreateRouter,
26
- onAfterHydrateRouter: onAfterHydrateRouter,
27
- onBeforeCreateRouter: onBeforeCreateRouter,
28
- modifyRoutes: modifyRoutes,
29
- onBeforeCreateRoutes: onBeforeCreateRoutes,
30
- onBeforeHydrateRouter: onBeforeHydrateRouter
31
- },
24
+ registryHooks: routerProviderRegistryHooks,
32
25
  setup: (api)=>{
33
26
  const routesContainer = {
34
27
  current: []
@@ -216,4 +209,4 @@ function useRouterCreation(props, options) {
216
209
  getBlockNavState
217
210
  ]);
218
211
  }
219
- export { beforeCreateRouter, finalRouteConfig, plugin_modifyRoutes as modifyRoutes, routerPlugin };
212
+ export { beforeCreateRouter, finalRouteConfig, modifyRoutes, routerPlugin };
@@ -8,8 +8,8 @@ import { useContext } from "react";
8
8
  import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
9
9
  import { setServerPayload } from "../../core/context/serverPayload/index.server.mjs";
10
10
  import DeferredDataScripts_node from "./DeferredDataScripts.node.mjs";
11
- import { modifyRoutes, onAfterCreateRouter, onBeforeCreateRouter, onBeforeCreateRoutes } from "./hooks.mjs";
12
11
  import { applyRouterRuntimeState, createRouterServerSnapshot } from "./lifecycle.mjs";
12
+ import { routerProviderRegistryHooks } from "./provider.mjs";
13
13
  import { RSCStaticRouter, createServerPayload, handleRSCRedirect, prepareRSCRoutes } from "./rsc-router.mjs";
14
14
  import { createRouteObjectsFromConfig, renderRoutes, urlJoin } from "./utils.mjs";
15
15
  function createRemixRequest(request) {
@@ -42,12 +42,7 @@ function createReactRouterServerSnapshot(routerContext, basename) {
42
42
  }
43
43
  const routerPlugin = (userConfig = {})=>({
44
44
  name: '@modern-js/plugin-router',
45
- registryHooks: {
46
- onAfterCreateRouter: onAfterCreateRouter,
47
- onBeforeCreateRouter: onBeforeCreateRouter,
48
- modifyRoutes: modifyRoutes,
49
- onBeforeCreateRoutes: onBeforeCreateRoutes
50
- },
45
+ registryHooks: routerProviderRegistryHooks,
51
46
  setup: (api)=>{
52
47
  let finalRouteConfig = {};
53
48
  api.onBeforeRender(async (context, interrupt)=>{
@@ -175,5 +170,5 @@ const routerPlugin = (userConfig = {})=>({
175
170
  });
176
171
  }
177
172
  });
178
- const plugin_node_modifyRoutes = ()=>{};
179
- export { plugin_node_modifyRoutes as modifyRoutes, routerPlugin };
173
+ const modifyRoutes = ()=>{};
174
+ export { modifyRoutes, routerPlugin };
@@ -0,0 +1,57 @@
1
+ import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
2
+ const routerProviderRegistryHooks = {
3
+ modifyRoutes: modifyRoutes,
4
+ onBeforeCreateRoutes: onBeforeCreateRoutes,
5
+ onBeforeCreateRouter: onBeforeCreateRouter,
6
+ onAfterCreateRouter: onAfterCreateRouter,
7
+ onBeforeHydrateRouter: onBeforeHydrateRouter,
8
+ onAfterHydrateRouter: onAfterHydrateRouter
9
+ };
10
+ function reportUnsupportedProviderRegistryHooks(providerPlugin) {
11
+ const unsupportedHookNames = Object.keys(providerPlugin.registryHooks ?? {}).filter((hookName)=>!(hookName in routerProviderRegistryHooks));
12
+ if (unsupportedHookNames.length > 0) console.warn(`[@modern-js/runtime] The router provider "${providerPlugin.name}" declares registry hooks outside the router hook contract: ${unsupportedHookNames.join(', ')}. These hooks are not registered when the provider is resolved through \`runtime.router.framework\` — declare them on a separate runtime plugin instead.`);
13
+ return unsupportedHookNames;
14
+ }
15
+ const REGISTRY_SLOT = Symbol.for('@modern-js/runtime:router-providers:v2');
16
+ function getRegistry() {
17
+ const host = globalThis;
18
+ host[REGISTRY_SLOT] ??= {
19
+ providers: new Map(),
20
+ warnedDuplicates: new Set()
21
+ };
22
+ host[REGISTRY_SLOT].warnedDuplicates ??= new Set();
23
+ return host[REGISTRY_SLOT];
24
+ }
25
+ function registerRouterProvider(name, factory, options = {}) {
26
+ const registry = getRegistry();
27
+ const existing = registry.providers.get(name);
28
+ if (void 0 !== existing) {
29
+ if (existing !== factory && !registry.warnedDuplicates.has(name)) {
30
+ registry.warnedDuplicates.add(name);
31
+ console.warn(`[@modern-js/runtime] The router provider "${name}" was registered more than once with different module instances; keeping the first registration. This usually means two copies of the providing plugin were bundled — for Module Federation, add the provider runtime (e.g. '@modern-js/plugin-tanstack/runtime') to the shared modules of both the host and the remote to deduplicate it.`);
32
+ }
33
+ return;
34
+ }
35
+ if (true !== options.isDefault) {
36
+ if (void 0 !== registry.nonDefaultProvider && registry.nonDefaultProvider !== name) throw new Error(`[@modern-js/runtime] Cannot register router provider "${name}": the competing router provider "${registry.nonDefaultProvider}" is already registered. Only one non-default router provider may be installed at a time — remove one of the router plugins.`);
37
+ registry.nonDefaultProvider = name;
38
+ } else registry.defaultProvider = name;
39
+ registry.providers.set(name, factory);
40
+ }
41
+ function resolveRouterProvider(framework, options = {}) {
42
+ const registry = getRegistry();
43
+ const name = framework || registry.defaultProvider || options.localDefault?.name;
44
+ if (void 0 === name) throw new Error('[@modern-js/runtime] No default router provider is registered. This is a bug in the runtime setup.');
45
+ if (void 0 !== options.localDefault && name === options.localDefault.name) return options.localDefault.factory;
46
+ const factory = registry.providers.get(name);
47
+ if (void 0 !== factory) return factory;
48
+ if ('tanstack' === name) throw new Error("[@modern-js/runtime] `runtime.router.framework` is set to \"tanstack\", but no TanStack router provider is registered. Install @modern-js/plugin-tanstack, add `tanstackRouterPlugin()` to the `plugins` array in modern.config.ts, and make sure '@modern-js/plugin-tanstack/runtime' is imported (e.g. in modern.runtime.ts).");
49
+ throw new Error(`[@modern-js/runtime] Unknown router framework "${name}". Registered providers: ${[
50
+ ...registry.providers.keys()
51
+ ].join(', ') || '(none)'}. Install and register the plugin that provides this router framework.`);
52
+ }
53
+ function unsafe_resetRouterProvidersForTesting() {
54
+ const host = globalThis;
55
+ delete host[REGISTRY_SLOT];
56
+ }
57
+ export { registerRouterProvider, reportUnsupportedProviderRegistryHooks, resolveRouterProvider, routerProviderRegistryHooks, unsafe_resetRouterProvidersForTesting };
@@ -98,7 +98,10 @@ function getRouteObjects(routes, { globalApp, ssrMode, props }) {
98
98
  }
99
99
  routeObjects.push({
100
100
  path: '*',
101
- element: /*#__PURE__*/ jsx(DefaultNotFound, {})
101
+ element: /*#__PURE__*/ jsx(DefaultNotFound, {}),
102
+ loader: ()=>new Response('404', {
103
+ status: 404
104
+ })
102
105
  });
103
106
  return routeObjects;
104
107
  }
@@ -147,17 +150,40 @@ function serializeErrors(errors) {
147
150
  if (!errors) return null;
148
151
  const entries = Object.entries(errors);
149
152
  const serialized = {};
150
- for (const [key, val] of entries)if (isRouteErrorResponse(val)) serialized[key] = {
151
- ...val,
152
- __type: 'RouteErrorResponse'
153
+ for (const [key, val] of entries)if (isRouteErrorResponse(val)) serialized[key] = serializeRouteErrorResponse(val);
154
+ else if (val instanceof Error) serialized[key] = serializeError(val);
155
+ else serialized[key] = val;
156
+ return serialized;
157
+ }
158
+ function shouldRedactServerError() {
159
+ return 'development' !== process.env.NODE_ENV && 'test' !== process.env.NODE_ENV;
160
+ }
161
+ function serializeError(error) {
162
+ if (shouldRedactServerError()) return {
163
+ message: 'Unexpected Server Error',
164
+ stack: void 0,
165
+ __type: 'Error'
153
166
  };
154
- else if (val instanceof Error) serialized[key] = {
155
- message: val.message,
156
- stack: val.stack,
167
+ return {
168
+ message: error.message,
169
+ stack: error.stack,
157
170
  __type: 'Error'
158
171
  };
159
- else serialized[key] = val;
160
- return serialized;
172
+ }
173
+ function serializeRouteErrorResponse(error) {
174
+ if (!isRouteErrorResponse(error)) return error;
175
+ if (error.status >= 500 && shouldRedactServerError()) return {
176
+ status: error.status,
177
+ statusText: 'Internal Server Error',
178
+ data: 'Unexpected Server Error',
179
+ __type: 'RouteErrorResponse'
180
+ };
181
+ return {
182
+ status: error.status,
183
+ statusText: error.statusText,
184
+ data: error.data,
185
+ __type: 'RouteErrorResponse'
186
+ };
161
187
  }
162
188
  function deserializeErrors(errors) {
163
189
  if (!errors) return null;
@@ -197,9 +197,13 @@ function BoundaryDebugger({ controlMode = 'visible', enabledByDefault = false, l
197
197
  enabled ? /*#__PURE__*/ jsx("div", {
198
198
  "aria-hidden": "true",
199
199
  children: boxes.map((box)=>/*#__PURE__*/ jsx("div", {
200
+ "data-modern-boundary-overlay": "",
201
+ "data-modern-boundary-overlay-id": box.id,
202
+ "data-modern-boundary-overlay-label": box.label,
200
203
  style: {
201
204
  border: `2px solid ${box.color}`,
202
205
  borderRadius: 8,
206
+ boxSizing: 'border-box',
203
207
  boxShadow: `0 0 0 1px rgba(255,255,255,.72), 0 6px 20px color-mix(in srgb, ${box.color} 20%, transparent)`,
204
208
  height: box.height,
205
209
  left: box.left,
@@ -3,7 +3,7 @@ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/
3
3
  import { cleanRequireCache, isReact18 as utils_isReact18 } from "@modern-js/utils";
4
4
  import path_0 from "path";
5
5
  import { documentPlugin } from "../document/cli/index.mjs";
6
- import { getEntrypointRoutesDir, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin } from "../router/cli/index.mjs";
6
+ import { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin } from "../router/cli/index.mjs";
7
7
  import { builderPluginAlias } from "./alias.mjs";
8
8
  import { generateCode } from "./code.mjs";
9
9
  import { ENTRY_BOOTSTRAP_FILE_NAME, ENTRY_POINT_FILE_NAME } from "./constants.mjs";
@@ -91,5 +91,7 @@ const runtimePlugin = (params)=>({
91
91
  }
92
92
  });
93
93
  const cli = runtimePlugin;
94
+ export { makeLegalIdentifier } from "../router/cli/code/makeLegalIdentifier.mjs";
95
+ export { getPathWithoutExt } from "../router/cli/code/utils.mjs";
94
96
  export default cli;
95
- export { documentPlugin, getEntrypointRoutesDir, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin };
97
+ export { documentPlugin, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin };
@@ -0,0 +1,29 @@
1
+ import "node:module";
2
+ const EXTENSIONS_SLOT = Symbol.for('@modern-js/runtime:context-extensions');
3
+ function getStore(context) {
4
+ return context[EXTENSIONS_SLOT];
5
+ }
6
+ function ensureStore(context) {
7
+ const target = context;
8
+ target[EXTENSIONS_SLOT] ??= new Map();
9
+ return target[EXTENSIONS_SLOT];
10
+ }
11
+ function stripRuntimeContextExtensions(context) {
12
+ delete context[EXTENSIONS_SLOT];
13
+ }
14
+ function createRuntimeContextExtension(id) {
15
+ const key = Symbol.for(`@modern-js/runtime:context-extension:${id}`);
16
+ return {
17
+ key,
18
+ get (context) {
19
+ return getStore(context)?.get(key);
20
+ },
21
+ set (context, value) {
22
+ ensureStore(context).set(key, value);
23
+ },
24
+ remove (context) {
25
+ getStore(context)?.delete(key);
26
+ }
27
+ };
28
+ }
29
+ export { createRuntimeContextExtension, stripRuntimeContextExtensions };
@@ -0,0 +1,14 @@
1
+ import "node:module";
2
+ import { createRuntimeContextExtension } from "./extensions.mjs";
3
+ const helmetContextExtension = createRuntimeContextExtension('@modern-js/runtime:helmet-context');
4
+ function getHelmetContext(context) {
5
+ return helmetContextExtension.get(context);
6
+ }
7
+ function ensureHelmetContext(context) {
8
+ const existing = helmetContextExtension.get(context);
9
+ if (void 0 !== existing) return existing;
10
+ const created = {};
11
+ helmetContextExtension.set(context, created);
12
+ return created;
13
+ }
14
+ export { ensureHelmetContext, getHelmetContext };
@@ -41,6 +41,11 @@ function getGlobalLayoutApp() {
41
41
  function getGlobalBasename() {
42
42
  return globalContext.basename;
43
43
  }
44
+ export { DefaultNotFound } from "../../router/runtime/DefaultNotFound.mjs";
45
+ export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "../../router/runtime/hooks.mjs";
46
+ export { applyRouterRuntimeState, applyRouterServerPrepareResult, cleanupRouterRuntimeState, createRouterRuntimeState, createRouterServerSnapshot, getRouterHydrationScripts, getRouterMatchedRouteIds, getRouterRuntimeState, getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
47
+ export { registerRouterProvider, resolveRouterProvider, routerProviderRegistryHooks } from "../../router/runtime/provider.mjs";
48
+ export { createRuntimeContextExtension } from "./extensions.mjs";
44
49
  export { InternalRuntimeContext, RuntimeContext, getInitialContext } from "./runtime.mjs";
45
50
  export { getServerPayload, setServerPayload } from "./serverPayload/index.mjs";
46
51
  export { getCurrentEntryName, getGlobalApp, getGlobalBasename, getGlobalEnableRsc, getGlobalInternalRuntimeContext, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRSCRoot, getGlobalRoutes, setGlobalContext, setGlobalInternalRuntimeContext };
@@ -2,24 +2,26 @@ import "node:module";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { HelmetProvider } from "react-helmet-async";
4
4
  import { InternalRuntimeContext, RuntimeContext } from "../context/index.mjs";
5
+ import { stripRuntimeContextExtensions } from "../context/extensions.mjs";
6
+ import { ensureHelmetContext } from "../context/helmetContext.mjs";
5
7
  function wrapRuntimeContextProvider(App, contextValue) {
6
- const { isBrowser, initialData, routes, routerFramework, context, routeManifest, routerRuntime, routerInstance, routerHydrationScript, routerMatchedRouteIds, routerServerSnapshot, routerContext, unstable_getBlockNavState, ssrContext, _internalContext, _internalRouterBaseName, _helmetContext, ...rest } = contextValue;
8
+ const { isBrowser, initialData, routes, context, routeManifest, routerContext, unstable_getBlockNavState, ssrContext, _internalContext, _internalRouterBaseName, ...rest } = contextValue;
7
9
  const internalContextValue = contextValue;
8
- internalContextValue._helmetContext ??= {};
10
+ const helmetContext = ensureHelmetContext(internalContextValue);
9
11
  const runtimeContextValue = {
10
12
  isBrowser,
11
13
  initialData,
12
14
  routes,
13
- routerFramework,
14
15
  context,
15
16
  ...rest
16
17
  };
18
+ stripRuntimeContextExtensions(runtimeContextValue);
17
19
  return /*#__PURE__*/ jsx(InternalRuntimeContext.Provider, {
18
20
  value: internalContextValue,
19
21
  children: /*#__PURE__*/ jsx(RuntimeContext.Provider, {
20
22
  value: runtimeContextValue,
21
23
  children: /*#__PURE__*/ jsx(HelmetProvider, {
22
- context: internalContextValue._helmetContext,
24
+ context: helmetContext,
23
25
  children: App
24
26
  })
25
27
  })
@@ -1,4 +1,5 @@
1
1
  import "node:module";
2
+ import { getHelmetContext } from "../context/helmetContext.mjs";
2
3
  import { safeReplace } from "./utils.mjs";
3
4
  const EOL = '\n';
4
5
  const RE_HTML_ATTR = /<html[^>]*>/;
@@ -7,7 +8,7 @@ const RE_LAST_IN_HEAD = /<\/head>/;
7
8
  const RE_TITLE = /<title[^>]*>([\s\S\n\r]*?)<\/title>/;
8
9
  const TEST_TITLE_CONTENT = /(?<=<title[^>]*>)([\s\S\n\r]*?)([.|\S])([\s\S\n\r]*?)(?=<\/title>)/;
9
10
  function getHelmetData(runtimeContext) {
10
- return runtimeContext._helmetContext?.helmet ?? void 0;
11
+ return getHelmetContext(runtimeContext)?.helmet ?? void 0;
11
12
  }
12
13
  function createReplaceHelemt(helmetData) {
13
14
  return helmetData ? (template)=>helmetReplace(template, helmetData) : (tempalte)=>tempalte;
@@ -3,13 +3,14 @@ import { jsx } from "react/jsx-runtime";
3
3
  import { storage } from "@modern-js/runtime-utils/node";
4
4
  import { getPathname, parseCookie, parseHeaders, parseQuery } from "@modern-js/runtime-utils/universal/request";
5
5
  import react, { Fragment } from "react";
6
- import { cleanupRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
6
+ import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
7
7
  import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
8
8
  import { getGlobalInternalRuntimeContext, getGlobalRSCRoot } from "../context/index.mjs";
9
9
  import { getInitialContext } from "../context/runtime.mjs";
10
10
  import { getServerPayload } from "../context/serverPayload/index.mjs";
11
11
  import { createRoot } from "../react/index.mjs";
12
12
  import { CHUNK_CSS_PLACEHOLDER } from "./constants.mjs";
13
+ import { withRouterCleanup } from "./routerCleanup.mjs";
13
14
  import { SSRErrors } from "./tracer.mjs";
14
15
  import { getSSRConfigByEntry, getSSRMode } from "./utils.mjs";
15
16
  async function handleRSCRequest(request, Root, context, options, handleRequest) {
@@ -38,6 +39,39 @@ const processRedirect = (headers, status, ctx)=>{
38
39
  headers
39
40
  });
40
41
  };
42
+ const applyRouterSnapshotResult = (context, onError)=>{
43
+ const routerServerSnapshot = getRouterServerSnapshot(context);
44
+ const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
45
+ if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
46
+ const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
47
+ if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
48
+ };
49
+ const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
50
+ if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
51
+ if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
52
+ const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
53
+ return processRedirect(new Headers({
54
+ Location: redirectUrl
55
+ }), beforeRenderResult.status, redirectCtx);
56
+ };
57
+ const renderRequest = async (request, Root, context, options, handleRequest, enableRsc)=>{
58
+ if (enableRsc) return handleRSCRequest(request, Root, context, options, handleRequest);
59
+ return handleRequest(request, Root, {
60
+ ...options,
61
+ runtimeContext: context
62
+ });
63
+ };
64
+ const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
65
+ if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
66
+ Object.entries(responseProxy.headers).forEach(([key, value])=>{
67
+ response.headers.set(key, value);
68
+ });
69
+ if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(response.body, {
70
+ status: responseProxy.status,
71
+ headers: response.headers
72
+ }));
73
+ return routerCleanup.deferUntilBodyDone(response);
74
+ };
41
75
  function createSSRContext(request, options) {
42
76
  const { config, loaderContext, onError, onTiming, locals, resource, params, responseProxy, reporter } = options;
43
77
  const { nonce, useJsonScript } = config;
@@ -133,41 +167,20 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
133
167
  isRSCNavigation: 'true' === request.headers.get('x-rsc-tree'),
134
168
  basename: ssrContext.baseUrl || '/'
135
169
  };
136
- try {
170
+ return withRouterCleanup(context, options.onError, async (routerCleanup)=>{
137
171
  const beforeRenderResult = await runBeforeRender(context);
138
- const routerServerSnapshot = context.routerServerSnapshot;
139
- const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
140
- if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
141
- const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
142
- if (errors.length > 0) options.onError(errors[0], SSRErrors.LOADER_ERROR);
143
- if ("u" > typeof Response && beforeRenderResult instanceof Response && isRedirectStatus(beforeRenderResult.status)) {
144
- if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
145
- const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
146
- return processRedirect(new Headers({
147
- Location: redirectUrl
148
- }), beforeRenderResult.status, redirectCtx);
172
+ applyRouterSnapshotResult(context, options.onError);
173
+ if ("u" > typeof Response) {
174
+ const redirectResponse = createLoaderRedirectResponse(beforeRenderResult, redirectCtx);
175
+ if (redirectResponse) return redirectResponse;
149
176
  }
150
177
  if (!createRequestOptions?.enableRsc) {
151
178
  const { htmlTemplate } = options.resource;
152
179
  options.resource.htmlTemplate = htmlTemplate.replace('</head>', `${CHUNK_CSS_PLACEHOLDER}</head>`);
153
180
  }
154
- let response;
155
- response = createRequestOptions?.enableRsc ? await handleRSCRequest(request, Root, context, options, handleRequest) : await handleRequest(request, Root, {
156
- ...options,
157
- runtimeContext: context
158
- });
159
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
160
- Object.entries(responseProxy.headers).forEach(([key, value])=>{
161
- response.headers.set(key, value);
162
- });
163
- if (-1 !== responseProxy.status) return new Response(response.body, {
164
- status: responseProxy.status,
165
- headers: response.headers
166
- });
167
- return response;
168
- } finally{
169
- await cleanupRouterRuntimeState(context);
170
- }
181
+ const response = await renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc);
182
+ return finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup);
183
+ });
171
184
  });
172
185
  };
173
186
  return requestHandler;
@@ -0,0 +1,67 @@
1
+ import "node:module";
2
+ import { getRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
3
+ const ROUTER_CLEANUP_ERROR = 'An error occurs during router runtime cleanup';
4
+ async function withRouterCleanup(runtimeContext, onError, callback) {
5
+ const routerCleanup = createRouterCleanup(runtimeContext, onError);
6
+ try {
7
+ return await callback(routerCleanup);
8
+ } finally{
9
+ if (!routerCleanup.deferred) await routerCleanup.run();
10
+ }
11
+ }
12
+ function createRouterCleanup(runtimeContext, onError) {
13
+ let deferred = false;
14
+ let finished = false;
15
+ const run = async ()=>{
16
+ if (finished) return;
17
+ finished = true;
18
+ try {
19
+ await getRouterRuntimeState(runtimeContext)?.cleanup?.();
20
+ } catch (error) {
21
+ onError(error, ROUTER_CLEANUP_ERROR);
22
+ }
23
+ };
24
+ const deferUntilBodyDone = (response)=>{
25
+ const { body } = response;
26
+ if (!body || body.locked) return response;
27
+ deferred = true;
28
+ const reader = body.getReader();
29
+ const wrappedBody = new ReadableStream({
30
+ async pull (controller) {
31
+ let result;
32
+ try {
33
+ result = await reader.read();
34
+ } catch (error) {
35
+ controller.error(error);
36
+ await run();
37
+ return;
38
+ }
39
+ if (result.done) {
40
+ controller.close();
41
+ await run();
42
+ return;
43
+ }
44
+ controller.enqueue(result.value);
45
+ },
46
+ async cancel (reason) {
47
+ try {
48
+ await reader.cancel(reason);
49
+ } catch {}
50
+ await run();
51
+ }
52
+ });
53
+ return new Response(wrappedBody, {
54
+ status: response.status,
55
+ statusText: response.statusText,
56
+ headers: response.headers
57
+ });
58
+ };
59
+ return {
60
+ get deferred () {
61
+ return deferred;
62
+ },
63
+ run,
64
+ deferUntilBodyDone
65
+ };
66
+ }
67
+ export { ROUTER_CLEANUP_ERROR, createRouterCleanup, withRouterCleanup };