@farm.js/core 0.1.0-beta.3 → 0.1.0-beta.5

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 (193) hide show
  1. package/dist/agent-runtime.d.mts +2 -1
  2. package/dist/agent-runtime.d.ts +2 -1
  3. package/dist/api/route-manager.cjs +313 -10
  4. package/dist/api/route-manager.cjs.map +1 -1
  5. package/dist/api/route-manager.d.mts +3 -2
  6. package/dist/api/route-manager.d.ts +3 -2
  7. package/dist/api/route-manager.mjs +6 -5
  8. package/dist/api/runtime.cjs +313 -10
  9. package/dist/api/runtime.cjs.map +1 -1
  10. package/dist/api/runtime.d.mts +2 -1
  11. package/dist/api/runtime.d.ts +2 -1
  12. package/dist/api/runtime.mjs +4 -3
  13. package/dist/api.cjs +642 -57
  14. package/dist/api.cjs.map +1 -1
  15. package/dist/api.d.mts +3 -2
  16. package/dist/api.d.ts +3 -2
  17. package/dist/api.mjs +29 -9
  18. package/dist/{app-DOKxo-LH.d.ts → app-BjN-da13.d.ts} +38 -3
  19. package/dist/{app-BB3Iu3xh.d.mts → app-CakAr8Be.d.mts} +38 -3
  20. package/dist/app-markdown.d.mts +2 -1
  21. package/dist/app-markdown.d.ts +2 -1
  22. package/dist/cache.cjs +395 -12
  23. package/dist/cache.cjs.map +1 -1
  24. package/dist/cache.d.mts +100 -6
  25. package/dist/cache.d.ts +100 -6
  26. package/dist/cache.mjs +8 -2
  27. package/dist/{chunk-XUBZ7JI4.mjs → chunk-2CUKEMVR.mjs} +187 -16
  28. package/dist/chunk-2CUKEMVR.mjs.map +1 -0
  29. package/dist/{chunk-OHC6VCDI.mjs → chunk-2NHCNRF6.mjs} +521 -42
  30. package/dist/chunk-2NHCNRF6.mjs.map +1 -0
  31. package/dist/{chunk-6WXJ54TC.mjs → chunk-65A7QIKI.mjs} +5 -5
  32. package/dist/{chunk-6WXJ54TC.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
  33. package/dist/{chunk-5QH4IKY3.mjs → chunk-7N62DNSO.mjs} +2 -2
  34. package/dist/{chunk-XJSHJN4M.mjs → chunk-A2LUXHD2.mjs} +593 -49
  35. package/dist/chunk-A2LUXHD2.mjs.map +1 -0
  36. package/dist/chunk-ALCLXXTY.mjs +187 -0
  37. package/dist/chunk-ALCLXXTY.mjs.map +1 -0
  38. package/dist/{chunk-CSU4KJJF.mjs → chunk-C2ROET2V.mjs} +2 -2
  39. package/dist/{chunk-JNYVN7YP.mjs → chunk-EEABSBKK.mjs} +2 -2
  40. package/dist/{chunk-JNYVN7YP.mjs.map → chunk-EEABSBKK.mjs.map} +1 -1
  41. package/dist/{chunk-BIOIOWXZ.mjs → chunk-HNIQFZKB.mjs} +2 -2
  42. package/dist/{chunk-MH6FKW2I.mjs → chunk-J5YWQVI5.mjs} +4 -4
  43. package/dist/chunk-J5YWQVI5.mjs.map +1 -0
  44. package/dist/{chunk-G5I34UA6.mjs → chunk-JDEOUK5V.mjs} +4 -4
  45. package/dist/{chunk-T543TMFY.mjs → chunk-NM3CRAAL.mjs} +3 -2
  46. package/dist/chunk-NM3CRAAL.mjs.map +1 -0
  47. package/dist/{chunk-LWMGIEJA.mjs → chunk-PFE6GMNE.mjs} +47 -37
  48. package/dist/chunk-PFE6GMNE.mjs.map +1 -0
  49. package/dist/{chunk-6VS6CKAV.mjs → chunk-QM746KUO.mjs} +8 -1
  50. package/dist/chunk-QM746KUO.mjs.map +1 -0
  51. package/dist/{chunk-5FW6PQ3J.mjs → chunk-QTZZ2ISQ.mjs} +41 -16
  52. package/dist/chunk-QTZZ2ISQ.mjs.map +1 -0
  53. package/dist/{chunk-SHRJG6OG.mjs → chunk-RBRLLZL5.mjs} +18 -3
  54. package/dist/chunk-RBRLLZL5.mjs.map +1 -0
  55. package/dist/{chunk-NRRFGX45.mjs → chunk-TQAEEJB4.mjs} +3 -3
  56. package/dist/{chunk-45LKHSHJ.mjs → chunk-UB5UOSHB.mjs} +24 -12
  57. package/dist/chunk-UB5UOSHB.mjs.map +1 -0
  58. package/dist/chunk-V3XURYJO.mjs +756 -0
  59. package/dist/chunk-V3XURYJO.mjs.map +1 -0
  60. package/dist/{chunk-HZYXGV4K.mjs → chunk-VY2UYN5R.mjs} +24 -4
  61. package/dist/chunk-VY2UYN5R.mjs.map +1 -0
  62. package/dist/{chunk-C33RALN7.mjs → chunk-W2CRQFF6.mjs} +79 -15
  63. package/dist/chunk-W2CRQFF6.mjs.map +1 -0
  64. package/dist/{chunk-LG3YINQN.mjs → chunk-Z5CQMP54.mjs} +3 -3
  65. package/dist/{client-DiViK9yK.d.mts → client-BT1mFQas.d.mts} +23 -4
  66. package/dist/{client-DpEBJbts.d.ts → client-Nn0q4eO4.d.ts} +23 -4
  67. package/dist/{client-plugins-CTnsZz_A.d.ts → client-plugins-Cw4qUGsw.d.ts} +6 -0
  68. package/dist/{client-plugins-Cnr0D3kk.d.mts → client-plugins-DQQ1adXM.d.mts} +6 -0
  69. package/dist/client-plugins.d.mts +2 -1
  70. package/dist/client-plugins.d.ts +2 -1
  71. package/dist/client.cjs +665 -82
  72. package/dist/client.cjs.map +1 -1
  73. package/dist/client.d.mts +71 -5
  74. package/dist/client.d.ts +71 -5
  75. package/dist/client.mjs +10 -7
  76. package/dist/config.d.mts +2 -1
  77. package/dist/config.d.ts +2 -1
  78. package/dist/{devtools-HE4FTUDN.mjs → devtools-LVC3VB5P.mjs} +4 -4
  79. package/dist/docs.cjs +11 -1
  80. package/dist/docs.cjs.map +1 -1
  81. package/dist/docs.mjs +4 -4
  82. package/dist/index.cjs +2113 -198
  83. package/dist/index.cjs.map +1 -1
  84. package/dist/index.d.mts +16 -16
  85. package/dist/index.d.ts +16 -16
  86. package/dist/index.mjs +49 -21
  87. package/dist/index.mjs.map +1 -1
  88. package/dist/integrations.d.mts +2 -1
  89. package/dist/integrations.d.ts +2 -1
  90. package/dist/internal/build-runtime.cjs +1455 -90
  91. package/dist/internal/build-runtime.cjs.map +1 -1
  92. package/dist/internal/build-runtime.d.mts +4 -3
  93. package/dist/internal/build-runtime.d.ts +4 -3
  94. package/dist/internal/build-runtime.mjs +15 -14
  95. package/dist/internal/config-runtime.cjs +12 -1
  96. package/dist/internal/config-runtime.cjs.map +1 -1
  97. package/dist/internal/config-runtime.d.mts +3 -2
  98. package/dist/internal/config-runtime.d.ts +3 -2
  99. package/dist/internal/config-runtime.mjs +3 -3
  100. package/dist/internal/production-runtime.cjs +282 -6
  101. package/dist/internal/production-runtime.cjs.map +1 -1
  102. package/dist/internal/production-runtime.d.mts +4 -4
  103. package/dist/internal/production-runtime.d.ts +4 -4
  104. package/dist/internal/production-runtime.mjs +4 -2
  105. package/dist/{metadata-eoVmHoyv.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
  106. package/dist/{metadata-Dp8AdvsB.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
  107. package/dist/middleware.d.mts +4 -3
  108. package/dist/middleware.d.ts +4 -3
  109. package/dist/navigation.cjs +40 -15
  110. package/dist/navigation.cjs.map +1 -1
  111. package/dist/navigation.mjs +2 -2
  112. package/dist/plugin.cjs +913 -53
  113. package/dist/plugin.cjs.map +1 -1
  114. package/dist/plugin.d.mts +2 -1
  115. package/dist/plugin.d.ts +2 -1
  116. package/dist/plugin.mjs +11 -10
  117. package/dist/{production-runtime-BqTnUTai.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
  118. package/dist/{production-runtime-DtDdG9fc.d.mts → production-runtime-DPfgMV9Y.d.mts} +1 -1
  119. package/dist/routes.cjs +276 -6
  120. package/dist/routes.cjs.map +1 -1
  121. package/dist/routes.d.mts +1 -1
  122. package/dist/routes.d.ts +1 -1
  123. package/dist/routes.mjs +3 -3
  124. package/dist/{runtime-C1B7pSGT.d.mts → runtime-9nQjVM7X.d.mts} +8 -9
  125. package/dist/{runtime-CdPHt0bv.d.ts → runtime-DgeS2skB.d.ts} +8 -9
  126. package/dist/server-action-security.cjs +28 -10
  127. package/dist/server-action-security.cjs.map +1 -1
  128. package/dist/server-action-security.d.mts +2 -1
  129. package/dist/server-action-security.d.ts +2 -1
  130. package/dist/server-action-security.mjs +2 -2
  131. package/dist/server-fn-client.d.mts +1 -0
  132. package/dist/server-fn-client.d.ts +1 -0
  133. package/dist/server-fn.cjs +785 -3
  134. package/dist/server-fn.cjs.map +1 -1
  135. package/dist/server-fn.d.mts +10 -1
  136. package/dist/server-fn.d.ts +10 -1
  137. package/dist/server-fn.mjs +6 -3
  138. package/dist/server-plugins.d.mts +3 -2
  139. package/dist/server-plugins.d.ts +3 -2
  140. package/dist/server-query-client.cjs +279 -8
  141. package/dist/server-query-client.cjs.map +1 -1
  142. package/dist/server-query-client.mjs +4 -4
  143. package/dist/server-query.cjs +381 -10
  144. package/dist/server-query.cjs.map +1 -1
  145. package/dist/server-query.mjs +5 -5
  146. package/dist/server.cjs +1086 -76
  147. package/dist/server.cjs.map +1 -1
  148. package/dist/server.d.mts +8 -7
  149. package/dist/server.d.ts +8 -7
  150. package/dist/server.mjs +31 -16
  151. package/dist/server.mjs.map +1 -1
  152. package/dist/testing.cjs +341 -20
  153. package/dist/testing.cjs.map +1 -1
  154. package/dist/testing.d.mts +3 -2
  155. package/dist/testing.d.ts +3 -2
  156. package/dist/testing.mjs +7 -6
  157. package/dist/testing.mjs.map +1 -1
  158. package/dist/transport-BmbGTXA5.d.mts +49 -0
  159. package/dist/transport-BmbGTXA5.d.ts +49 -0
  160. package/dist/{utils-8USa5BiY.d.mts → utils-CHXlMDkg.d.mts} +1 -1
  161. package/dist/{utils-DKJb6K6G.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
  162. package/dist/version.cjs +1 -1
  163. package/dist/version.cjs.map +1 -1
  164. package/dist/version.mjs +1 -1
  165. package/dist/vite.cjs +914 -54
  166. package/dist/vite.cjs.map +1 -1
  167. package/dist/vite.d.mts +2 -1
  168. package/dist/vite.d.ts +2 -1
  169. package/dist/vite.mjs +11 -10
  170. package/package.json +1 -1
  171. package/types/api.d.ts +44 -0
  172. package/types/client.d.ts +85 -4
  173. package/dist/chunk-45LKHSHJ.mjs.map +0 -1
  174. package/dist/chunk-5FW6PQ3J.mjs.map +0 -1
  175. package/dist/chunk-6VS6CKAV.mjs.map +0 -1
  176. package/dist/chunk-C33RALN7.mjs.map +0 -1
  177. package/dist/chunk-GZWT6VI5.mjs +0 -382
  178. package/dist/chunk-GZWT6VI5.mjs.map +0 -1
  179. package/dist/chunk-HZYXGV4K.mjs.map +0 -1
  180. package/dist/chunk-LWMGIEJA.mjs.map +0 -1
  181. package/dist/chunk-MH6FKW2I.mjs.map +0 -1
  182. package/dist/chunk-OHC6VCDI.mjs.map +0 -1
  183. package/dist/chunk-SHRJG6OG.mjs.map +0 -1
  184. package/dist/chunk-T543TMFY.mjs.map +0 -1
  185. package/dist/chunk-XJSHJN4M.mjs.map +0 -1
  186. package/dist/chunk-XUBZ7JI4.mjs.map +0 -1
  187. /package/dist/{chunk-5QH4IKY3.mjs.map → chunk-7N62DNSO.mjs.map} +0 -0
  188. /package/dist/{chunk-CSU4KJJF.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
  189. /package/dist/{chunk-BIOIOWXZ.mjs.map → chunk-HNIQFZKB.mjs.map} +0 -0
  190. /package/dist/{chunk-G5I34UA6.mjs.map → chunk-JDEOUK5V.mjs.map} +0 -0
  191. /package/dist/{chunk-NRRFGX45.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
  192. /package/dist/{chunk-LG3YINQN.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
  193. /package/dist/{devtools-HE4FTUDN.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
@@ -9,7 +9,7 @@ import {
9
9
  FARM_DOCS_LAST_MODIFIED_MANIFEST,
10
10
  createFarmDocsLastModifiedManifest,
11
11
  getFarmDocsRouteTypeEntries
12
- } from "./chunk-BIOIOWXZ.mjs";
12
+ } from "./chunk-HNIQFZKB.mjs";
13
13
  import {
14
14
  generateFarmDocsSearchClientRuntime,
15
15
  isFarmDocsSearchEnabled,
@@ -17,11 +17,11 @@ import {
17
17
  } from "./chunk-V7RBCSDJ.mjs";
18
18
  import {
19
19
  mergeFarmViteConfig
20
- } from "./chunk-6VS6CKAV.mjs";
20
+ } from "./chunk-QM746KUO.mjs";
21
21
  import {
22
22
  hasCustomFarmRouteContext,
23
23
  resolveDeployOutputPath
24
- } from "./chunk-T543TMFY.mjs";
24
+ } from "./chunk-NM3CRAAL.mjs";
25
25
  import {
26
26
  PluginManager
27
27
  } from "./chunk-C3DLZMBU.mjs";
@@ -31,7 +31,7 @@ import {
31
31
  generateFarmTypeArtifacts,
32
32
  getClientModuleMetadata,
33
33
  resolveRouteRenderingConfigFromFile
34
- } from "./chunk-XJSHJN4M.mjs";
34
+ } from "./chunk-A2LUXHD2.mjs";
35
35
  import {
36
36
  farmEnvironmentFunctionsPlugin
37
37
  } from "./chunk-V6WE6JSZ.mjs";
@@ -59,7 +59,7 @@ import {
59
59
  } from "./chunk-K4667E2Q.mjs";
60
60
  import {
61
61
  APIRouteManager
62
- } from "./chunk-LG3YINQN.mjs";
62
+ } from "./chunk-Z5CQMP54.mjs";
63
63
  import {
64
64
  readFarmI18nCatalogs
65
65
  } from "./chunk-2ED5Q2GH.mjs";
@@ -749,6 +749,18 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
749
749
  ...isFarmMarkdownPageFile(entry.modulePath) ? { source: readFileSync(entry.modulePath, "utf8") } : {}
750
750
  });
751
751
  }
752
+ const routeSlots = Array.from(
753
+ routeManager.getRouteSlots().values(),
754
+ (entry) => ({
755
+ name: entry.name,
756
+ ownerPattern: entry.ownerPattern,
757
+ pattern: entry.pattern,
758
+ modulePath: entry.modulePath,
759
+ containerId: entry.containerId,
760
+ interception: entry.interception,
761
+ fallback: entry.fallback
762
+ })
763
+ );
752
764
  logger.info(`\u{1F4CB} Found ${pageRoutes.length} page routes`);
753
765
  const fs = await import("fs/promises");
754
766
  const layoutRoutes = [];
@@ -792,7 +804,16 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
792
804
  logger.info("\u{1F4E6} Building client and SSR bundles in parallel...");
793
805
  const [clientBuildResult, ssrBuildResult] = await Promise.allSettled([
794
806
  // Client build (to disk)
795
- buildClient(productionVite, config, root, srcDir, clientOutputDir, pageRoutes, layoutRoutes),
807
+ buildClient(
808
+ productionVite,
809
+ config,
810
+ root,
811
+ srcDir,
812
+ clientOutputDir,
813
+ pageRoutes,
814
+ layoutRoutes,
815
+ routeSlots
816
+ ),
796
817
  // SSR build (in memory)
797
818
  buildSSRInMemory(
798
819
  productionVite,
@@ -803,7 +824,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
803
824
  serverRenderer,
804
825
  preset,
805
826
  pageRoutes,
806
- layoutRoutes
827
+ layoutRoutes,
828
+ routeSlots
807
829
  )
808
830
  ]);
809
831
  const [routeRuntimeManifestResult] = await routeRuntimeManifestResultPromise;
@@ -823,7 +845,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
823
845
  srcDir,
824
846
  clientOutputDir,
825
847
  pageRoutes,
826
- layoutRoutes
848
+ layoutRoutes,
849
+ routeSlots
827
850
  );
828
851
  }
829
852
  const ssrResult = ssrBuildResult.value;
@@ -926,7 +949,7 @@ async function validateClientBuildOutput(root, srcDir, outputDir) {
926
949
  }
927
950
  }
928
951
  __name(validateClientBuildOutput, "validateClientBuildOutput");
929
- async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = []) {
952
+ async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = []) {
930
953
  const viteBuild = productionVite.build;
931
954
  const { farmPlugin } = await import("./vite.mjs");
932
955
  const { PluginManager: PluginManager2 } = await import("./plugin.mjs");
@@ -953,8 +976,16 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
953
976
  logger.warn(`\u26A0\uFE0F Could not inspect route file ${route.modulePath}: ${error}`);
954
977
  }
955
978
  }
979
+ const clientRouteSlots = routeSlots.filter((slot) => {
980
+ try {
981
+ return getClientModuleMetadata(slot.modulePath, root).shouldHydrate;
982
+ } catch (error) {
983
+ logger.warn(`\u26A0\uFE0F Could not inspect route slot ${slot.modulePath}: ${error}`);
984
+ return false;
985
+ }
986
+ });
956
987
  logger.info(
957
- `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} out of ${pageRoutes.length} pages`
988
+ `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} pages and ${clientRouteSlots.length} slots`
958
989
  );
959
990
  const clientEntryRoot = path3.join(root, ".farm", "tmp");
960
991
  await fs.mkdir(clientEntryRoot, { recursive: true });
@@ -963,6 +994,7 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
963
994
  const clientHydrationCode = generateClientHydrationEntry(
964
995
  clientPages,
965
996
  layoutRoutes,
997
+ clientRouteSlots,
966
998
  root,
967
999
  srcDir,
968
1000
  isFarmDocsSearchEnabled(config.docs),
@@ -1295,7 +1327,7 @@ function generateUniversalRouterStateProperties() {
1295
1327
  `.trim();
1296
1328
  }
1297
1329
  __name(generateUniversalRouterStateProperties, "generateUniversalRouterStateProperties");
1298
- function generateClientHydrationEntry(clientPages, layoutRoutes, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
1330
+ function generateClientHydrationEntry(clientPages, layoutRoutes, clientRouteSlots, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
1299
1331
  enabled: false,
1300
1332
  locales: ["en"],
1301
1333
  defaultLocale: "en",
@@ -1363,7 +1395,7 @@ function isFarmLocaleDocumentChange() {
1363
1395
  return false;
1364
1396
  }
1365
1397
  `;
1366
- if (clientPages.length === 0) {
1398
+ if (clientPages.length === 0 && clientRouteSlots.length === 0) {
1367
1399
  return `
1368
1400
  // Farm.js Client Runtime (no client components)
1369
1401
  ${cssImport}
@@ -1613,11 +1645,25 @@ document.addEventListener("click", function(e) {
1613
1645
  }
1614
1646
  const imports = [];
1615
1647
  const routeEntries = [];
1648
+ const routeSlotEntries = [];
1616
1649
  clientPages.forEach((page, index) => {
1617
1650
  const importPath = toImportPath(page.modulePath);
1618
1651
  imports.push(`import Page${index} from "${importPath}";`);
1619
1652
  routeEntries.push(` { pattern: ${JSON.stringify(page.pattern)}, Component: Page${index} }`);
1620
1653
  });
1654
+ clientRouteSlots.forEach((slot, index) => {
1655
+ const importPath = toImportPath(slot.modulePath);
1656
+ imports.push(`import RouteSlot${index} from "${importPath}";`);
1657
+ routeSlotEntries.push(` {
1658
+ name: ${JSON.stringify(slot.name)},
1659
+ ownerPattern: ${JSON.stringify(slot.ownerPattern)},
1660
+ pattern: ${JSON.stringify(slot.pattern)},
1661
+ containerId: ${JSON.stringify(slot.containerId)},
1662
+ interception: ${JSON.stringify(slot.interception)},
1663
+ fallback: ${JSON.stringify(slot.fallback)},
1664
+ Component: RouteSlot${index},
1665
+ }`);
1666
+ });
1621
1667
  return `
1622
1668
  // Farm.js Client Runtime - SPA with Hydration
1623
1669
  ${cssImport}
@@ -1639,6 +1685,10 @@ const clientRoutes = [
1639
1685
  ${routeEntries.join(",\n")}
1640
1686
  ];
1641
1687
 
1688
+ const clientRouteSlots = [
1689
+ ${routeSlotEntries.join(",\n")}
1690
+ ];
1691
+
1642
1692
  // Layout routes for wrapping client components
1643
1693
  const layoutRoutes = [
1644
1694
  ${layoutRegistrations.join(",\n")}
@@ -1693,6 +1743,146 @@ function matchRoute(pathname) {
1693
1743
  return null;
1694
1744
  }
1695
1745
 
1746
+ function matchesRoutePrefix(pathname, pattern) {
1747
+ if (pattern === "/") return true;
1748
+ const pathSegments = getFarmRoutePathname(pathname).split("/").filter(Boolean);
1749
+ const patternSegments = pattern.split("/").filter(Boolean);
1750
+ if (patternSegments.length > pathSegments.length) return false;
1751
+ const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
1752
+ return matchFarmRoute(pattern, candidate) !== null;
1753
+ }
1754
+
1755
+ function matchInterceptedRouteSlot(pathname, from) {
1756
+ for (const slot of clientRouteSlots) {
1757
+ if (!slot.interception || !matchesRoutePrefix(from, slot.ownerPattern)) continue;
1758
+ const params = matchFarmRoute(slot.pattern, getFarmRoutePathname(pathname));
1759
+ if (params !== null) return { slot: slot, params: params };
1760
+ }
1761
+ return null;
1762
+ }
1763
+
1764
+ function routeSlotKey(slot) {
1765
+ return slot.ownerPattern + ":" + slot.name;
1766
+ }
1767
+
1768
+ function findClientRouteSlot(slot) {
1769
+ return clientRouteSlots.find(function(candidate) {
1770
+ return candidate.name === slot.name &&
1771
+ candidate.ownerPattern === slot.ownerPattern &&
1772
+ candidate.pattern === slot.pattern &&
1773
+ candidate.interception === slot.interception &&
1774
+ candidate.fallback === slot.fallback;
1775
+ });
1776
+ }
1777
+
1778
+ function readRouteSlotPayload(doc) {
1779
+ const script = doc.getElementById("__farm_route_slots_data__");
1780
+ if (!script?.textContent) return [];
1781
+ try {
1782
+ const parsed = JSON.parse(script.textContent);
1783
+ return Array.isArray(parsed) ? parsed : [];
1784
+ } catch {
1785
+ return [];
1786
+ }
1787
+ }
1788
+
1789
+ const routeSlotRoots = new Map();
1790
+ let activeRouteInterception = null;
1791
+
1792
+ function resetRouteSlotRoots() {
1793
+ for (const root of routeSlotRoots.values()) {
1794
+ try { root.unmount(); } catch {}
1795
+ }
1796
+ routeSlotRoots.clear();
1797
+ activeRouteInterception = null;
1798
+ }
1799
+
1800
+ function renderClientRouteSlot(slot, registration, mode) {
1801
+ const container = document.getElementById(slot.containerId);
1802
+ if (!container || !registration?.Component) return false;
1803
+ const key = routeSlotKey(slot);
1804
+ const existingRoot = routeSlotRoots.get(key);
1805
+ const props = slot.props && typeof slot.props === "object" ? slot.props : {};
1806
+ const element = React.createElement(registration.Component, props);
1807
+
1808
+ if (mode === "hydrate") {
1809
+ if (existingRoot) return true;
1810
+ const root = hydrateRoot(container, element);
1811
+ routeSlotRoots.set(key, root);
1812
+ return true;
1813
+ }
1814
+
1815
+ if (existingRoot) {
1816
+ try { existingRoot.unmount(); } catch {}
1817
+ routeSlotRoots.delete(key);
1818
+ } else {
1819
+ container.replaceChildren();
1820
+ }
1821
+ const root = createRoot(container);
1822
+ root.render(element);
1823
+ routeSlotRoots.set(key, root);
1824
+ return true;
1825
+ }
1826
+
1827
+ function hydrateInitialRouteSlots() {
1828
+ const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
1829
+ ? window.__FARM_ROUTE_SLOTS__
1830
+ : [];
1831
+ for (const slot of slots) {
1832
+ const registration = findClientRouteSlot(slot);
1833
+ if (!registration) continue;
1834
+ try {
1835
+ renderClientRouteSlot(slot, registration, "hydrate");
1836
+ } catch (error) {
1837
+ console.warn("[Farm.js] Could not hydrate route slot:", slot.name, error);
1838
+ }
1839
+ }
1840
+ }
1841
+
1842
+ function renderRouteInterception(slot, registration, from) {
1843
+ const container = document.getElementById(slot.containerId);
1844
+ if (!container) return false;
1845
+ const key = routeSlotKey(slot);
1846
+ const previousSlot = (window.__FARM_ROUTE_SLOTS__ || []).find(function(candidate) {
1847
+ return routeSlotKey(candidate) === key;
1848
+ }) || null;
1849
+ const previousHtml = container.innerHTML;
1850
+
1851
+ if (!renderClientRouteSlot(slot, registration, "render")) return false;
1852
+ activeRouteInterception = {
1853
+ from: from,
1854
+ key: key,
1855
+ slot: slot,
1856
+ previousSlot: previousSlot,
1857
+ previousHtml: previousHtml,
1858
+ };
1859
+ return true;
1860
+ }
1861
+
1862
+ function clearRouteInterception(destination) {
1863
+ if (!activeRouteInterception) return false;
1864
+ const active = activeRouteInterception;
1865
+ activeRouteInterception = null;
1866
+ const root = routeSlotRoots.get(active.key);
1867
+ if (root) {
1868
+ try { root.unmount(); } catch {}
1869
+ routeSlotRoots.delete(active.key);
1870
+ }
1871
+ const container = document.getElementById(active.slot.containerId);
1872
+ if (container) {
1873
+ container.innerHTML = active.previousHtml;
1874
+ if (active.previousSlot) {
1875
+ const registration = findClientRouteSlot(active.previousSlot);
1876
+ if (registration) {
1877
+ try {
1878
+ renderClientRouteSlot(active.previousSlot, registration, "hydrate");
1879
+ } catch {}
1880
+ }
1881
+ }
1882
+ }
1883
+ return destination === active.from;
1884
+ }
1885
+
1696
1886
  // State
1697
1887
  let reactRoot = null;
1698
1888
  let currentPathname = null;
@@ -1711,12 +1901,17 @@ function resetReactRoot() {
1711
1901
  async function hydrate() {
1712
1902
  const pathname = window.location.pathname;
1713
1903
  const matched = matchRoute(pathname);
1714
-
1904
+ hydrateInitialRouteSlots();
1905
+
1715
1906
  if (!matched) {
1716
1907
  return;
1717
1908
  }
1718
1909
 
1719
- const container = document.getElementById("root");
1910
+ const hasRouteSlots =
1911
+ Array.isArray(window.__FARM_ROUTE_SLOTS__) && window.__FARM_ROUTE_SLOTS__.length > 0;
1912
+ const container =
1913
+ (hasRouteSlots ? document.getElementById("__farm_page__") : null) ||
1914
+ document.getElementById("root");
1720
1915
  if (!container) {
1721
1916
  console.error("[Farm.js] No root element found");
1722
1917
  return;
@@ -1730,7 +1925,9 @@ async function hydrate() {
1730
1925
 
1731
1926
  // Create page element and wrap with layouts
1732
1927
  const pageElement = React.createElement(Component, props);
1733
- const wrappedElement = wrapWithLayouts(pageElement, pathname, params);
1928
+ const wrappedElement = hasRouteSlots
1929
+ ? pageElement
1930
+ : wrapWithLayouts(pageElement, pathname, params);
1734
1931
 
1735
1932
  const shouldHydrate = !isHydrated && Boolean(container.innerHTML.trim());
1736
1933
  const hydrationSession = await farmClientRuntime.beginHydration({
@@ -1795,6 +1992,57 @@ ${generateUniversalRouterStateProperties()}
1795
1992
  : undefined,
1796
1993
  });
1797
1994
 
1995
+ if (activeRouteInterception && clearRouteInterception(to)) {
1996
+ await farmClientRuntime.markNavigationLoaded(clientNavigation, {
1997
+ routeSlots: "restored",
1998
+ });
1999
+ await farmClientRuntime.resolveNavigation(clientNavigation);
2000
+ void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
2001
+ this.currentPath = to;
2002
+ this.finishNavigation();
2003
+ return;
2004
+ }
2005
+ if (activeRouteInterception) {
2006
+ clearRouteInterception(to);
2007
+ }
2008
+
2009
+ const intercepted = matchInterceptedRouteSlot(pathname, from);
2010
+ if (intercepted) {
2011
+ const html = await this.fetchPage(to, from);
2012
+ const doc = new DOMParser().parseFromString(html, "text/html");
2013
+ const slotPayload = readRouteSlotPayload(doc);
2014
+ const selectedSlot = slotPayload.find(function(slot) {
2015
+ return slot.interception &&
2016
+ slot.name === intercepted.slot.name &&
2017
+ slot.ownerPattern === intercepted.slot.ownerPattern;
2018
+ });
2019
+
2020
+ if (
2021
+ selectedSlot &&
2022
+ renderRouteInterception(selectedSlot, intercepted.slot, from)
2023
+ ) {
2024
+ await farmClientRuntime.markNavigationLoaded(clientNavigation, {
2025
+ route: intercepted.slot.pattern,
2026
+ params: intercepted.params,
2027
+ });
2028
+ const historyState = createHistoryState(
2029
+ to,
2030
+ options.state,
2031
+ window.history.state,
2032
+ );
2033
+ if (action === "replace") {
2034
+ window.history.replaceState(historyState, "", url);
2035
+ } else if (action !== "pop") {
2036
+ window.history.pushState(historyState, "", url);
2037
+ }
2038
+ await farmClientRuntime.resolveNavigation(clientNavigation);
2039
+ void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
2040
+ this.currentPath = to;
2041
+ this.finishNavigation();
2042
+ return;
2043
+ }
2044
+ }
2045
+
1798
2046
  if (matched) {
1799
2047
  const Component = matched.route.Component;
1800
2048
  const params = matched.params;
@@ -1871,21 +2119,28 @@ ${generateUniversalRouterStateProperties()}
1871
2119
  }
1872
2120
  },
1873
2121
 
1874
- fetchPage: async function(url) {
1875
- const cached = this.prefetchCache.get(url);
2122
+ fetchPage: async function(url, interceptFrom) {
2123
+ const cacheKey = interceptFrom ? url + "\\nintercept:" + interceptFrom : url;
2124
+ const cached = this.prefetchCache.get(cacheKey);
1876
2125
  if (cached) return cached;
1877
2126
 
1878
2127
  const response = await fetch(url, {
1879
- headers: { "Accept": "text/html" }
2128
+ headers: {
2129
+ "Accept": "text/html",
2130
+ ...(interceptFrom ? { "X-Farm-Intercept-From": interceptFrom } : {}),
2131
+ }
1880
2132
  });
1881
2133
  if (!response.ok) throw new Error("Failed to fetch page");
1882
- return response.text();
2134
+ const html = await response.text();
2135
+ this.prefetchCache.set(cacheKey, html);
2136
+ return html;
1883
2137
  },
1884
2138
 
1885
2139
  swapContent: function(html, targetPath) {
1886
2140
  const parser = new DOMParser();
1887
2141
  const doc = parser.parseFromString(html, "text/html");
1888
2142
  if (isFarmLocaleDocumentChange(doc)) return false;
2143
+ const nextRouteSlots = readRouteSlotPayload(doc);
1889
2144
 
1890
2145
  // Update title
1891
2146
  const newTitle = doc.querySelector("title");
@@ -1910,7 +2165,10 @@ ${generateUniversalRouterStateProperties()}
1910
2165
  const currentRoot = document.getElementById("root");
1911
2166
  if (!newRoot || !currentRoot) return this.swapDocument(doc);
1912
2167
  resetReactRoot();
2168
+ resetRouteSlotRoots();
1913
2169
  currentRoot.innerHTML = newRoot.innerHTML;
2170
+ window.__FARM_ROUTE_SLOTS__ = nextRouteSlots;
2171
+ hydrateInitialRouteSlots();
1914
2172
 
1915
2173
  // Check if new page has a client component
1916
2174
  const targetUrl = new URL(targetPath || window.location.href, window.location.origin);
@@ -1922,13 +2180,15 @@ ${generateUniversalRouterStateProperties()}
1922
2180
  const params = matched.params;
1923
2181
  const searchParams = Object.fromEntries(targetUrl.searchParams);
1924
2182
  const props = { params: params, searchParams: Promise.resolve(searchParams) };
1925
-
1926
- if (!reactRoot) {
1927
- reactRoot = createRoot(currentRoot);
1928
- }
1929
2183
  const pageElement = React.createElement(Component, props);
1930
- const wrappedElement = wrapWithLayouts(pageElement, newPathname, params);
1931
- reactRoot.render(wrappedElement);
2184
+ const hasRouteSlots = nextRouteSlots.length > 0;
2185
+ const pageContainer =
2186
+ (hasRouteSlots ? document.getElementById("__farm_page__") : null) || currentRoot;
2187
+ const wrappedElement = hasRouteSlots
2188
+ ? pageElement
2189
+ : wrapWithLayouts(pageElement, newPathname, params);
2190
+ reactRoot = hydrateRoot(pageContainer, wrappedElement);
2191
+ isHydrated = true;
1932
2192
  }
1933
2193
  return true;
1934
2194
  },
@@ -1937,6 +2197,7 @@ ${generateUniversalRouterStateProperties()}
1937
2197
  if (!doc.documentElement || !doc.body) return false;
1938
2198
 
1939
2199
  resetReactRoot();
2200
+ resetRouteSlotRoots();
1940
2201
 
1941
2202
  Array.from(document.documentElement.attributes).forEach(function(attr) {
1942
2203
  if (!doc.documentElement.hasAttribute(attr.name)) {
@@ -1970,10 +2231,12 @@ ${generateUniversalRouterStateProperties()}
1970
2231
  if (url.origin !== window.location.origin) return;
1971
2232
 
1972
2233
  const pathname = url.pathname + url.search;
1973
- if (this.prefetchCache.has(pathname)) return;
2234
+ const interceptFrom = this.currentPath;
2235
+ const cacheKey = pathname + "\\nintercept:" + interceptFrom;
2236
+ if (this.prefetchCache.has(cacheKey)) return;
1974
2237
 
1975
- this.fetchPage(pathname)
1976
- .then(function(html) { spaRouter.prefetchCache.set(pathname, html); })
2238
+ this.fetchPage(pathname, interceptFrom)
2239
+ .then(function(html) { spaRouter.prefetchCache.set(cacheKey, html); })
1977
2240
  .catch(function() {});
1978
2241
  },
1979
2242
 
@@ -2064,7 +2327,7 @@ if (isFarmDocsSearchPage()) {
2064
2327
  `.trim();
2065
2328
  }
2066
2329
  __name(generateClientHydrationEntry, "generateClientHydrationEntry");
2067
- async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes) {
2330
+ async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes, collectedRouteSlots) {
2068
2331
  const viteBuild = productionVite.build;
2069
2332
  const { farmPlugin } = await import("./vite.mjs");
2070
2333
  const { PluginManager: PluginManager2 } = await import("./plugin.mjs");
@@ -2097,6 +2360,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
2097
2360
  let ssrEntryFile;
2098
2361
  const pageRoutes = collectedPageRoutes.map((route) => ({ ...route }));
2099
2362
  const layoutRoutes = collectedLayoutRoutes.map((route) => ({ ...route }));
2363
+ const routeSlots = collectedRouteSlots.map((slot) => ({ ...slot }));
2100
2364
  const metadataImageRoutes = [];
2101
2365
  for (const entry of routeManager.getMetadataImages().values()) {
2102
2366
  if (entry.sourceType === "static") {
@@ -2197,6 +2461,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
2197
2461
  apiRoutes,
2198
2462
  pageRoutes,
2199
2463
  layoutRoutes,
2464
+ routeSlots,
2200
2465
  errorRoutes,
2201
2466
  metadataImageRoutes,
2202
2467
  middlewareRoutes,
@@ -2367,10 +2632,14 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
2367
2632
  }
2368
2633
  }
2369
2634
  }
2370
- return { bundle: ssrBundle, entryFile: ssrEntryFile, configuredHeaderRoutes };
2635
+ return {
2636
+ bundle: ssrBundle,
2637
+ entryFile: ssrEntryFile,
2638
+ configuredHeaderRoutes
2639
+ };
2371
2640
  }
2372
2641
  __name(buildSSRInMemory, "buildSSRInMemory");
2373
- function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
2642
+ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
2374
2643
  const hasPluginRuntime = hasRuntimeIntegrationConfig || hasConfiguredRuntimePlugins;
2375
2644
  const hasMiddlewareRuntime = middlewareRoutes.length > 0 || hasFarmMiddlewareConfig(config.middleware);
2376
2645
  const farmDocsBaseConfig = config.docs?.enabled ? { ...config.docs, config: void 0 } : void 0;
@@ -2414,10 +2683,12 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
2414
2683
  return;
2415
2684
  }
2416
2685
  pageImports.push(`import * as ${varName} from "${route.modulePath}";`);
2686
+ const shouldHydrate = getClientModuleMetadata(route.modulePath, config.root).shouldHydrate;
2417
2687
  pageRegistrations.push(`
2418
2688
  {
2419
2689
  pattern: ${JSON.stringify(route.pattern)},
2420
2690
  module: ${varName},
2691
+ shouldHydrate: ${JSON.stringify(shouldHydrate)},
2421
2692
  }`);
2422
2693
  });
2423
2694
  const layoutImports = [];
@@ -2431,6 +2702,22 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
2431
2702
  module: ${varName},
2432
2703
  }`);
2433
2704
  });
2705
+ const routeSlotImports = [];
2706
+ const routeSlotRegistrations = [];
2707
+ routeSlots.forEach((slot, index) => {
2708
+ const varName = `routeSlot${index}`;
2709
+ routeSlotImports.push(`import * as ${varName} from "${slot.modulePath}";`);
2710
+ routeSlotRegistrations.push(`
2711
+ {
2712
+ name: ${JSON.stringify(slot.name)},
2713
+ ownerPattern: ${JSON.stringify(slot.ownerPattern)},
2714
+ pattern: ${JSON.stringify(slot.pattern)},
2715
+ containerId: ${JSON.stringify(slot.containerId)},
2716
+ interception: ${JSON.stringify(slot.interception)},
2717
+ fallback: ${JSON.stringify(slot.fallback)},
2718
+ module: ${varName},
2719
+ }`);
2720
+ });
2434
2721
  const errorImports = [];
2435
2722
  const errorRegistrations = [];
2436
2723
  errorRoutes.forEach((errorRoute, index) => {
@@ -2481,6 +2768,7 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
2481
2768
  _runWithMiddlewareData,
2482
2769
  addMetadataImageReference,
2483
2770
  applyProductionMiddlewareHeaders,
2771
+ configureFarmCache,
2484
2772
  configureFarmObservability,
2485
2773
  createFarmCacheKey,
2486
2774
  createFarmLocaleCookie,
@@ -2583,6 +2871,7 @@ async function handleAPIRequest(request) {
2583
2871
  ${apiImports.join("\n")}
2584
2872
  ${pageImports.join("\n")}
2585
2873
  ${layoutImports.join("\n")}
2874
+ ${routeSlotImports.join("\n")}
2586
2875
  ${errorImports.join("\n")}
2587
2876
  ${metadataImageImports.join("\n")}
2588
2877
  ${middlewareImports.join("\n")}
@@ -2660,6 +2949,7 @@ const farmObservabilityConfig = farmUserConfig?.observability ?? ${JSON.stringif
2660
2949
  config.observability ?? false
2661
2950
  )};
2662
2951
  configureFarmObservability(farmObservabilityConfig);
2952
+ configureFarmCache(farmResolvedRuntimeConfig.cache);
2663
2953
  const farmI18nConfig = ${JSON.stringify(config.i18n)};
2664
2954
  const farmI18nRuntime = ${config.i18n.enabled ? `createFarmI18nRuntime(farmI18nConfig, ${JSON.stringify(i18nCatalogs)})` : "null"};
2665
2955
  ${config.i18n.enabled ? "_setDefaultFarmI18nRuntime(farmI18nRuntime);" : ""}
@@ -2717,6 +3007,9 @@ for (const route of pageRoutes) {
2717
3007
  const layoutRoutes = [${layoutRegistrations.join(",")}
2718
3008
  ];
2719
3009
 
3010
+ const routeSlots = [${routeSlotRegistrations.join(",")}
3011
+ ];
3012
+
2720
3013
  // Route-level error boundaries bundled at build time.
2721
3014
  const errorRoutes = [${errorRegistrations.join(",")}
2722
3015
  ];
@@ -2751,18 +3044,21 @@ function serializeFarmInlineValue(value) {
2751
3044
  .replace(/\\u2029/g, "\\\\u2029");
2752
3045
  }
2753
3046
 
2754
- function renderFarmClientBootstrapScript(canonicalPath) {
3047
+ function renderFarmClientBootstrapScript(canonicalPath, selectedRouteSlots) {
2755
3048
  const integrationManifest = ${hasRuntimeIntegrationConfig ? "getRegisteredIntegrationAPIManifest()" : "{}"};
3049
+ const serializedRouteSlots = serializeFarmInlineValue(selectedRouteSlots || []);
2756
3050
  let source = 'window.__FARM_INTEGRATION_API_MANIFEST__=' +
2757
3051
  serializeFarmInlineValue(integrationManifest) +
2758
- ';';
3052
+ ';window.__FARM_ROUTE_SLOTS__=' + serializedRouteSlots + ';';
2759
3053
  if (typeof canonicalPath === "string" && canonicalPath.startsWith("/")) {
2760
3054
  const serializedPath = serializeFarmInlineValue(canonicalPath);
2761
3055
  source += 'if(location.pathname+location.search!==' + serializedPath + '){' +
2762
3056
  'history.replaceState(Object.assign({},history.state||{},{path:' + serializedPath + '}),"",' +
2763
3057
  serializedPath + ');}';
2764
3058
  }
2765
- return '<script>' + source + '</script>';
3059
+ return '<script id="__farm_route_slots_data__" type="application/json">' +
3060
+ serializedRouteSlots +
3061
+ '</script><script>' + source + '</script>';
2766
3062
  }
2767
3063
 
2768
3064
  function escapeFarmHtmlAttribute(value) {
@@ -3512,6 +3808,79 @@ function matchPageRoute(pathname) {
3512
3808
  return null;
3513
3809
  }
3514
3810
 
3811
+ function matchesRoutePrefix(pathname, pattern) {
3812
+ if (pattern === "/") return true;
3813
+ const pathSegments = normalizeRuntimePath(pathname).split("/").filter(Boolean);
3814
+ const patternSegments = normalizeRuntimePath(pattern).split("/").filter(Boolean);
3815
+ if (patternSegments.length > pathSegments.length) return false;
3816
+ const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
3817
+ return matchRuntimePathPattern(pattern, candidate) !== null;
3818
+ }
3819
+
3820
+ function routeSlotSpecificity(slot) {
3821
+ return slot.pattern.split("/").reduce(function(score, segment) {
3822
+ if (!segment) return score;
3823
+ if (segment.startsWith("[[...")) return score + 1;
3824
+ if (segment.startsWith("[...")) return score + 2;
3825
+ if (segment.startsWith("[")) return score + 3;
3826
+ return score + 10;
3827
+ }, 0);
3828
+ }
3829
+
3830
+ function matchRouteSlots(pathname, interceptFrom) {
3831
+ const groups = new Map();
3832
+ for (const slot of routeSlots) {
3833
+ if (!matchesRoutePrefix(pathname, slot.ownerPattern)) continue;
3834
+ const key = slot.ownerPattern + ":" + slot.name;
3835
+ const entries = groups.get(key) || [];
3836
+ entries.push(slot);
3837
+ groups.set(key, entries);
3838
+ }
3839
+
3840
+ const normalizedFrom =
3841
+ typeof interceptFrom === "string" && interceptFrom.startsWith("/")
3842
+ ? new URL(interceptFrom, "http://farm.local").pathname
3843
+ : null;
3844
+ const matches = [];
3845
+
3846
+ for (const entries of groups.values()) {
3847
+ const candidates = entries
3848
+ .filter(function(entry) { return !entry.fallback; })
3849
+ .filter(function(entry) {
3850
+ return !entry.interception ||
3851
+ (normalizedFrom && matchesRoutePrefix(normalizedFrom, entry.ownerPattern));
3852
+ })
3853
+ .map(function(entry) {
3854
+ return {
3855
+ entry: entry,
3856
+ params: matchRuntimePathPattern(entry.pattern, pathname),
3857
+ };
3858
+ })
3859
+ .filter(function(candidate) { return candidate.params !== null; })
3860
+ .sort(function(left, right) {
3861
+ if (left.entry.interception !== right.entry.interception) {
3862
+ return left.entry.interception ? -1 : 1;
3863
+ }
3864
+ return routeSlotSpecificity(right.entry) - routeSlotSpecificity(left.entry);
3865
+ });
3866
+
3867
+ if (candidates[0]) {
3868
+ matches.push({ ...candidates[0].entry, params: candidates[0].params });
3869
+ continue;
3870
+ }
3871
+
3872
+ const fallback = entries.find(function(entry) { return entry.fallback; });
3873
+ if (fallback) matches.push({ ...fallback, params: {} });
3874
+ }
3875
+
3876
+ return matches.sort(function(left, right) {
3877
+ const ownerDepth =
3878
+ left.ownerPattern.split("/").filter(Boolean).length -
3879
+ right.ownerPattern.split("/").filter(Boolean).length;
3880
+ return ownerDepth || left.name.localeCompare(right.name);
3881
+ });
3882
+ }
3883
+
3515
3884
  function hasLocalRequestRoute(request, routePathname) {
3516
3885
  const pathname = new URL(request.url).pathname;
3517
3886
  if (matchLocalAPIRequest(request) || matchLocalIntegrationRequest(request)) {
@@ -3662,6 +4031,7 @@ function getPPRShellBypassReason(request, middlewareData, middlewareContext) {
3662
4031
  if (method !== "GET" && method !== "HEAD") return "method";
3663
4032
  if (request.headers.get("cookie")) return "cookie";
3664
4033
  if (request.headers.get("authorization")) return "authorization";
4034
+ if (request.headers.get("x-farm-intercept-from")) return "route-interception";
3665
4035
  if (request.headers.get("x-farm-ppr-refresh")) return "refresh";
3666
4036
  if (hasConfiguredRouteContext) return "route-context";
3667
4037
  if (middlewareData?.size) return "middleware-data";
@@ -3715,8 +4085,8 @@ function getRouteSharedCacheControl(routeModule, pprCanCache) {
3715
4085
  return "public, s-maxage=" + revalidate + ", stale-while-revalidate=300";
3716
4086
  }
3717
4087
 
3718
- function getCachedPPRShell(cacheKey) {
3719
- const entry = pprShellCache.getEntry(cacheKey);
4088
+ async function getCachedPPRShell(cacheKey) {
4089
+ const entry = await pprShellCache.getEntryAsync(cacheKey);
3720
4090
  if (!entry) {
3721
4091
  return null;
3722
4092
  }
@@ -3931,7 +4301,7 @@ async function handleFarmRequestInContext(
3931
4301
  }
3932
4302
  }
3933
4303
  if (pprCacheKey) {
3934
- const cachedPPRShell = getCachedPPRShell(pprCacheKey);
4304
+ const cachedPPRShell = await getCachedPPRShell(pprCacheKey);
3935
4305
  if (cachedPPRShell) {
3936
4306
  emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
3937
4307
  emitFarmEvent({
@@ -3959,6 +4329,10 @@ async function handleFarmRequestInContext(
3959
4329
 
3960
4330
  // Get applicable layouts for this page
3961
4331
  const applicableLayouts = getApplicableLayouts(routePathname);
4332
+ const selectedRouteSlots = matchRouteSlots(
4333
+ routePathname,
4334
+ request.headers.get("x-farm-intercept-from"),
4335
+ );
3962
4336
 
3963
4337
  if (PageComponent) {
3964
4338
  // Parse search params - make it a resolved Promise for async components
@@ -4046,6 +4420,82 @@ async function handleFarmRequestInContext(
4046
4420
  throw routeStateError;
4047
4421
  }
4048
4422
  }
4423
+
4424
+ const renderedRouteSlots = await Promise.all(
4425
+ selectedRouteSlots.map(async function(slot) {
4426
+ const slotContext = hasConfiguredRouteContext
4427
+ ? await resolveFarmRouteContext(farmResolvedRuntimeConfig, {
4428
+ request,
4429
+ params: slot.params,
4430
+ search: searchParamsObj,
4431
+ path: pathname,
4432
+ })
4433
+ : undefined;
4434
+ const rawSlotProps = withFarmRouteContext(
4435
+ {
4436
+ params: slot.params,
4437
+ searchParams: Promise.resolve(searchParamsObj),
4438
+ path: pathname,
4439
+ ...(middlewareData?.size ? { middleware: { data: middlewareData } } : {}),
4440
+ },
4441
+ slotContext,
4442
+ );
4443
+ if (slot.module.__farmResolveRouteProps && slotContext !== undefined) {
4444
+ Object.defineProperty(rawSlotProps, "context", {
4445
+ value: slotContext,
4446
+ enumerable: true,
4447
+ configurable: true,
4448
+ });
4449
+ }
4450
+
4451
+ const slotSchemas = slot.module.__farmRouteParsesProps
4452
+ ? {}
4453
+ : slot.module.__farmRouteSchemas || {};
4454
+ let slotProps = slot.module.__farmResolveRouteProps
4455
+ ? await slot.module.__farmResolveRouteProps(rawSlotProps)
4456
+ : {
4457
+ ...rawSlotProps,
4458
+ params: slotSchemas.params?.parse
4459
+ ? slotSchemas.params.parse(slot.params)
4460
+ : slot.params,
4461
+ search: slotSchemas.search?.parse
4462
+ ? slotSchemas.search.parse(searchParamsObj)
4463
+ : searchParamsObj,
4464
+ searchParams: Promise.resolve(
4465
+ slotSchemas.search?.parse
4466
+ ? slotSchemas.search.parse(searchParamsObj)
4467
+ : searchParamsObj,
4468
+ ),
4469
+ };
4470
+ if (
4471
+ slot.module.__farmResolveRouteProps &&
4472
+ slotContext !== undefined &&
4473
+ slotProps.context === slotContext
4474
+ ) {
4475
+ const { context: _slotContext, ...renderSlotProps } = slotProps;
4476
+ slotProps = renderSlotProps;
4477
+ }
4478
+
4479
+ return { ...slot, props: slotProps };
4480
+ }),
4481
+ );
4482
+ const routeSlotPayload = renderedRouteSlots.map(function(slot) {
4483
+ return {
4484
+ name: slot.name,
4485
+ ownerPattern: slot.ownerPattern,
4486
+ pattern: slot.pattern,
4487
+ containerId: slot.containerId,
4488
+ interception: slot.interception,
4489
+ fallback: slot.fallback,
4490
+ props: {
4491
+ params: slot.props.params,
4492
+ search: slot.props.search || searchParamsObj,
4493
+ searchParams: slot.props.search || searchParamsObj,
4494
+ ...("data" in slot.props ? { data: slot.props.data } : {}),
4495
+ path: pathname,
4496
+ },
4497
+ };
4498
+ });
4049
4499
 
4050
4500
  const renderPageElement = async () => {
4051
4501
  // First, render the page content
@@ -4073,6 +4523,14 @@ async function handleFarmRequestInContext(
4073
4523
  pageElement = React.createElement(PageComponent, pageProps);
4074
4524
  }
4075
4525
 
4526
+ if (route.shouldHydrate && renderedRouteSlots.length > 0) {
4527
+ pageElement = React.createElement(
4528
+ "div",
4529
+ { id: "__farm_page__", "data-farm-client": "true" },
4530
+ pageElement,
4531
+ );
4532
+ }
4533
+
4076
4534
  // Wrap with layouts (from innermost to outermost)
4077
4535
  // Layouts are sorted by depth (root first), so we process in reverse
4078
4536
  let wrappedElement = pageElement;
@@ -4080,9 +4538,23 @@ async function handleFarmRequestInContext(
4080
4538
  const layout = applicableLayouts[i];
4081
4539
  const LayoutComponent = layout.module.default;
4082
4540
  if (LayoutComponent) {
4541
+ const slotProps = {};
4542
+ for (const slot of renderedRouteSlots) {
4543
+ if (slot.ownerPattern !== layout.pattern) continue;
4544
+ slotProps[slot.name] = React.createElement(
4545
+ "div",
4546
+ {
4547
+ id: slot.containerId,
4548
+ "data-farm-route-slot": slot.name,
4549
+ "data-farm-slot-owner": slot.ownerPattern,
4550
+ },
4551
+ React.createElement(slot.module.default, slot.props),
4552
+ );
4553
+ }
4083
4554
  wrappedElement = React.createElement(LayoutComponent, {
4084
4555
  children: wrappedElement,
4085
4556
  params,
4557
+ ...slotProps,
4086
4558
  });
4087
4559
  }
4088
4560
  }
@@ -4134,6 +4606,7 @@ async function handleFarmRequestInContext(
4134
4606
  );
4135
4607
  const hasRequestScopedRender = Boolean(
4136
4608
  pageStatus >= 400 ||
4609
+ request.headers.get("x-farm-intercept-from") ||
4137
4610
  hasPrivateRequestHeaders ||
4138
4611
  hasConfiguredRouteContext ||
4139
4612
  middlewareData?.size ||
@@ -4173,7 +4646,10 @@ async function handleFarmRequestInContext(
4173
4646
  ' <link rel="modulepreload" href="/farm-client.js">\\n' +
4174
4647
  '</head>\\n<body>\\n <div id="root">';
4175
4648
  const streamSuffix = '</div>\\n' +
4176
- ' ' + renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath) + '\\n' +
4649
+ ' ' + renderFarmClientBootstrapScript(
4650
+ pageProps.__farmCanonicalPath,
4651
+ routeSlotPayload
4652
+ ) + '\\n' +
4177
4653
  ' <script type="module" src="/farm-client.js"></script>\\n' +
4178
4654
  '</body>\\n</html>';
4179
4655
  const streamedDocument = createFarmDocumentStream(
@@ -4230,7 +4706,10 @@ async function handleFarmRequestInContext(
4230
4706
  // Inject client script before closing body tag
4231
4707
  .replace(
4232
4708
  /<\\/body>/i,
4233
- ' ' + renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath) + '\\n' +
4709
+ ' ' + renderFarmClientBootstrapScript(
4710
+ pageProps.__farmCanonicalPath,
4711
+ routeSlotPayload
4712
+ ) + '\\n' +
4234
4713
  ' <script type="module" src="/farm-client.js"></script>\\n</body>',
4235
4714
  );
4236
4715
 
@@ -4251,7 +4730,7 @@ async function handleFarmRequestInContext(
4251
4730
  </head>
4252
4731
  <body>
4253
4732
  <div id="root">\${html}</div>
4254
- \${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath)}
4733
+ \${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath, routeSlotPayload)}
4255
4734
  <script type="module" src="/farm-client.js"></script>
4256
4735
  </body>
4257
4736
  </html>\`;
@@ -4259,7 +4738,7 @@ async function handleFarmRequestInContext(
4259
4738
  fullHtml = applyFarmI18nDocument(fullHtml, pathname, farmI18nSnapshot);
4260
4739
 
4261
4740
  if (pageStatus === 200 && pprCacheKey && request.method.toUpperCase() !== "HEAD") {
4262
- pprShellCache.set(
4741
+ await pprShellCache.setAsync(
4263
4742
  pprCacheKey,
4264
4743
  { html: fullHtml },
4265
4744
  {
@@ -5759,4 +6238,4 @@ __name(buildNitro, "buildNitro");
5759
6238
  export {
5760
6239
  build
5761
6240
  };
5762
- //# sourceMappingURL=chunk-OHC6VCDI.mjs.map
6241
+ //# sourceMappingURL=chunk-2NHCNRF6.mjs.map