@farm.js/core 0.1.0-beta.1 → 0.1.0-beta.4

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 (254) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-runtime.d.mts +2 -1
  3. package/dist/agent-runtime.d.ts +2 -1
  4. package/dist/api/route-manager.cjs +410 -15
  5. package/dist/api/route-manager.cjs.map +1 -1
  6. package/dist/api/route-manager.d.mts +4 -2
  7. package/dist/api/route-manager.d.ts +4 -2
  8. package/dist/api/route-manager.mjs +9 -8
  9. package/dist/api/runtime.cjs +748 -9
  10. package/dist/api/runtime.cjs.map +1 -1
  11. package/dist/api/runtime.d.mts +3 -16
  12. package/dist/api/runtime.d.ts +3 -16
  13. package/dist/api/runtime.mjs +8 -1
  14. package/dist/api.cjs +1243 -342
  15. package/dist/api.cjs.map +1 -1
  16. package/dist/api.d.mts +5 -147
  17. package/dist/api.d.ts +5 -147
  18. package/dist/api.mjs +51 -21
  19. package/dist/{app-CFRNJXP1.d.ts → app-BjN-da13.d.ts} +38 -3
  20. package/dist/{app-BiX4qb-d.d.mts → app-CakAr8Be.d.mts} +38 -3
  21. package/dist/app-markdown.cjs +1 -1
  22. package/dist/app-markdown.cjs.map +1 -1
  23. package/dist/app-markdown.d.mts +2 -1
  24. package/dist/app-markdown.d.ts +2 -1
  25. package/dist/app-markdown.mjs +1 -1
  26. package/dist/cache.cjs +414 -12
  27. package/dist/cache.cjs.map +1 -1
  28. package/dist/cache.d.mts +120 -6
  29. package/dist/cache.d.ts +120 -6
  30. package/dist/cache.mjs +11 -3
  31. package/dist/{chunk-Y7A27276.mjs → chunk-2CUKEMVR.mjs} +349 -15
  32. package/dist/chunk-2CUKEMVR.mjs.map +1 -0
  33. package/dist/{chunk-QF4PHCMA.mjs → chunk-2ED5Q2GH.mjs} +3 -3
  34. package/dist/chunk-2ED5Q2GH.mjs.map +1 -0
  35. package/dist/{chunk-GZP5W4K3.mjs → chunk-32W4QEJP.mjs} +1 -1
  36. package/dist/chunk-32W4QEJP.mjs.map +1 -0
  37. package/dist/{chunk-TRORP7E4.mjs → chunk-3U3ZUQAQ.mjs} +2 -2
  38. package/dist/{chunk-25D7G34K.mjs → chunk-65A7QIKI.mjs} +5 -5
  39. package/dist/{chunk-25D7G34K.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
  40. package/dist/{chunk-G3B5BRDY.mjs → chunk-AJWRO5WE.mjs} +539 -61
  41. package/dist/chunk-AJWRO5WE.mjs.map +1 -0
  42. package/dist/chunk-ALCLXXTY.mjs +187 -0
  43. package/dist/chunk-ALCLXXTY.mjs.map +1 -0
  44. package/dist/{chunk-CHFHNEMO.mjs → chunk-AOBXKNS5.mjs} +627 -84
  45. package/dist/chunk-AOBXKNS5.mjs.map +1 -0
  46. package/dist/{chunk-B6N4ZB2H.mjs → chunk-C2ROET2V.mjs} +3 -3
  47. package/dist/{chunk-JN3UU635.mjs → chunk-EJ7T4TPB.mjs} +2 -2
  48. package/dist/chunk-EJ7T4TPB.mjs.map +1 -0
  49. package/dist/{chunk-ZJQNATYV.mjs → chunk-FRPWCMMG.mjs} +3 -3
  50. package/dist/chunk-FRPWCMMG.mjs.map +1 -0
  51. package/dist/{chunk-QM6VV26B.mjs → chunk-GQVGIUSN.mjs} +3 -3
  52. package/dist/{chunk-QM6VV26B.mjs.map → chunk-GQVGIUSN.mjs.map} +1 -1
  53. package/dist/{chunk-UREJA4GZ.mjs → chunk-GXASWWJU.mjs} +1 -1
  54. package/dist/{chunk-UREJA4GZ.mjs.map → chunk-GXASWWJU.mjs.map} +1 -1
  55. package/dist/{chunk-3QJO55ZF.mjs → chunk-HNIQFZKB.mjs} +5 -3
  56. package/dist/{chunk-3QJO55ZF.mjs.map → chunk-HNIQFZKB.mjs.map} +1 -1
  57. package/dist/{chunk-PRNYWD7K.mjs → chunk-JDEOUK5V.mjs} +67 -239
  58. package/dist/chunk-JDEOUK5V.mjs.map +1 -0
  59. package/dist/{chunk-O3HADRW6.mjs → chunk-MIUW47JX.mjs} +2 -2
  60. package/dist/{chunk-O3HADRW6.mjs.map → chunk-MIUW47JX.mjs.map} +1 -1
  61. package/dist/{chunk-UHE2TTLK.mjs → chunk-NM3CRAAL.mjs} +9 -8
  62. package/dist/chunk-NM3CRAAL.mjs.map +1 -0
  63. package/dist/chunk-PFE6GMNE.mjs +603 -0
  64. package/dist/chunk-PFE6GMNE.mjs.map +1 -0
  65. package/dist/{chunk-S2XHZS7W.mjs → chunk-QGQX7SFC.mjs} +2 -2
  66. package/dist/chunk-QGQX7SFC.mjs.map +1 -0
  67. package/dist/{chunk-RKI6TN3A.mjs → chunk-QM746KUO.mjs} +9 -2
  68. package/dist/chunk-QM746KUO.mjs.map +1 -0
  69. package/dist/chunk-RBRLLZL5.mjs +81 -0
  70. package/dist/chunk-RBRLLZL5.mjs.map +1 -0
  71. package/dist/{chunk-HXP3ZSPC.mjs → chunk-SADGIRS2.mjs} +3 -3
  72. package/dist/{chunk-6XDUHOEM.mjs → chunk-TQAEEJB4.mjs} +3 -3
  73. package/dist/{chunk-AGS7UJ52.mjs → chunk-UB5UOSHB.mjs} +24 -12
  74. package/dist/chunk-UB5UOSHB.mjs.map +1 -0
  75. package/dist/{chunk-SXZTEK3V.mjs → chunk-UXUAWNO5.mjs} +2 -2
  76. package/dist/chunk-V3XURYJO.mjs +756 -0
  77. package/dist/chunk-V3XURYJO.mjs.map +1 -0
  78. package/dist/{chunk-TU4YJICB.mjs → chunk-VVKWFZAH.mjs} +41 -16
  79. package/dist/chunk-VVKWFZAH.mjs.map +1 -0
  80. package/dist/{chunk-JLWMCADZ.mjs → chunk-VY2UYN5R.mjs} +24 -4
  81. package/dist/chunk-VY2UYN5R.mjs.map +1 -0
  82. package/dist/{chunk-QFQRHRZS.mjs → chunk-W2CRQFF6.mjs} +151 -23
  83. package/dist/chunk-W2CRQFF6.mjs.map +1 -0
  84. package/dist/chunk-W4UIVMVI.mjs +10 -0
  85. package/dist/chunk-W4UIVMVI.mjs.map +1 -0
  86. package/dist/{chunk-Y2OJJD7R.mjs → chunk-XIVV5IWN.mjs} +7 -9
  87. package/dist/chunk-XIVV5IWN.mjs.map +1 -0
  88. package/dist/{chunk-OYXO65LI.mjs → chunk-YW7OBE6Q.mjs} +4 -4
  89. package/dist/chunk-YW7OBE6Q.mjs.map +1 -0
  90. package/dist/{chunk-YHU7SS6L.mjs → chunk-Z5CQMP54.mjs} +11 -11
  91. package/dist/{chunk-SOU3Q3ZA.mjs → chunk-ZZ57EH5Z.mjs} +1 -1
  92. package/dist/chunk-ZZ57EH5Z.mjs.map +1 -0
  93. package/dist/{client-D_yUjVhe.d.mts → client-BT1mFQas.d.mts} +55 -10
  94. package/dist/{client-Dkc03WP8.d.ts → client-Nn0q4eO4.d.ts} +55 -10
  95. package/dist/{client-plugins-BZnpeTGA.d.ts → client-plugins-Cw4qUGsw.d.ts} +7 -0
  96. package/dist/{client-plugins-g4bzuCmo.d.mts → client-plugins-DQQ1adXM.d.mts} +7 -0
  97. package/dist/client-plugins.d.mts +2 -1
  98. package/dist/client-plugins.d.ts +2 -1
  99. package/dist/client.cjs +922 -91
  100. package/dist/client.cjs.map +1 -1
  101. package/dist/client.d.mts +121 -3
  102. package/dist/client.d.ts +121 -3
  103. package/dist/client.mjs +23 -16
  104. package/dist/config.d.mts +2 -1
  105. package/dist/config.d.ts +2 -1
  106. package/dist/cron.cjs.map +1 -1
  107. package/dist/cron.mjs +1 -1
  108. package/dist/{devtools-AE4RVXCM.mjs → devtools-LVC3VB5P.mjs} +10 -10
  109. package/dist/{devtools-client-6WPY2AQU.mjs → devtools-client-3XRTBND5.mjs} +2 -11
  110. package/dist/devtools-client-3XRTBND5.mjs.map +1 -0
  111. package/dist/docs.cjs +14 -2
  112. package/dist/docs.cjs.map +1 -1
  113. package/dist/docs.mjs +10 -10
  114. package/dist/i18n/server.cjs +2 -2
  115. package/dist/i18n/server.cjs.map +1 -1
  116. package/dist/i18n/server.mjs +1 -1
  117. package/dist/index.cjs +2852 -463
  118. package/dist/index.cjs.map +1 -1
  119. package/dist/index.d.mts +13 -12
  120. package/dist/index.d.ts +13 -12
  121. package/dist/index.mjs +152 -109
  122. package/dist/index.mjs.map +1 -1
  123. package/dist/integrations.d.mts +2 -1
  124. package/dist/integrations.d.ts +2 -1
  125. package/dist/internal/build-runtime.cjs +1616 -149
  126. package/dist/internal/build-runtime.cjs.map +1 -1
  127. package/dist/internal/build-runtime.d.mts +4 -3
  128. package/dist/internal/build-runtime.d.ts +4 -3
  129. package/dist/internal/build-runtime.mjs +27 -25
  130. package/dist/internal/client-runtime.cjs.map +1 -1
  131. package/dist/internal/client-runtime.mjs +1 -1
  132. package/dist/internal/config-runtime.cjs +13 -2
  133. package/dist/internal/config-runtime.cjs.map +1 -1
  134. package/dist/internal/config-runtime.d.mts +3 -2
  135. package/dist/internal/config-runtime.d.ts +3 -2
  136. package/dist/internal/config-runtime.mjs +9 -9
  137. package/dist/internal/production-runtime.cjs +285 -9
  138. package/dist/internal/production-runtime.cjs.map +1 -1
  139. package/dist/internal/production-runtime.d.mts +4 -4
  140. package/dist/internal/production-runtime.d.ts +4 -4
  141. package/dist/internal/production-runtime.mjs +10 -8
  142. package/dist/{metadata-DAXRaOHx.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
  143. package/dist/{metadata-C9NZxMDW.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
  144. package/dist/middleware.cjs +2 -2
  145. package/dist/middleware.cjs.map +1 -1
  146. package/dist/middleware.d.mts +4 -3
  147. package/dist/middleware.d.ts +4 -3
  148. package/dist/middleware.mjs +3 -3
  149. package/dist/navigation.cjs +40 -15
  150. package/dist/navigation.cjs.map +1 -1
  151. package/dist/navigation.mjs +3 -3
  152. package/dist/{nitro-KME62MWG.mjs → nitro-QO5LV6QK.mjs} +11 -13
  153. package/dist/{nitro-KME62MWG.mjs.map → nitro-QO5LV6QK.mjs.map} +1 -1
  154. package/dist/plugin.cjs +1032 -92
  155. package/dist/plugin.cjs.map +1 -1
  156. package/dist/plugin.d.mts +2 -1
  157. package/dist/plugin.d.ts +2 -1
  158. package/dist/plugin.mjs +23 -21
  159. package/dist/{production-runtime-DRkCHUvJ.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
  160. package/dist/{production-runtime-flrjp_nC.d.mts → production-runtime-DPfgMV9Y.d.mts} +1 -1
  161. package/dist/routes.cjs +276 -6
  162. package/dist/routes.cjs.map +1 -1
  163. package/dist/routes.d.mts +1 -1
  164. package/dist/routes.d.ts +1 -1
  165. package/dist/routes.mjs +4 -4
  166. package/dist/runtime-9nQjVM7X.d.mts +206 -0
  167. package/dist/runtime-DgeS2skB.d.ts +206 -0
  168. package/dist/server-action-security.cjs +28 -10
  169. package/dist/server-action-security.cjs.map +1 -1
  170. package/dist/server-action-security.d.mts +2 -1
  171. package/dist/server-action-security.d.ts +2 -1
  172. package/dist/server-action-security.mjs +2 -2
  173. package/dist/server-fn-client.cjs.map +1 -1
  174. package/dist/server-fn-client.d.mts +1 -0
  175. package/dist/server-fn-client.d.ts +1 -0
  176. package/dist/server-fn-client.mjs +1 -1
  177. package/dist/server-fn.cjs +785 -3
  178. package/dist/server-fn.cjs.map +1 -1
  179. package/dist/server-fn.d.mts +10 -1
  180. package/dist/server-fn.d.ts +10 -1
  181. package/dist/server-fn.mjs +6 -3
  182. package/dist/server-plugins.d.mts +3 -2
  183. package/dist/server-plugins.d.ts +3 -2
  184. package/dist/server-query-client.cjs +278 -7
  185. package/dist/server-query-client.cjs.map +1 -1
  186. package/dist/server-query-client.mjs +4 -4
  187. package/dist/server-query.cjs +381 -10
  188. package/dist/server-query.cjs.map +1 -1
  189. package/dist/server-query.mjs +5 -5
  190. package/dist/server.cjs +1233 -118
  191. package/dist/server.cjs.map +1 -1
  192. package/dist/server.d.mts +8 -7
  193. package/dist/server.d.ts +8 -7
  194. package/dist/server.mjs +53 -33
  195. package/dist/server.mjs.map +1 -1
  196. package/dist/testing.cjs +436 -25
  197. package/dist/testing.cjs.map +1 -1
  198. package/dist/testing.d.mts +4 -3
  199. package/dist/testing.d.ts +4 -3
  200. package/dist/testing.mjs +19 -18
  201. package/dist/testing.mjs.map +1 -1
  202. package/dist/transport-BmbGTXA5.d.mts +49 -0
  203. package/dist/transport-BmbGTXA5.d.ts +49 -0
  204. package/dist/{utils-DOXXivjL.d.mts → utils-CHXlMDkg.d.mts} +1 -1
  205. package/dist/{utils-DA1yo54_.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
  206. package/dist/version.cjs +36 -0
  207. package/dist/version.cjs.map +1 -0
  208. package/dist/version.d.mts +3 -0
  209. package/dist/version.d.ts +3 -0
  210. package/dist/version.mjs +8 -0
  211. package/dist/version.mjs.map +1 -0
  212. package/dist/vite.cjs +1039 -93
  213. package/dist/vite.cjs.map +1 -1
  214. package/dist/vite.d.mts +2 -1
  215. package/dist/vite.d.ts +2 -1
  216. package/dist/vite.mjs +23 -21
  217. package/dist/workflows.cjs +6 -8
  218. package/dist/workflows.cjs.map +1 -1
  219. package/dist/workflows.mjs +1 -1
  220. package/package.json +12 -5
  221. package/types/api.d.ts +44 -0
  222. package/types/client.d.ts +220 -16
  223. package/dist/chunk-4PTK6KT4.mjs +0 -364
  224. package/dist/chunk-4PTK6KT4.mjs.map +0 -1
  225. package/dist/chunk-AGS7UJ52.mjs.map +0 -1
  226. package/dist/chunk-CHFHNEMO.mjs.map +0 -1
  227. package/dist/chunk-EVGBEZDF.mjs +0 -215
  228. package/dist/chunk-EVGBEZDF.mjs.map +0 -1
  229. package/dist/chunk-G3B5BRDY.mjs.map +0 -1
  230. package/dist/chunk-GZP5W4K3.mjs.map +0 -1
  231. package/dist/chunk-JLWMCADZ.mjs.map +0 -1
  232. package/dist/chunk-JN3UU635.mjs.map +0 -1
  233. package/dist/chunk-OYXO65LI.mjs.map +0 -1
  234. package/dist/chunk-PRNYWD7K.mjs.map +0 -1
  235. package/dist/chunk-QF4PHCMA.mjs.map +0 -1
  236. package/dist/chunk-QFQRHRZS.mjs.map +0 -1
  237. package/dist/chunk-RKI6TN3A.mjs.map +0 -1
  238. package/dist/chunk-S2XHZS7W.mjs.map +0 -1
  239. package/dist/chunk-SOU3Q3ZA.mjs.map +0 -1
  240. package/dist/chunk-TU4YJICB.mjs.map +0 -1
  241. package/dist/chunk-TXCFGOHW.mjs +0 -42
  242. package/dist/chunk-TXCFGOHW.mjs.map +0 -1
  243. package/dist/chunk-UHE2TTLK.mjs.map +0 -1
  244. package/dist/chunk-Y2OJJD7R.mjs.map +0 -1
  245. package/dist/chunk-Y7A27276.mjs.map +0 -1
  246. package/dist/chunk-ZJQNATYV.mjs.map +0 -1
  247. package/dist/devtools-client-6WPY2AQU.mjs.map +0 -1
  248. /package/dist/{chunk-TRORP7E4.mjs.map → chunk-3U3ZUQAQ.mjs.map} +0 -0
  249. /package/dist/{chunk-B6N4ZB2H.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
  250. /package/dist/{chunk-HXP3ZSPC.mjs.map → chunk-SADGIRS2.mjs.map} +0 -0
  251. /package/dist/{chunk-6XDUHOEM.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
  252. /package/dist/{chunk-SXZTEK3V.mjs.map → chunk-UXUAWNO5.mjs.map} +0 -0
  253. /package/dist/{chunk-YHU7SS6L.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
  254. /package/dist/{devtools-AE4RVXCM.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
package/dist/server.cjs CHANGED
@@ -118,7 +118,7 @@ function createFarmMarkdownRouteModule(input) {
118
118
  ...props,
119
119
  components: {
120
120
  ...components,
121
- ...props?.components || {}
121
+ ...props?.components
122
122
  }
123
123
  })
124
124
  );
@@ -635,7 +635,11 @@ async function prepareFarmWorkflowsForNitro(config) {
635
635
  };
636
636
  }
637
637
  const handlerPath = path23.join(generatedDir, "http-handler.mjs");
638
- await fs9.writeFile(handlerPath, createNitroWorkflowHTTPHandler(workflowConfig, workflows), "utf8");
638
+ await fs9.writeFile(
639
+ handlerPath,
640
+ createNitroWorkflowHTTPHandler(workflowConfig, workflows),
641
+ "utf8"
642
+ );
639
643
  const manifestPath = path23.join(generatedDir, "manifest.json");
640
644
  await fs9.writeFile(
641
645
  manifestPath,
@@ -709,13 +713,7 @@ function normalizeSchedule(schedule) {
709
713
  return (Array.isArray(schedule) ? schedule : [schedule]).map((value) => value.trim()).filter(Boolean);
710
714
  }
711
715
  function resolveWorkflowDefinition(module2) {
712
- const candidates = [
713
- module2.default,
714
- module2.workflow,
715
- module2.cron,
716
- module2.task,
717
- module2.job
718
- ];
716
+ const candidates = [module2.default, module2.workflow, module2.cron, module2.task, module2.job];
719
717
  for (const candidate of candidates) {
720
718
  if (candidate && typeof candidate === "object" && typeof candidate.run === "function") {
721
719
  return candidate;
@@ -1708,8 +1706,8 @@ function compareFarmRouteRuleSpecificity(left, right) {
1708
1706
  }
1709
1707
  function getFarmRouteRuleSpecificity(pattern) {
1710
1708
  return normalizeRoutePattern(pattern).split("/").filter(Boolean).reduce((score, segment) => {
1711
- if (segment === "**" || /^\[\[\.\.\./.test(segment)) return score + 1;
1712
- if (segment === "*" || /^\[\.\.\./.test(segment)) return score + 10;
1709
+ if (segment === "**" || segment.startsWith("[[...")) return score + 1;
1710
+ if (segment === "*" || segment.startsWith("[...")) return score + 10;
1713
1711
  if (/^\[.+\]$/.test(segment) || /^:.+$/.test(segment)) return score + 50;
1714
1712
  return score + 100;
1715
1713
  }, 0);
@@ -1770,7 +1768,7 @@ function routeRulesToHeaders(routeRules) {
1770
1768
  for (const [source, rule] of Object.entries(routeRules)) {
1771
1769
  const headers = {
1772
1770
  ...normalizeCorsHeaders(rule.cors),
1773
- ...rule.headers || {}
1771
+ ...rule.headers
1774
1772
  };
1775
1773
  const entries = Object.entries(headers);
1776
1774
  if (entries.length === 0) continue;
@@ -1821,7 +1819,8 @@ var init_route_rules = __esm({
1821
1819
  // src/cache-invalidation.ts
1822
1820
  function getFarmCacheInvalidationState() {
1823
1821
  return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
1824
- listeners: /* @__PURE__ */ new Set()
1822
+ listeners: /* @__PURE__ */ new Set(),
1823
+ taskListeners: /* @__PURE__ */ new Set()
1825
1824
  });
1826
1825
  }
1827
1826
  function notifyFarmCacheInvalidation(key) {
@@ -1830,6 +1829,11 @@ function notifyFarmCacheInvalidation(key) {
1830
1829
  listener(key);
1831
1830
  }
1832
1831
  }
1832
+ function notifyFarmCacheTask(task) {
1833
+ for (const listener of getFarmCacheInvalidationState().taskListeners) {
1834
+ listener(task);
1835
+ }
1836
+ }
1833
1837
  function applyFarmCacheInvalidations(keys) {
1834
1838
  if (!Array.isArray(keys)) return;
1835
1839
  for (const key of keys) {
@@ -1838,21 +1842,49 @@ function applyFarmCacheInvalidations(keys) {
1838
1842
  }
1839
1843
  }
1840
1844
  }
1845
+ function encodeFarmCacheInvalidations(keys) {
1846
+ const normalized = Array.from(
1847
+ new Set(keys.filter((key) => typeof key === "string" && key.length > 0))
1848
+ );
1849
+ if (normalized.length === 0) return null;
1850
+ return encodeURIComponent(JSON.stringify(normalized));
1851
+ }
1852
+ function decodeFarmCacheInvalidations(value) {
1853
+ if (!value) return [];
1854
+ try {
1855
+ const parsed = JSON.parse(decodeURIComponent(value));
1856
+ return Array.isArray(parsed) ? Array.from(
1857
+ new Set(parsed.filter((key) => typeof key === "string" && key.length > 0))
1858
+ ) : [];
1859
+ } catch {
1860
+ return [];
1861
+ }
1862
+ }
1841
1863
  function subscribeFarmCacheInvalidation(listener) {
1842
1864
  const state = getFarmCacheInvalidationState();
1843
1865
  state.listeners.add(listener);
1844
1866
  return () => state.listeners.delete(listener);
1845
1867
  }
1846
- var FARM_CACHE_INVALIDATION_STATE, globalState;
1868
+ function subscribeFarmCacheTask(listener) {
1869
+ const state = getFarmCacheInvalidationState();
1870
+ state.taskListeners.add(listener);
1871
+ return () => state.taskListeners.delete(listener);
1872
+ }
1873
+ var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
1847
1874
  var init_cache_invalidation = __esm({
1848
1875
  "src/cache-invalidation.ts"() {
1849
1876
  "use strict";
1877
+ FARM_CACHE_INVALIDATION_HEADER = "x-farm-cache-invalidations";
1850
1878
  FARM_CACHE_INVALIDATION_STATE = /* @__PURE__ */ Symbol.for("farm.cacheInvalidationState");
1851
1879
  globalState = globalThis;
1852
1880
  __name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
1853
1881
  __name(notifyFarmCacheInvalidation, "notifyFarmCacheInvalidation");
1882
+ __name(notifyFarmCacheTask, "notifyFarmCacheTask");
1854
1883
  __name(applyFarmCacheInvalidations, "applyFarmCacheInvalidations");
1884
+ __name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
1885
+ __name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
1855
1886
  __name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
1887
+ __name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
1856
1888
  }
1857
1889
  });
1858
1890
 
@@ -1948,16 +1980,24 @@ function sanitizeServerActionError(_error) {
1948
1980
  message: "Server function failed"
1949
1981
  };
1950
1982
  }
1951
- function runWithServerActionRequest(request, callback) {
1983
+ async function runWithServerActionRequest(request, callback) {
1952
1984
  throwIfAborted(request.signal);
1953
- return getServerActionStorage().run(
1954
- {
1955
- request,
1956
- signal: request.signal,
1957
- invalidations: /* @__PURE__ */ new Set()
1958
- },
1959
- callback
1960
- );
1985
+ const context = {
1986
+ request,
1987
+ signal: request.signal,
1988
+ invalidations: /* @__PURE__ */ new Set(),
1989
+ cacheTasks: /* @__PURE__ */ new Set()
1990
+ };
1991
+ return getServerActionStorage().run(context, async () => {
1992
+ try {
1993
+ const result = await callback();
1994
+ await Promise.all(context.cacheTasks);
1995
+ return result;
1996
+ } catch (error) {
1997
+ await Promise.allSettled(context.cacheTasks);
1998
+ throw error;
1999
+ }
2000
+ });
1961
2001
  }
1962
2002
  function getServerActionExecutionContext() {
1963
2003
  return getServerActionStorage().getStore();
@@ -2268,6 +2308,9 @@ var init_server_action_security = __esm({
2268
2308
  subscribeFarmCacheInvalidation((key) => {
2269
2309
  getServerActionExecutionContext()?.invalidations.add(key);
2270
2310
  });
2311
+ subscribeFarmCacheTask((task) => {
2312
+ getServerActionExecutionContext()?.cacheTasks.add(task);
2313
+ });
2271
2314
  __name(getServerActionStorage, "getServerActionStorage");
2272
2315
  __name(getFallbackAbortController, "getFallbackAbortController");
2273
2316
  __name(parseBodySizeLimit, "parseBodySizeLimit");
@@ -5898,7 +5941,9 @@ function readManifest(contentDir) {
5898
5941
  const manifestPath = import_node_path7.default.join(contentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
5899
5942
  if (!(0, import_node_fs5.existsSync)(manifestPath)) return null;
5900
5943
  try {
5901
- const parsed = JSON.parse((0, import_node_fs5.readFileSync)(manifestPath, "utf8"));
5944
+ const parsed = JSON.parse(
5945
+ (0, import_node_fs5.readFileSync)(manifestPath, "utf8")
5946
+ );
5902
5947
  if (parsed.version !== 1 || !parsed.pages || typeof parsed.pages !== "object") return null;
5903
5948
  const pages = Object.fromEntries(
5904
5949
  Object.entries(parsed.pages).filter(
@@ -9446,6 +9491,7 @@ async function resolveConfig(userConfig, mode) {
9446
9491
  observability: userConfig.observability ?? false,
9447
9492
  devtools: resolveFarmDevtoolsConfig(userConfig.devtools, mode),
9448
9493
  storage: userConfig.storage || {},
9494
+ cache: userConfig.cache || {},
9449
9495
  suppressLintOnLink: userConfig.suppressLintOnLink ?? false,
9450
9496
  experimental: {
9451
9497
  serverComponents: false,
@@ -12417,16 +12463,7 @@ __export(devtools_client_exports, {
12417
12463
  function parseShortcut(shortcut) {
12418
12464
  const tokens = shortcut.toLowerCase().split("+").map((token) => token.trim()).filter(Boolean);
12419
12465
  const key = tokens.find(
12420
- (token) => ![
12421
- "alt",
12422
- "ctrl",
12423
- "control",
12424
- "meta",
12425
- "cmd",
12426
- "command",
12427
- "mod",
12428
- "shift"
12429
- ].includes(token)
12466
+ (token) => !["alt", "ctrl", "control", "meta", "cmd", "command", "mod", "shift"].includes(token)
12430
12467
  );
12431
12468
  if (!key) {
12432
12469
  return null;
@@ -12709,6 +12746,7 @@ var init_image_sharp = __esm({
12709
12746
  // src/server.ts
12710
12747
  var server_exports = {};
12711
12748
  __export(server_exports, {
12749
+ DEFAULT_FARM_DEV_SERVER_PORT: () => DEFAULT_FARM_DEV_SERVER_PORT,
12712
12750
  DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT: () => DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,
12713
12751
  FARM_SERVER_QUERY_SYMBOL: () => FARM_SERVER_QUERY_SYMBOL,
12714
12752
  FarmApp: () => FarmApp,
@@ -12721,7 +12759,9 @@ __export(server_exports, {
12721
12759
  _runWithAfterRequest: () => _runWithAfterRequest,
12722
12760
  _withAfterNodeMiddleware: () => _withAfterNodeMiddleware,
12723
12761
  after: () => after,
12762
+ applyFarmCacheInvalidationTargets: () => applyFarmCacheInvalidationTargets,
12724
12763
  applyFarmCacheInvalidations: () => applyFarmCacheInvalidations,
12764
+ configureFarmCache: () => configureFarmCache,
12725
12765
  createClientOnlyFn: () => createClientOnlyFn,
12726
12766
  createFarmApp: () => createFarmApp,
12727
12767
  createFarmCacheKey: () => createFarmCacheKey,
@@ -12736,6 +12776,7 @@ __export(server_exports, {
12736
12776
  createServerQuery: () => createServerQuery,
12737
12777
  createStorageClient: () => createStorageClient,
12738
12778
  databaseStorage: () => databaseStorage,
12779
+ defineCacheKey: () => defineCacheKey,
12739
12780
  defineConfig: () => defineConfig2,
12740
12781
  defineStorageClient: () => defineStorageClient,
12741
12782
  disposeStorage: () => disposeStorage,
@@ -12786,6 +12827,7 @@ __export(server_exports, {
12786
12827
  segmentsToPattern: () => segmentsToPattern,
12787
12828
  sqliteStorage: () => sqliteStorage,
12788
12829
  startDevServer: () => startDevServer,
12830
+ storageCacheAdapter: () => storageCacheAdapter,
12789
12831
  toViteModuleId: () => toViteModuleId,
12790
12832
  unstable_cache: () => unstable_cache,
12791
12833
  updateTag: () => updateTag,
@@ -13472,12 +13514,109 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
13472
13514
 
13473
13515
  // src/cache.ts
13474
13516
  init_cache_invalidation();
13517
+ function defineCacheKey() {
13518
+ return (factory) => {
13519
+ if (typeof factory !== "function") {
13520
+ throw new TypeError("defineCacheKey expects a key factory function.");
13521
+ }
13522
+ return ((...args) => {
13523
+ const key = factory(...args);
13524
+ if (typeof key !== "string" && !Array.isArray(key)) {
13525
+ throw new TypeError(
13526
+ "A defined cache key factory must return a string or structured array."
13527
+ );
13528
+ }
13529
+ return key;
13530
+ });
13531
+ };
13532
+ }
13533
+ __name(defineCacheKey, "defineCacheKey");
13534
+ function storageCacheAdapter(storage, options = {}) {
13535
+ if (!storage || typeof storage.getItem !== "function" || typeof storage.setItem !== "function") {
13536
+ throw new TypeError("storageCacheAdapter expects a compatible storage client.");
13537
+ }
13538
+ const base = normalizeCacheNamespace(options.base || "farm-cache");
13539
+ const entryKey = /* @__PURE__ */ __name((key) => `${base}:entry:${key}`, "entryKey");
13540
+ const tagKey = /* @__PURE__ */ __name((tag) => `${base}:tag:${tag}`, "tagKey");
13541
+ return {
13542
+ name: "storage",
13543
+ get: /* @__PURE__ */ __name((key) => storage.getItem(entryKey(key)), "get"),
13544
+ set: /* @__PURE__ */ __name(async (key, entry) => {
13545
+ await storage.setItem(entryKey(key), entry);
13546
+ }, "set"),
13547
+ delete: /* @__PURE__ */ __name(async (key) => {
13548
+ await storage.removeItem(entryKey(key));
13549
+ }, "delete"),
13550
+ clear: storage.clear ? async () => {
13551
+ await storage.clear(base);
13552
+ } : void 0,
13553
+ getTagVersions: /* @__PURE__ */ __name(async (tags) => {
13554
+ const versions = await Promise.all(
13555
+ tags.map(async (tag) => {
13556
+ const value = await storage.getItem(tagKey(tag));
13557
+ return [tag, normalizeAdapterVersion(value)];
13558
+ })
13559
+ );
13560
+ return Object.fromEntries(versions);
13561
+ }, "getTagVersions"),
13562
+ invalidateTags: /* @__PURE__ */ __name(async (tags) => {
13563
+ await Promise.all(
13564
+ tags.map(async (tag) => {
13565
+ const key = tagKey(tag);
13566
+ const current = normalizeAdapterVersion(await storage.getItem(key));
13567
+ await storage.setItem(key, Math.max(Date.now(), current + 1));
13568
+ })
13569
+ );
13570
+ }, "invalidateTags")
13571
+ };
13572
+ }
13573
+ __name(storageCacheAdapter, "storageCacheAdapter");
13475
13574
  var _FarmDataCache = class _FarmDataCache {
13476
- constructor() {
13575
+ constructor(config = {}) {
13477
13576
  this.entries = /* @__PURE__ */ new Map();
13478
13577
  this.inflight = /* @__PURE__ */ new Map();
13479
13578
  this.invalidatedTagVersions = /* @__PURE__ */ new Map();
13480
13579
  this.version = 0;
13580
+ this.namespace = "farm";
13581
+ this.local = true;
13582
+ this.lease = {
13583
+ enabled: true,
13584
+ ttlMs: 1e4,
13585
+ waitTimeoutMs: 1e4,
13586
+ pollIntervalMs: 25
13587
+ };
13588
+ this.configure(config);
13589
+ }
13590
+ configure(config = {}) {
13591
+ this.adapter = config.adapter;
13592
+ this.namespace = normalizeCacheNamespace(config.namespace || "farm");
13593
+ this.local = !config.adapter;
13594
+ this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
13595
+ enabled: true,
13596
+ ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
13597
+ waitTimeoutMs: normalizePositiveDuration(
13598
+ config.lease?.waitTimeoutMs,
13599
+ 1e4,
13600
+ "cache.lease.waitTimeoutMs"
13601
+ ),
13602
+ pollIntervalMs: normalizePositiveDuration(
13603
+ config.lease?.pollIntervalMs,
13604
+ 25,
13605
+ "cache.lease.pollIntervalMs"
13606
+ )
13607
+ };
13608
+ if (!this.local) {
13609
+ this.entries.clear();
13610
+ this.inflight.clear();
13611
+ this.invalidatedTagVersions.clear();
13612
+ this.version = 0;
13613
+ }
13614
+ }
13615
+ get adapterName() {
13616
+ return this.adapter?.name || (this.adapter ? "custom" : "memory");
13617
+ }
13618
+ get hasAdapter() {
13619
+ return this.adapter !== void 0;
13481
13620
  }
13482
13621
  get size() {
13483
13622
  return this.entries.size;
@@ -13513,6 +13652,45 @@ var _FarmDataCache = class _FarmDataCache {
13513
13652
  });
13514
13653
  return this.toPublicEntry(entry);
13515
13654
  }
13655
+ async getEntryAsync(key, options = {}) {
13656
+ if (this.local) {
13657
+ const localEntry = this.getEntry(key, options);
13658
+ if (localEntry) return localEntry;
13659
+ }
13660
+ if (!this.adapter) {
13661
+ return this.local ? void 0 : this.getEntry(key, options);
13662
+ }
13663
+ const entry = await this.adapter.get(this.createAdapterKey(key));
13664
+ if (!entry) {
13665
+ emitFarmEvent({ type: "cache.miss", key });
13666
+ return void 0;
13667
+ }
13668
+ assertFarmCacheEntry(entry, key);
13669
+ const stale = await this.isAdapterEntryStale(entry, options.now);
13670
+ if (stale) {
13671
+ emitFarmEvent({
13672
+ type: "cache.stale",
13673
+ key,
13674
+ tags: [...entry.tags],
13675
+ revalidate: entry.revalidate
13676
+ });
13677
+ if (!options.allowStale) {
13678
+ emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
13679
+ return void 0;
13680
+ }
13681
+ }
13682
+ emitFarmEvent({
13683
+ type: "cache.hit",
13684
+ key,
13685
+ tags: [...entry.tags],
13686
+ revalidate: entry.revalidate,
13687
+ stale
13688
+ });
13689
+ if (this.local && !stale) {
13690
+ this.hydrateLocalEntry(entry);
13691
+ }
13692
+ return { ...entry, key };
13693
+ }
13516
13694
  set(key, value, options = {}) {
13517
13695
  const tags = /* @__PURE__ */ new Set();
13518
13696
  for (const tag of options.tags ?? []) {
@@ -13525,6 +13703,7 @@ var _FarmDataCache = class _FarmDataCache {
13525
13703
  key,
13526
13704
  value,
13527
13705
  tags,
13706
+ tagVersions: void 0,
13528
13707
  createdAt: options.createdAt ?? Date.now(),
13529
13708
  createdVersion: ++this.version,
13530
13709
  revalidate: normalizeRevalidate(options.revalidate)
@@ -13538,11 +13717,45 @@ var _FarmDataCache = class _FarmDataCache {
13538
13717
  });
13539
13718
  return this.toPublicEntry(entry);
13540
13719
  }
13720
+ async setAsync(key, value, options = {}, tagVersions) {
13721
+ const tags = normalizeCacheOptionsTags(options);
13722
+ const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
13723
+ const entry = {
13724
+ key,
13725
+ value,
13726
+ tags: Array.from(tags),
13727
+ tagVersions: capturedVersions,
13728
+ createdAt: options.createdAt ?? Date.now(),
13729
+ createdVersion: ++this.version,
13730
+ revalidate: normalizeRevalidate(options.revalidate)
13731
+ };
13732
+ if (this.local) {
13733
+ this.hydrateLocalEntry(entry);
13734
+ }
13735
+ if (this.adapter) {
13736
+ await this.adapter.set(this.createAdapterKey(key), entry);
13737
+ }
13738
+ emitFarmEvent({
13739
+ type: "cache.set",
13740
+ key,
13741
+ tags: [...entry.tags],
13742
+ revalidate: entry.revalidate
13743
+ });
13744
+ return entry;
13745
+ }
13541
13746
  delete(key) {
13542
13747
  const deleted = this.entries.delete(key);
13543
13748
  emitFarmEvent({ type: "cache.delete", key, deleted });
13544
13749
  return deleted;
13545
13750
  }
13751
+ async deleteAsync(key) {
13752
+ const deleted = this.entries.delete(key);
13753
+ if (this.adapter) {
13754
+ await this.adapter.delete(this.createAdapterKey(key));
13755
+ }
13756
+ emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
13757
+ return this.adapter ? true : deleted;
13758
+ }
13546
13759
  clear() {
13547
13760
  const count = this.entries.size;
13548
13761
  this.entries.clear();
@@ -13551,6 +13764,10 @@ var _FarmDataCache = class _FarmDataCache {
13551
13764
  this.version = 0;
13552
13765
  emitFarmEvent({ type: "cache.clear", count });
13553
13766
  }
13767
+ async clearAsync() {
13768
+ this.clear();
13769
+ await this.adapter?.clear?.();
13770
+ }
13554
13771
  isStale(entry, now = Date.now()) {
13555
13772
  if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
13556
13773
  return true;
@@ -13563,6 +13780,12 @@ var _FarmDataCache = class _FarmDataCache {
13563
13780
  }
13564
13781
  return false;
13565
13782
  }
13783
+ async isStaleAsync(entry, now = Date.now()) {
13784
+ if (this.adapter) {
13785
+ return this.isAdapterEntryStale(entry, now);
13786
+ }
13787
+ return this.isStale(entry, now);
13788
+ }
13566
13789
  revalidateTag(tag, options = {}) {
13567
13790
  const normalized = normalizeCacheTag(tag);
13568
13791
  const count = this.invalidateTag(normalized);
@@ -13571,6 +13794,15 @@ var _FarmDataCache = class _FarmDataCache {
13571
13794
  );
13572
13795
  return count;
13573
13796
  }
13797
+ async revalidateTagAsync(tag, options = {}) {
13798
+ const normalized = normalizeCacheTag(tag);
13799
+ const count = this.invalidateTag(normalized);
13800
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
13801
+ emitFarmEvent(
13802
+ options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
13803
+ );
13804
+ return count;
13805
+ }
13574
13806
  revalidatePath(routePath) {
13575
13807
  const normalizedPath = normalizeRevalidatePath(routePath);
13576
13808
  const pathTag = createPathCacheTag(normalizedPath);
@@ -13587,8 +13819,25 @@ var _FarmDataCache = class _FarmDataCache {
13587
13819
  }
13588
13820
  return count;
13589
13821
  }
13822
+ async revalidatePathAsync(routePath) {
13823
+ const normalizedPath = normalizeRevalidatePath(routePath);
13824
+ const pathTag = createPathCacheTag(normalizedPath);
13825
+ const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
13826
+ const count = this.invalidateTag(pathTag);
13827
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
13828
+ emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
13829
+ if (pprCount > 0) {
13830
+ emitFarmEvent({
13831
+ type: "ppr.shell.invalidated",
13832
+ route: normalizedPath,
13833
+ reason: "revalidatePath",
13834
+ count: pprCount
13835
+ });
13836
+ }
13837
+ return count;
13838
+ }
13590
13839
  async getOrSet(key, producer, options = {}) {
13591
- const cached = this.getEntry(key);
13840
+ const cached = await this.getEntryAsync(key);
13592
13841
  if (cached) {
13593
13842
  return cached.value;
13594
13843
  }
@@ -13597,10 +13846,8 @@ var _FarmDataCache = class _FarmDataCache {
13597
13846
  emitFarmEvent({ type: "cache.dedupe", key });
13598
13847
  return inflight;
13599
13848
  }
13600
- const promise = Promise.resolve().then(producer).then((value) => {
13601
- this.set(key, value, options);
13602
- return value;
13603
- }).catch((error) => {
13849
+ const tags = Array.from(normalizeCacheOptionsTags(options));
13850
+ const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
13604
13851
  emitFarmEvent({ type: "cache.error", key, operation: "set", error });
13605
13852
  throw error;
13606
13853
  }).finally(() => {
@@ -13609,6 +13856,40 @@ var _FarmDataCache = class _FarmDataCache {
13609
13856
  this.inflight.set(key, promise);
13610
13857
  return promise;
13611
13858
  }
13859
+ async fillCacheEntry(key, producer, options, tags) {
13860
+ const leaseKey = `${this.namespace}:lease:${key}`;
13861
+ let leaseToken;
13862
+ if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
13863
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
13864
+ if (!leaseToken) {
13865
+ const shared = await this.waitForAdapterEntry(key);
13866
+ if (shared) {
13867
+ emitFarmEvent({ type: "cache.dedupe", key });
13868
+ return shared.value;
13869
+ }
13870
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
13871
+ }
13872
+ }
13873
+ try {
13874
+ const initialTagVersions = await this.getAdapterTagVersions(tags);
13875
+ const value = await producer();
13876
+ await this.setAsync(key, value, options, initialTagVersions);
13877
+ return value;
13878
+ } finally {
13879
+ if (leaseToken && this.adapter?.releaseLease) {
13880
+ await this.adapter.releaseLease(leaseKey, leaseToken);
13881
+ }
13882
+ }
13883
+ }
13884
+ async waitForAdapterEntry(key) {
13885
+ const deadline = Date.now() + this.lease.waitTimeoutMs;
13886
+ while (Date.now() < deadline) {
13887
+ await delay(this.lease.pollIntervalMs);
13888
+ const entry = await this.getEntryAsync(key);
13889
+ if (entry) return entry;
13890
+ }
13891
+ return void 0;
13892
+ }
13612
13893
  countEntriesForTag(tag) {
13613
13894
  let count = 0;
13614
13895
  for (const entry of this.entries.values()) {
@@ -13636,11 +13917,53 @@ var _FarmDataCache = class _FarmDataCache {
13636
13917
  key: entry.key,
13637
13918
  value: entry.value,
13638
13919
  tags: Array.from(entry.tags),
13920
+ tagVersions: entry.tagVersions,
13639
13921
  createdAt: entry.createdAt,
13640
13922
  createdVersion: entry.createdVersion,
13641
13923
  revalidate: entry.revalidate
13642
13924
  };
13643
13925
  }
13926
+ hydrateLocalEntry(entry) {
13927
+ this.entries.set(entry.key, {
13928
+ key: entry.key,
13929
+ value: entry.value,
13930
+ tags: new Set(entry.tags.map(normalizeCacheTag)),
13931
+ tagVersions: entry.tagVersions,
13932
+ createdAt: entry.createdAt,
13933
+ createdVersion: entry.createdVersion ?? ++this.version,
13934
+ revalidate: normalizeRevalidate(entry.revalidate)
13935
+ });
13936
+ }
13937
+ createAdapterKey(key) {
13938
+ return `${this.namespace}:entry:${key}`;
13939
+ }
13940
+ createAdapterTag(tag) {
13941
+ return `${this.namespace}:tag:${tag}`;
13942
+ }
13943
+ async getAdapterTagVersions(tags) {
13944
+ if (!this.adapter?.getTagVersions || tags.length === 0) return {};
13945
+ const normalized = tags.map(normalizeCacheTag);
13946
+ const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
13947
+ const versions = await this.adapter.getTagVersions(physicalTags);
13948
+ return Object.fromEntries(
13949
+ normalized.map((tag, index) => [
13950
+ tag,
13951
+ normalizeAdapterVersion(versions[physicalTags[index]])
13952
+ ])
13953
+ );
13954
+ }
13955
+ async isAdapterEntryStale(entry, now = Date.now()) {
13956
+ if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
13957
+ return true;
13958
+ }
13959
+ const currentVersions = await this.getAdapterTagVersions(entry.tags);
13960
+ for (const tag of entry.tags) {
13961
+ if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
13962
+ return true;
13963
+ }
13964
+ }
13965
+ return false;
13966
+ }
13644
13967
  };
13645
13968
  __name(_FarmDataCache, "FarmDataCache");
13646
13969
  var FarmDataCache = _FarmDataCache;
@@ -13653,6 +13976,10 @@ function getFarmDataCache() {
13653
13976
  return sharedFarmDataCache;
13654
13977
  }
13655
13978
  __name(getFarmDataCache, "getFarmDataCache");
13979
+ function configureFarmCache(config) {
13980
+ sharedFarmDataCache.configure(config);
13981
+ }
13982
+ __name(configureFarmCache, "configureFarmCache");
13656
13983
  function unstable_cache(fn, keyParts = [], options = {}) {
13657
13984
  return async (...args) => {
13658
13985
  const locale = getActiveFarmI18nSnapshot()?.locale;
@@ -13668,30 +13995,71 @@ function unstable_cache(fn, keyParts = [], options = {}) {
13668
13995
  }
13669
13996
  __name(unstable_cache, "unstable_cache");
13670
13997
  function revalidateTag(_tag, _profile) {
13671
- getFarmDataCache().revalidateTag(_tag, {
13998
+ const cache = getFarmDataCache();
13999
+ if (cache.hasAdapter) {
14000
+ const task = cache.revalidateTagAsync(_tag, {
14001
+ source: "revalidateTag",
14002
+ profile: _profile
14003
+ }).then(() => void 0);
14004
+ notifyFarmCacheTask(task);
14005
+ return task;
14006
+ }
14007
+ cache.revalidateTag(_tag, {
13672
14008
  source: "revalidateTag",
13673
14009
  profile: _profile
13674
14010
  });
13675
14011
  }
13676
14012
  __name(revalidateTag, "revalidateTag");
13677
14013
  function updateTag(tag) {
13678
- getFarmDataCache().revalidateTag(tag, { source: "updateTag" });
14014
+ const cache = getFarmDataCache();
14015
+ if (cache.hasAdapter) {
14016
+ const task = cache.revalidateTagAsync(tag, { source: "updateTag" }).then(() => void 0);
14017
+ notifyFarmCacheTask(task);
14018
+ return task;
14019
+ }
14020
+ cache.revalidateTag(tag, { source: "updateTag" });
13679
14021
  }
13680
14022
  __name(updateTag, "updateTag");
13681
14023
  function revalidatePath(routePath) {
13682
- getFarmDataCache().revalidatePath(routePath);
14024
+ const cache = getFarmDataCache();
14025
+ if (cache.hasAdapter) {
14026
+ const task = cache.revalidatePathAsync(routePath).then(() => void 0);
14027
+ notifyFarmCacheTask(task);
14028
+ return task;
14029
+ }
14030
+ cache.revalidatePath(routePath);
13683
14031
  }
13684
14032
  __name(revalidatePath, "revalidatePath");
13685
14033
  function invalidate(key) {
13686
14034
  const clientKey = createRouteDataCacheKey(key);
13687
- getFarmDataCache().revalidateTag(createRouteDataCacheTag(key), { source: "updateTag" });
14035
+ const task = updateTag(createRouteDataCacheTag(key));
13688
14036
  notifyFarmCacheInvalidation(clientKey);
14037
+ return task;
13689
14038
  }
13690
14039
  __name(invalidate, "invalidate");
13691
14040
  function invalidateRouteData(key) {
13692
- invalidate(key);
14041
+ return invalidate(key);
13693
14042
  }
13694
14043
  __name(invalidateRouteData, "invalidateRouteData");
14044
+ async function applyFarmCacheInvalidationTargets(targets) {
14045
+ if (!Array.isArray(targets)) {
14046
+ throw new TypeError("Cache invalidations must resolve to an array of targets.");
14047
+ }
14048
+ const clientKeys = [];
14049
+ for (const target of targets) {
14050
+ assertFarmCacheInvalidationTarget(target);
14051
+ if ("key" in target) {
14052
+ await invalidate(target.key);
14053
+ clientKeys.push(createRouteDataCacheKey(target.key));
14054
+ } else if ("path" in target) {
14055
+ await revalidatePath(target.path);
14056
+ } else {
14057
+ await updateTag(target.tag);
14058
+ }
14059
+ }
14060
+ return Array.from(new Set(clientKeys));
14061
+ }
14062
+ __name(applyFarmCacheInvalidationTargets, "applyFarmCacheInvalidationTargets");
13695
14063
  function createPathCacheTag(routePath) {
13696
14064
  return `path:${normalizeRevalidatePath(routePath)}`;
13697
14065
  }
@@ -13752,6 +14120,67 @@ function normalizeCacheTag(tag) {
13752
14120
  return normalized;
13753
14121
  }
13754
14122
  __name(normalizeCacheTag, "normalizeCacheTag");
14123
+ function normalizeCacheNamespace(namespace) {
14124
+ if (typeof namespace !== "string") {
14125
+ throw new TypeError("Cache namespace must be a string.");
14126
+ }
14127
+ const normalized = namespace.trim().replace(/:+$/g, "");
14128
+ if (!normalized) {
14129
+ throw new Error("Cache namespace cannot be empty.");
14130
+ }
14131
+ return normalized;
14132
+ }
14133
+ __name(normalizeCacheNamespace, "normalizeCacheNamespace");
14134
+ function normalizeAdapterVersion(value) {
14135
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
14136
+ }
14137
+ __name(normalizeAdapterVersion, "normalizeAdapterVersion");
14138
+ function normalizePositiveDuration(value, fallback, name) {
14139
+ if (value === void 0) return fallback;
14140
+ if (!Number.isFinite(value) || value <= 0) {
14141
+ throw new TypeError(`${name} must be a positive number of milliseconds.`);
14142
+ }
14143
+ return Math.floor(value);
14144
+ }
14145
+ __name(normalizePositiveDuration, "normalizePositiveDuration");
14146
+ function delay(ms) {
14147
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
14148
+ }
14149
+ __name(delay, "delay");
14150
+ function normalizeCacheOptionsTags(options) {
14151
+ const tags = /* @__PURE__ */ new Set();
14152
+ for (const tag of options.tags ?? []) {
14153
+ tags.add(normalizeCacheTag(tag));
14154
+ }
14155
+ for (const routePath of options.paths ?? []) {
14156
+ tags.add(createPathCacheTag(routePath));
14157
+ }
14158
+ return tags;
14159
+ }
14160
+ __name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
14161
+ function assertFarmCacheEntry(entry, expectedKey) {
14162
+ if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
14163
+ throw new TypeError(
14164
+ `Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
14165
+ );
14166
+ }
14167
+ }
14168
+ __name(assertFarmCacheEntry, "assertFarmCacheEntry");
14169
+ function assertFarmCacheInvalidationTarget(target) {
14170
+ if (!target || typeof target !== "object") {
14171
+ throw new TypeError("Cache invalidation targets must be { key }, { path }, or { tag }.");
14172
+ }
14173
+ if ("key" in target) {
14174
+ const key = target.key;
14175
+ if (typeof key === "string" || Array.isArray(key)) return;
14176
+ } else if ("path" in target && typeof target.path === "string") {
14177
+ return;
14178
+ } else if ("tag" in target && typeof target.tag === "string") {
14179
+ return;
14180
+ }
14181
+ throw new TypeError("Cache invalidation targets must contain a string/array key, path, or tag.");
14182
+ }
14183
+ __name(assertFarmCacheInvalidationTarget, "assertFarmCacheInvalidationTarget");
13755
14184
  function getFunctionCacheIdentity(fn) {
13756
14185
  if (fn.name) {
13757
14186
  return `name:${fn.name}`;
@@ -14892,6 +15321,76 @@ function normalizePathname(pathname) {
14892
15321
  }
14893
15322
  __name(normalizePathname, "normalizePathname");
14894
15323
 
15324
+ // src/routing/route-slots.ts
15325
+ var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
15326
+ function parseRouteSlotFile(filePath) {
15327
+ const normalized = filePath.replace(/\\/g, "/");
15328
+ const parts = normalized.split("/").filter(Boolean);
15329
+ const fileName = parts.at(-1) ?? "";
15330
+ const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
15331
+ if (baseName !== "page" && baseName !== "default") return null;
15332
+ const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
15333
+ if (slotIndex < 0) return null;
15334
+ if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
15335
+ throw new Error(`Nested route slots are not supported in "${filePath}"`);
15336
+ }
15337
+ const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
15338
+ const name = slotMatch?.[1];
15339
+ if (!name) return null;
15340
+ const ownerParts = parts.slice(0, slotIndex);
15341
+ const contentParts = parts.slice(slotIndex + 1, -1);
15342
+ const marker = parseInterceptionMarker(contentParts[0]);
15343
+ let targetBase = ownerParts;
15344
+ let targetParts = contentParts;
15345
+ if (marker) {
15346
+ targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
15347
+ targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
15348
+ }
15349
+ const ownerFile = [...ownerParts, "layout.tsx"].join("/");
15350
+ const routeFile = [
15351
+ ...baseName === "default" ? ownerParts : targetBase,
15352
+ ...baseName === "default" ? [] : targetParts,
15353
+ "page.tsx"
15354
+ ].join("/");
15355
+ return {
15356
+ name,
15357
+ ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
15358
+ route: parseRoutePath(routeFile || "page.tsx"),
15359
+ interception: marker !== null,
15360
+ fallback: baseName === "default"
15361
+ };
15362
+ }
15363
+ __name(parseRouteSlotFile, "parseRouteSlotFile");
15364
+ function createRouteSlotContainerId(name, ownerPattern) {
15365
+ const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
15366
+ return `__farm_slot_${name}_${owner || "root"}__`;
15367
+ }
15368
+ __name(createRouteSlotContainerId, "createRouteSlotContainerId");
15369
+ function parseInterceptionMarker(segment) {
15370
+ if (!segment) return null;
15371
+ if (segment.startsWith("(...)")) {
15372
+ return {
15373
+ up: 0,
15374
+ root: true,
15375
+ remainder: segment.slice(5)
15376
+ };
15377
+ }
15378
+ if (segment.startsWith("(.)")) {
15379
+ return {
15380
+ up: 0,
15381
+ remainder: segment.slice(3)
15382
+ };
15383
+ }
15384
+ let remainder = segment;
15385
+ let up = 0;
15386
+ while (remainder.startsWith("(..)")) {
15387
+ up += 1;
15388
+ remainder = remainder.slice(4);
15389
+ }
15390
+ return up > 0 ? { up, remainder } : null;
15391
+ }
15392
+ __name(parseInterceptionMarker, "parseInterceptionMarker");
15393
+
14895
15394
  // src/routing/route-manager.ts
14896
15395
  function routeSpecificity(entry) {
14897
15396
  return entry.route.segments.reduce((score, segment) => {
@@ -14905,6 +15404,7 @@ var _RouteManager = class _RouteManager {
14905
15404
  constructor(config, viteServer) {
14906
15405
  this.routes = /* @__PURE__ */ new Map();
14907
15406
  this.layouts = /* @__PURE__ */ new Map();
15407
+ this.routeSlots = /* @__PURE__ */ new Map();
14908
15408
  this.loadings = /* @__PURE__ */ new Map();
14909
15409
  this.errors = /* @__PURE__ */ new Map();
14910
15410
  this.metadataImages = /* @__PURE__ */ new Map();
@@ -14920,6 +15420,7 @@ var _RouteManager = class _RouteManager {
14920
15420
  async discoverRoutes() {
14921
15421
  this.routes.clear();
14922
15422
  this.layouts.clear();
15423
+ this.routeSlots.clear();
14923
15424
  this.loadings.clear();
14924
15425
  this.errors.clear();
14925
15426
  this.metadataImages.clear();
@@ -14930,6 +15431,13 @@ var _RouteManager = class _RouteManager {
14930
15431
  await this.discoverFileRoutes(source);
14931
15432
  await this.discoverProgrammaticRoutes(source);
14932
15433
  }
15434
+ for (const slot of this.routeSlots.values()) {
15435
+ if (slot.interception && !this.routes.has(slot.pattern)) {
15436
+ throw new Error(
15437
+ `Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
15438
+ );
15439
+ }
15440
+ }
14933
15441
  this.routes = new Map(
14934
15442
  Array.from(this.routes.entries()).sort(
14935
15443
  ([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
@@ -14945,7 +15453,7 @@ var _RouteManager = class _RouteManager {
14945
15453
  /**
14946
15454
  * Find matching route for a given URL path
14947
15455
  */
14948
- matchRoute(pathname) {
15456
+ matchRoute(pathname, options = {}) {
14949
15457
  const routePathname = this.toRoutePathname(pathname);
14950
15458
  const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
14951
15459
  let matchedRoute = null;
@@ -14959,10 +15467,12 @@ var _RouteManager = class _RouteManager {
14959
15467
  }
14960
15468
  }
14961
15469
  const layouts = this.findMatchingLayouts(normalizedPath);
15470
+ const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
14962
15471
  return {
14963
15472
  route: matchedRoute,
14964
15473
  params,
14965
- layouts
15474
+ layouts,
15475
+ slots
14966
15476
  };
14967
15477
  }
14968
15478
  /**
@@ -14977,6 +15487,9 @@ var _RouteManager = class _RouteManager {
14977
15487
  getLayouts() {
14978
15488
  return new Map(this.layouts);
14979
15489
  }
15490
+ getRouteSlots() {
15491
+ return new Map(this.routeSlots);
15492
+ }
14980
15493
  /** Resolve route rules, inherited layouts, and the page export in precedence order. */
14981
15494
  async resolveRouteRuntimeConfig(pattern) {
14982
15495
  const routeEntry = this.routes.get(pattern);
@@ -15135,7 +15648,22 @@ var _RouteManager = class _RouteManager {
15135
15648
  pattern: entry.pattern,
15136
15649
  modulePath: toUrlPath(entry.modulePath)
15137
15650
  }));
15138
- return { routes, layouts };
15651
+ const slots = Array.from(this.routeSlots.values()).map((entry) => {
15652
+ const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
15653
+ return {
15654
+ name: entry.name,
15655
+ ownerPattern: entry.ownerPattern,
15656
+ pattern: entry.pattern,
15657
+ modulePath: toUrlPath(entry.modulePath),
15658
+ containerId: entry.containerId,
15659
+ interception: entry.interception,
15660
+ fallback: entry.fallback,
15661
+ shouldHydrate: metadata.shouldHydrate,
15662
+ isClientComponent: metadata.isClientComponent,
15663
+ segments: entry.route.segments
15664
+ };
15665
+ });
15666
+ return { routes, layouts, slots };
15139
15667
  }
15140
15668
  /**
15141
15669
  * Load a route module dynamically
@@ -15212,6 +15740,7 @@ var _RouteManager = class _RouteManager {
15212
15740
  async discoverFileRoutes(source) {
15213
15741
  const appDir = resolveAppPath(source.root, source.srcDir, "app");
15214
15742
  const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
15743
+ const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
15215
15744
  const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
15216
15745
  const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
15217
15746
  const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
@@ -15220,7 +15749,7 @@ var _RouteManager = class _RouteManager {
15220
15749
  appDir
15221
15750
  );
15222
15751
  for (const [kind, files, target] of [
15223
- ["page", pageFiles, this.routes],
15752
+ ["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
15224
15753
  ["layout", layoutFiles, this.layouts],
15225
15754
  ["loading", loadingFiles, this.loadings],
15226
15755
  ["error", errorFiles, this.errors]
@@ -15244,6 +15773,32 @@ var _RouteManager = class _RouteManager {
15244
15773
  });
15245
15774
  }
15246
15775
  }
15776
+ for (const file of [...pageFiles, ...slotDefaultFiles]) {
15777
+ const slot = parseRouteSlotFile(file);
15778
+ if (!slot) continue;
15779
+ const modulePath = import_path5.default.join(appDir, file);
15780
+ const pattern = this.createRoutePattern(slot.route);
15781
+ const ownerPattern = this.createRoutePattern(slot.ownerRoute);
15782
+ const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
15783
+ const existing = this.routeSlots.get(key);
15784
+ if (existing?.sourceRoot === source.root) {
15785
+ throw new Error(
15786
+ `Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
15787
+ );
15788
+ }
15789
+ this.routeSlots.set(key, {
15790
+ route: slot.route,
15791
+ modulePath,
15792
+ pattern,
15793
+ source: "file",
15794
+ sourceRoot: source.root,
15795
+ name: slot.name,
15796
+ ownerPattern,
15797
+ interception: slot.interception,
15798
+ fallback: slot.fallback,
15799
+ containerId: createRouteSlotContainerId(slot.name, ownerPattern)
15800
+ });
15801
+ }
15247
15802
  for (const file of metadataImageFiles) {
15248
15803
  const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
15249
15804
  const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
@@ -15369,6 +15924,71 @@ var _RouteManager = class _RouteManager {
15369
15924
  }
15370
15925
  return matchingLayouts;
15371
15926
  }
15927
+ findMatchingRouteSlots(pathname, interceptFrom) {
15928
+ const groups = /* @__PURE__ */ new Map();
15929
+ for (const entry of this.routeSlots.values()) {
15930
+ if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
15931
+ const key = `${entry.ownerPattern}:${entry.name}`;
15932
+ const entries = groups.get(key) ?? [];
15933
+ entries.push(entry);
15934
+ groups.set(key, entries);
15935
+ }
15936
+ const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
15937
+ const matches = [];
15938
+ for (const entries of groups.values()) {
15939
+ const candidates = entries.filter((entry) => !entry.fallback).filter(
15940
+ (entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
15941
+ ).map((entry) => ({
15942
+ entry,
15943
+ match: matchRoute(pathname, entry.route.segments)
15944
+ })).filter((candidate) => candidate.match.matches).sort((left, right) => {
15945
+ if (left.entry.interception !== right.entry.interception) {
15946
+ return left.entry.interception ? -1 : 1;
15947
+ }
15948
+ return routeSpecificity(right.entry) - routeSpecificity(left.entry);
15949
+ });
15950
+ const selected = candidates[0];
15951
+ if (selected) {
15952
+ matches.push({
15953
+ name: selected.entry.name,
15954
+ ownerPattern: selected.entry.ownerPattern,
15955
+ containerId: selected.entry.containerId,
15956
+ interception: selected.entry.interception,
15957
+ fallback: false,
15958
+ route: selected.entry,
15959
+ params: selected.match.params
15960
+ });
15961
+ continue;
15962
+ }
15963
+ const fallback = entries.find((entry) => entry.fallback);
15964
+ if (fallback) {
15965
+ matches.push({
15966
+ name: fallback.name,
15967
+ ownerPattern: fallback.ownerPattern,
15968
+ containerId: fallback.containerId,
15969
+ interception: false,
15970
+ fallback: true,
15971
+ route: fallback,
15972
+ params: {}
15973
+ });
15974
+ }
15975
+ }
15976
+ return matches.sort((left, right) => {
15977
+ const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
15978
+ return ownerDifference || left.name.localeCompare(right.name);
15979
+ });
15980
+ }
15981
+ matchesRoutePrefix(pathname, pattern) {
15982
+ if (pattern === "/") return true;
15983
+ const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
15984
+ const pathSegments = pathname.split("/").filter(Boolean);
15985
+ if (patternSegments.length > pathSegments.length) return false;
15986
+ for (let index = 0; index < patternSegments.length; index++) {
15987
+ const segment = patternSegments[index];
15988
+ if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
15989
+ }
15990
+ return true;
15991
+ }
15372
15992
  findNearestBoundary(pathname, boundaries) {
15373
15993
  const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
15374
15994
  const pathSegments = normalizedPath.split("/").filter(Boolean);
@@ -15985,7 +16605,7 @@ function mergeMetadata(base, next) {
15985
16605
  __name(mergeMetadata, "mergeMetadata");
15986
16606
  function addMetadataImageReference(metadata, reference) {
15987
16607
  if (reference.kind === "opengraph") {
15988
- const openGraph = { ...metadata.openGraph || {} };
16608
+ const openGraph = { ...metadata.openGraph };
15989
16609
  if (!hasMetadataImages(openGraph.images) && !hasMetadataImages(openGraph.image)) {
15990
16610
  openGraph.images = [
15991
16611
  {
@@ -16002,7 +16622,7 @@ function addMetadataImageReference(metadata, reference) {
16002
16622
  openGraph
16003
16623
  };
16004
16624
  }
16005
- const twitter = { ...metadata.twitter || {} };
16625
+ const twitter = { ...metadata.twitter };
16006
16626
  if (!hasMetadataImages(twitter.images)) {
16007
16627
  twitter.images = [reference.href];
16008
16628
  twitter.card = twitter.card || "summary_large_image";
@@ -16608,8 +17228,8 @@ var _FarmI18nRuntime = class _FarmI18nRuntime {
16608
17228
  cookie: this.config.cookie,
16609
17229
  direction: getFarmLocaleDirection(resolution.locale, this.config.direction),
16610
17230
  messages: {
16611
- ...this.catalogs[this.config.fallbackLocale] || {},
16612
- ...this.catalogs[resolution.locale] || {}
17231
+ ...this.catalogs[this.config.fallbackLocale],
17232
+ ...this.catalogs[resolution.locale]
16613
17233
  }
16614
17234
  };
16615
17235
  }
@@ -16911,7 +17531,9 @@ var _ServerRenderer = class _ServerRenderer {
16911
17531
  async runWithRequestContext(request, fn) {
16912
17532
  return _runWithCurrentRequest(
16913
17533
  request,
16914
- () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, { redirect: false }) : fn()
17534
+ () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
17535
+ redirect: false
17536
+ }) : fn()
16915
17537
  );
16916
17538
  }
16917
17539
  async resolveRouteContext(input) {
@@ -16934,11 +17556,11 @@ var _ServerRenderer = class _ServerRenderer {
16934
17556
  /**
16935
17557
  * Check if a path should be served from SSG cache
16936
17558
  */
16937
- shouldServeSSG(pathname) {
17559
+ async shouldServeSSG(pathname) {
16938
17560
  const ssgPage = matchSSGPage(pathname, this.ssgManifest);
16939
17561
  if (!ssgPage) return null;
16940
- const cached = this.getCachedSSGPage(pathname);
16941
- if (cached && this.dataCache.isStale(cached)) {
17562
+ const cached = await this.getCachedSSGPage(pathname);
17563
+ if (cached && await this.dataCache.isStaleAsync(cached)) {
16942
17564
  this.regenerateSSGPage(ssgPage);
16943
17565
  }
16944
17566
  return ssgPage;
@@ -16950,12 +17572,12 @@ var _ServerRenderer = class _ServerRenderer {
16950
17572
  return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
16951
17573
  }
16952
17574
  getCachedSSGPage(urlPath) {
16953
- return this.dataCache.getEntry(this.getSSGCacheKey(urlPath), {
17575
+ return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
16954
17576
  allowStale: true
16955
17577
  });
16956
17578
  }
16957
- cacheSSGPage(page2, html, options) {
16958
- this.dataCache.set(
17579
+ async cacheSSGPage(page2, html, options) {
17580
+ await this.dataCache.setAsync(
16959
17581
  this.getSSGCacheKey(page2.urlPath),
16960
17582
  { html, document: options.document },
16961
17583
  {
@@ -16967,11 +17589,11 @@ var _ServerRenderer = class _ServerRenderer {
16967
17589
  );
16968
17590
  }
16969
17591
  getCachedPPRShell(pathname, search) {
16970
- return this.dataCache.getEntry(this.getPPRCacheKey(pathname, search));
17592
+ return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
16971
17593
  }
16972
- cachePPRShell(options, html) {
17594
+ async cachePPRShell(options, html) {
16973
17595
  const key = this.getPPRCacheKey(options.pathname, options.search);
16974
- this.dataCache.set(
17596
+ await this.dataCache.setAsync(
16975
17597
  key,
16976
17598
  { html },
16977
17599
  {
@@ -17069,7 +17691,7 @@ var _ServerRenderer = class _ServerRenderer {
17069
17691
  }
17070
17692
  const { renderToString } = await import("react-dom/server");
17071
17693
  const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
17072
- this.cacheSSGPage(page2, html, { document: false });
17694
+ await this.cacheSSGPage(page2, html, { document: false });
17073
17695
  logger.info(`ISR: Regenerated ${page2.urlPath}`);
17074
17696
  } catch (error) {
17075
17697
  logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
@@ -17083,7 +17705,7 @@ var _ServerRenderer = class _ServerRenderer {
17083
17705
  * Serve a pre-rendered SSG page
17084
17706
  */
17085
17707
  async serveSSGPage(req, res, page2) {
17086
- const cached = this.getCachedSSGPage(page2.urlPath);
17708
+ const cached = await this.getCachedSSGPage(page2.urlPath);
17087
17709
  if (cached) {
17088
17710
  res.setHeader("Content-Type", "text/html; charset=utf-8");
17089
17711
  res.setHeader("X-Farm-SSG", "cached");
@@ -17101,9 +17723,12 @@ var _ServerRenderer = class _ServerRenderer {
17101
17723
  if (fs2.existsSync(htmlPath)) {
17102
17724
  const stat = fs2.statSync(htmlPath);
17103
17725
  const html = fs2.readFileSync(htmlPath, "utf-8");
17104
- this.cacheSSGPage(page2, html, { document: true, createdAt: stat.mtimeMs });
17105
- const fileCacheEntry = this.getCachedSSGPage(page2.urlPath);
17106
- if (fileCacheEntry && this.dataCache.isStale(fileCacheEntry)) {
17726
+ await this.cacheSSGPage(page2, html, {
17727
+ document: true,
17728
+ createdAt: stat.mtimeMs
17729
+ });
17730
+ const fileCacheEntry = await this.getCachedSSGPage(page2.urlPath);
17731
+ if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
17107
17732
  this.regenerateSSGPage(page2);
17108
17733
  }
17109
17734
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -17149,6 +17774,7 @@ var _ServerRenderer = class _ServerRenderer {
17149
17774
  let pathname = "/";
17150
17775
  let params = {};
17151
17776
  let layouts = [];
17777
+ let routeSlots = [];
17152
17778
  let searchParamsObject = {};
17153
17779
  let middlewareMap = /* @__PURE__ */ new Map();
17154
17780
  let middlewareContext = /* @__PURE__ */ new Map();
@@ -17181,7 +17807,7 @@ var _ServerRenderer = class _ServerRenderer {
17181
17807
  }
17182
17808
  this.applyDeploymentHeaders(req, res);
17183
17809
  if (process.env.NODE_ENV === "production") {
17184
- const ssgPage = this.shouldServeSSG(pathname);
17810
+ const ssgPage = await this.shouldServeSSG(pathname);
17185
17811
  if (ssgPage) {
17186
17812
  const served = await this.serveSSGPage(req, res, ssgPage);
17187
17813
  if (served) {
@@ -17194,6 +17820,7 @@ var _ServerRenderer = class _ServerRenderer {
17194
17820
  const route = match.route;
17195
17821
  params = match.params;
17196
17822
  layouts = match.layouts;
17823
+ routeSlots = match.slots ?? [];
17197
17824
  if (!route) {
17198
17825
  emitFarmEvent({ type: "route.notFound", pathname });
17199
17826
  await this.render404(req, res);
@@ -17210,7 +17837,9 @@ var _ServerRenderer = class _ServerRenderer {
17210
17837
  errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
17211
17838
  middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
17212
17839
  middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
17213
- pluginExposedContext = getRequestContextSnapshot(req, { exposedOnly: true });
17840
+ pluginExposedContext = getRequestContextSnapshot(req, {
17841
+ exposedOnly: true
17842
+ });
17214
17843
  const currentRequest = createWebRequestFromFarmRequest(req);
17215
17844
  const routeContext = await this.resolveRouteContext({
17216
17845
  request: currentRequest,
@@ -17274,8 +17903,16 @@ var _ServerRenderer = class _ServerRenderer {
17274
17903
  revalidate: renderingConfig.revalidate
17275
17904
  } : void 0;
17276
17905
  if (renderingConfig.ppr && pprBypassReason) {
17277
- emitFarmEvent({ type: "ppr.shell.bypass", route: pathname, reason: pprBypassReason });
17278
- emitFarmEvent({ type: "cache.bypass", route: pathname, reason: pprBypassReason });
17906
+ emitFarmEvent({
17907
+ type: "ppr.shell.bypass",
17908
+ route: pathname,
17909
+ reason: pprBypassReason
17910
+ });
17911
+ emitFarmEvent({
17912
+ type: "cache.bypass",
17913
+ route: pathname,
17914
+ reason: pprBypassReason
17915
+ });
17279
17916
  if (pprBypassReason === "refresh") {
17280
17917
  pprRefreshRoute = pathname;
17281
17918
  emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
@@ -17283,14 +17920,22 @@ var _ServerRenderer = class _ServerRenderer {
17283
17920
  }
17284
17921
  if (pprShellOptions) {
17285
17922
  const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
17286
- const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
17923
+ const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
17287
17924
  if (cachedPPRShell) {
17288
- emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
17925
+ emitFarmEvent({
17926
+ type: "ppr.shell.hit",
17927
+ route: pathname,
17928
+ key: pprCacheKey
17929
+ });
17289
17930
  this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
17290
17931
  completeRender(res.statusCode || 200, pathname);
17291
17932
  return;
17292
17933
  }
17293
- emitFarmEvent({ type: "ppr.shell.miss", route: pathname, key: pprCacheKey });
17934
+ emitFarmEvent({
17935
+ type: "ppr.shell.miss",
17936
+ route: pathname,
17937
+ key: pprCacheKey
17938
+ });
17294
17939
  }
17295
17940
  let LoadingFallbackComponent = null;
17296
17941
  if (loadingBoundaryEntry) {
@@ -17314,14 +17959,77 @@ var _ServerRenderer = class _ServerRenderer {
17314
17959
  );
17315
17960
  const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
17316
17961
  const isClientComponent = moduleMetadata.isClientComponent;
17962
+ const renderedRouteSlots = await Promise.all(
17963
+ routeSlots.map(async (slot) => {
17964
+ const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
17965
+ if (!slotModule.default) {
17966
+ throw new Error(
17967
+ `Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
17968
+ );
17969
+ }
17970
+ const slotContext = await this.resolveRouteContext({
17971
+ request: currentRequest,
17972
+ rawRequest: req,
17973
+ params: slot.params,
17974
+ search: searchParamsObject,
17975
+ path: pathname
17976
+ });
17977
+ const rawSlotProps = withFarmRouteContext(
17978
+ {
17979
+ params: slot.params,
17980
+ searchParams: Promise.resolve(searchParamsObject),
17981
+ path: pathname,
17982
+ middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
17983
+ context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
17984
+ },
17985
+ slotContext
17986
+ );
17987
+ const slotProps = await parseRouteModuleProps(slotModule, {
17988
+ props: rawSlotProps,
17989
+ search: searchParamsObject,
17990
+ routePath: slot.route.pattern
17991
+ });
17992
+ const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
17993
+ return {
17994
+ ...slot,
17995
+ module: slotModule,
17996
+ props: slotProps,
17997
+ isClientComponent: metadata.isClientComponent,
17998
+ shouldHydrate: metadata.shouldHydrate
17999
+ };
18000
+ })
18001
+ );
17317
18002
  const shouldHydrate = moduleMetadata.shouldHydrate;
18003
+ const hasHydratableRouteSlots = renderedRouteSlots.some(
18004
+ (slot) => slot.isClientComponent || slot.shouldHydrate
18005
+ );
17318
18006
  req.__FARM_PAGE_PATH__ = route.modulePath;
17319
18007
  req.__FARM_ROUTE__ = pathname;
17320
18008
  req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
17321
18009
  req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
18010
+ req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
17322
18011
  req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
17323
18012
  loadingBoundaryEntry.modulePath.indexOf("/src/app/")
17324
18013
  ) : null;
18014
+ req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
18015
+ name: slot.name,
18016
+ ownerPattern: slot.ownerPattern,
18017
+ containerId: slot.containerId,
18018
+ interception: slot.interception,
18019
+ fallback: slot.fallback,
18020
+ modulePath: slot.route.modulePath,
18021
+ isClientComponent: slot.isClientComponent,
18022
+ shouldHydrate: slot.shouldHydrate,
18023
+ props: {
18024
+ params: slot.props.params,
18025
+ search: slot.props.search,
18026
+ searchParams: slot.props.search,
18027
+ ..."data" in slot.props ? { data: slot.props.data } : {},
18028
+ ...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
18029
+ ...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
18030
+ path: pathname
18031
+ }
18032
+ }));
17325
18033
  req.__FARM_PROPS__ = {
17326
18034
  params: pageProps.params,
17327
18035
  search: pageProps.search,
@@ -17381,12 +18089,32 @@ var _ServerRenderer = class _ServerRenderer {
17381
18089
  let wrappedElement = pageElement;
17382
18090
  for (let i = layoutModules.length - 1; i >= 0; i--) {
17383
18091
  const layoutModule = layoutModules[i];
18092
+ const layoutEntry = layouts[i];
17384
18093
  const LayoutComponent = layoutModule.default;
18094
+ const slotProps = {};
18095
+ for (const slot of renderedRouteSlots) {
18096
+ if (slot.ownerPattern !== layoutEntry.pattern) continue;
18097
+ let slotElement = import_react4.default.createElement(
18098
+ slot.module.default,
18099
+ slot.props
18100
+ );
18101
+ slotElement = import_react4.default.createElement(
18102
+ "div",
18103
+ {
18104
+ id: slot.containerId,
18105
+ "data-farm-route-slot": slot.name,
18106
+ "data-farm-slot-owner": slot.ownerPattern
18107
+ },
18108
+ slotElement
18109
+ );
18110
+ slotProps[slot.name] = slotElement;
18111
+ }
17385
18112
  wrappedElement = import_react4.default.createElement(
17386
18113
  LayoutComponent,
17387
18114
  {
17388
18115
  children: wrappedElement,
17389
- params
18116
+ params,
18117
+ ...slotProps
17390
18118
  }
17391
18119
  );
17392
18120
  }
@@ -17423,7 +18151,10 @@ var _ServerRenderer = class _ServerRenderer {
17423
18151
  routeManifest,
17424
18152
  captureStaticShell: Boolean(pprShellOptions),
17425
18153
  observabilityRoute: pathname,
17426
- onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({ type: "ppr.suspense.holeDetected", route: pathname }) : void 0,
18154
+ onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
18155
+ type: "ppr.suspense.holeDetected",
18156
+ route: pathname
18157
+ }) : void 0,
17427
18158
  onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
17428
18159
  }
17429
18160
  );
@@ -17471,7 +18202,11 @@ var _ServerRenderer = class _ServerRenderer {
17471
18202
  }
17472
18203
  emitFarmEvent({ type: "render.error", route: pathname, error });
17473
18204
  if (pprRefreshRoute) {
17474
- emitFarmEvent({ type: "ppr.refresh.error", route: pprRefreshRoute, error });
18205
+ emitFarmEvent({
18206
+ type: "ppr.refresh.error",
18207
+ route: pprRefreshRoute,
18208
+ error
18209
+ });
17475
18210
  }
17476
18211
  logger.error(`Error rendering page: ${error}`);
17477
18212
  if (res.headersSent || res.writableEnded) {
@@ -17524,7 +18259,9 @@ var _ServerRenderer = class _ServerRenderer {
17524
18259
  if (typeof layoutModule.generateMetadata === "function") {
17525
18260
  metadata = mergeMetadata(
17526
18261
  metadata,
17527
- await layoutModule.generateMetadata({ params: options.pageProps.params })
18262
+ await layoutModule.generateMetadata({
18263
+ params: options.pageProps.params
18264
+ })
17528
18265
  );
17529
18266
  }
17530
18267
  }
@@ -17755,7 +18492,13 @@ var _ServerRenderer = class _ServerRenderer {
17755
18492
  clientEntry: "/@farm/client.js",
17756
18493
  routes: {},
17757
18494
  layouts: {},
17758
- sharedAssets: [{ tag: "link", attrs: { rel: "stylesheet", href: "/src/app/globals.css" } }]
18495
+ slots: [],
18496
+ sharedAssets: [
18497
+ {
18498
+ tag: "link",
18499
+ attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
18500
+ }
18501
+ ]
17759
18502
  };
17760
18503
  for (const routeEntry of manifest.routes) {
17761
18504
  clientManifest.routes[routeEntry.pattern] = {
@@ -17777,9 +18520,26 @@ var _ServerRenderer = class _ServerRenderer {
17777
18520
  assets: []
17778
18521
  };
17779
18522
  }
17780
- const deferredProps = prepareDeferredData(req.__FARM_PROPS__ || {});
18523
+ for (const slotEntry of manifest.slots ?? []) {
18524
+ clientManifest.slots.push({
18525
+ ...slotEntry,
18526
+ preloads: [slotEntry.modulePath],
18527
+ assets: []
18528
+ });
18529
+ }
18530
+ const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
18531
+ (slot) => ({
18532
+ ...slot,
18533
+ modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
18534
+ })
18535
+ );
18536
+ const deferredProps = prepareDeferredData({
18537
+ page: req.__FARM_PROPS__ || {},
18538
+ slots: routeSlotPayload
18539
+ });
17781
18540
  const propsScript = `<script>
17782
- window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
18541
+ window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
18542
+ window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
17783
18543
  window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
17784
18544
  window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
17785
18545
  window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
@@ -17792,7 +18552,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
17792
18552
  window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
17793
18553
  ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
17794
18554
  </script>`;
17795
- const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
18555
+ const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
17796
18556
  const {
17797
18557
  title,
17798
18558
  tags: metaTags,
@@ -17903,7 +18663,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
17903
18663
  didError = true;
17904
18664
  if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
17905
18665
  logger.error(`SSR shell error: ${error}`);
17906
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
18666
+ emitFarmEvent({
18667
+ type: "render.error",
18668
+ route: observabilityRoute,
18669
+ error
18670
+ });
17907
18671
  }
17908
18672
  if (clearMiddlewareData) {
17909
18673
  clearMiddlewareData();
@@ -17914,7 +18678,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
17914
18678
  didError = true;
17915
18679
  if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
17916
18680
  logger.error(`SSR streaming error: ${error}`);
17917
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
18681
+ emitFarmEvent({
18682
+ type: "render.error",
18683
+ route: observabilityRoute,
18684
+ error
18685
+ });
17918
18686
  }
17919
18687
  }
17920
18688
  });
@@ -18083,17 +18851,14 @@ var _FarmApp = class _FarmApp {
18083
18851
  _setDefaultFarmI18nRuntime(this.i18nRuntime);
18084
18852
  this.viteServer = viteServer;
18085
18853
  this.routeManager = new RouteManager(this.config, viteServer);
18086
- this.serverRenderer = new ServerRenderer(
18087
- this.config,
18088
- this.routeManager,
18089
- this.i18nRuntime
18090
- );
18854
+ this.serverRenderer = new ServerRenderer(this.config, this.routeManager, this.i18nRuntime);
18091
18855
  }
18092
18856
  async initialize() {
18093
18857
  if (process.env.FARM_VERBOSE) {
18094
18858
  logger.info("Initializing Farm.js application...");
18095
18859
  }
18096
18860
  await initStorage(this.config.storage);
18861
+ await configureFarmCache(this.config.cache);
18097
18862
  await this.i18nRuntime.initialize();
18098
18863
  await this.verifyAppStructure();
18099
18864
  await this.routeManager.discoverRoutes();
@@ -18125,6 +18890,7 @@ var _FarmApp = class _FarmApp {
18125
18890
  preset: config.preset ?? "node-server",
18126
18891
  deploy: config.deploy || {},
18127
18892
  storage: config.storage || {},
18893
+ cache: config.cache || {},
18128
18894
  integrations: config.integrations || {},
18129
18895
  plugins: config.plugins || [],
18130
18896
  migrations: config.migrations || { commands: [] },
@@ -18536,6 +19302,29 @@ var fs3 = __toESM(require("fs"));
18536
19302
  var path10 = __toESM(require("path"));
18537
19303
  init_route_runtime();
18538
19304
 
19305
+ // src/api/runtime.ts
19306
+ init_cache_invalidation();
19307
+
19308
+ // src/api/endpoint.ts
19309
+ var import_better_call = require("better-call");
19310
+ var _EndpointFailure = class _EndpointFailure extends Error {
19311
+ constructor(code, data, options) {
19312
+ super(options.message);
19313
+ this.name = "EndpointFailure";
19314
+ this.code = code;
19315
+ this.data = data;
19316
+ this.status = options.status;
19317
+ }
19318
+ };
19319
+ __name(_EndpointFailure, "EndpointFailure");
19320
+ var EndpointFailure = _EndpointFailure;
19321
+ function isEndpointFailure(value) {
19322
+ return value instanceof EndpointFailure;
19323
+ }
19324
+ __name(isEndpointFailure, "isEndpointFailure");
19325
+ var EMPTY_ENDPOINT_MIDDLEWARE = Object.freeze([]);
19326
+ var EMPTY_ENDPOINT_CONTEXT = Object.freeze(/* @__PURE__ */ Object.create(null));
19327
+
18539
19328
  // src/api/runtime.ts
18540
19329
  function matchAPIRoute(routes, pathname) {
18541
19330
  const exactRoute = routes.get(pathname);
@@ -18568,10 +19357,10 @@ __name(invokeAPIRouteEndpoint, "invokeAPIRouteEndpoint");
18568
19357
  async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
18569
19358
  const farmHandler = endpoint.__handler || (isFarmContextHandler(endpoint) ? endpoint : null);
18570
19359
  if (!farmHandler) {
18571
- const result2 = await endpoint(request, {
19360
+ const result = await endpoint(request, {
18572
19361
  params: Promise.resolve(params)
18573
19362
  });
18574
- return normalizeRouteResponse(result2);
19363
+ return normalizeRouteResponse(result);
18575
19364
  }
18576
19365
  const url = new URL(request.url);
18577
19366
  const query = {};
@@ -18580,7 +19369,7 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
18580
19369
  });
18581
19370
  let body = void 0;
18582
19371
  if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
18583
- body = await readJSONBody(request);
19372
+ body = await readRequestBody2(request);
18584
19373
  }
18585
19374
  const headers = Object.fromEntries(request.headers.entries());
18586
19375
  const types = endpoint.__types || {};
@@ -18596,15 +19385,30 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
18596
19385
  if (headersValidation instanceof Response) {
18597
19386
  return headersValidation;
18598
19387
  }
18599
- const result = await farmHandler({
19388
+ const handlerContext = {
18600
19389
  query: queryValidation,
18601
19390
  body: bodyValidation,
18602
19391
  headers: headersValidation,
18603
19392
  request,
18604
19393
  context: {},
18605
19394
  params
18606
- });
18607
- return normalizeRouteResponse(result);
19395
+ };
19396
+ let execution;
19397
+ try {
19398
+ execution = typeof endpoint.__farmInvoke === "function" ? await endpoint.__farmInvoke(handlerContext) : {
19399
+ result: await farmHandler(handlerContext),
19400
+ context: handlerContext.context,
19401
+ handlerExecuted: true,
19402
+ invalidations: []
19403
+ };
19404
+ } catch (error) {
19405
+ if (isEndpointFailure(error)) {
19406
+ return createEndpointFailureResponse(error);
19407
+ }
19408
+ throw error;
19409
+ }
19410
+ const response = normalizeRouteResponse(execution.result);
19411
+ return attachEndpointInvalidations(response, execution.invalidations);
18608
19412
  }
18609
19413
  __name(invokeAPIRouteEndpointInContext, "invokeAPIRouteEndpointInContext");
18610
19414
  function normalizeRouteResponse(result) {
@@ -18624,6 +19428,40 @@ function isWebResponse2(value) {
18624
19428
  return value instanceof Response || typeof value === "object" && value !== null && "headers" in value && "status" in value && typeof value.arrayBuffer === "function";
18625
19429
  }
18626
19430
  __name(isWebResponse2, "isWebResponse");
19431
+ function attachEndpointInvalidations(response, keys) {
19432
+ const existing = decodeFarmCacheInvalidations(
19433
+ response.headers.get(FARM_CACHE_INVALIDATION_HEADER)
19434
+ );
19435
+ const encoded = encodeFarmCacheInvalidations([...existing, ...keys]);
19436
+ if (!encoded) return response;
19437
+ const headers = new Headers(response.headers);
19438
+ headers.set(FARM_CACHE_INVALIDATION_HEADER, encoded);
19439
+ return new Response(response.body, {
19440
+ status: response.status,
19441
+ statusText: response.statusText,
19442
+ headers
19443
+ });
19444
+ }
19445
+ __name(attachEndpointInvalidations, "attachEndpointInvalidations");
19446
+ function createEndpointFailureResponse(failure) {
19447
+ return new Response(
19448
+ JSON.stringify({
19449
+ error: {
19450
+ code: failure.code,
19451
+ message: failure.message,
19452
+ data: failure.data
19453
+ }
19454
+ }),
19455
+ {
19456
+ status: failure.status,
19457
+ headers: {
19458
+ "cache-control": "no-store",
19459
+ "content-type": "application/json"
19460
+ }
19461
+ }
19462
+ );
19463
+ }
19464
+ __name(createEndpointFailureResponse, "createEndpointFailureResponse");
18627
19465
  function isFarmContextHandler(endpoint) {
18628
19466
  if (typeof endpoint !== "function") {
18629
19467
  return false;
@@ -18635,17 +19473,50 @@ function isFarmContextHandler(endpoint) {
18635
19473
  return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
18636
19474
  }
18637
19475
  __name(isFarmContextHandler, "isFarmContextHandler");
18638
- async function readJSONBody(request) {
19476
+ async function readRequestBody2(request) {
19477
+ const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
18639
19478
  try {
19479
+ if (contentType === "multipart/form-data") {
19480
+ return formDataToObject(await request.clone().formData());
19481
+ }
18640
19482
  const text2 = await request.clone().text();
18641
- if (text2) {
19483
+ if (!text2) return void 0;
19484
+ if (contentType === "application/x-www-form-urlencoded") {
19485
+ return searchParamsToObject2(new URLSearchParams(text2));
19486
+ }
19487
+ if (contentType === "application/json" || contentType?.endsWith("+json")) {
18642
19488
  return JSON.parse(text2);
18643
19489
  }
19490
+ return JSON.parse(text2);
18644
19491
  } catch {
18645
19492
  }
18646
19493
  return void 0;
18647
19494
  }
18648
- __name(readJSONBody, "readJSONBody");
19495
+ __name(readRequestBody2, "readRequestBody");
19496
+ function formDataToObject(formData) {
19497
+ return entriesToObject(formData.entries());
19498
+ }
19499
+ __name(formDataToObject, "formDataToObject");
19500
+ function searchParamsToObject2(searchParams) {
19501
+ return entriesToObject(searchParams.entries());
19502
+ }
19503
+ __name(searchParamsToObject2, "searchParamsToObject");
19504
+ function entriesToObject(entries) {
19505
+ const output = /* @__PURE__ */ Object.create(null);
19506
+ for (const [key, value] of entries) {
19507
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
19508
+ const current = output[key];
19509
+ if (current === void 0) {
19510
+ output[key] = value;
19511
+ } else if (Array.isArray(current)) {
19512
+ current.push(value);
19513
+ } else {
19514
+ output[key] = [current, value];
19515
+ }
19516
+ }
19517
+ return output;
19518
+ }
19519
+ __name(entriesToObject, "entriesToObject");
18649
19520
  function validateInput(schema, value, error) {
18650
19521
  if (!schema || typeof schema.parse !== "function") {
18651
19522
  return value;
@@ -19652,7 +20523,7 @@ var _MiddlewareManager = class _MiddlewareManager {
19652
20523
  if (!nestedMatch.matched) {
19653
20524
  return { matched: false };
19654
20525
  }
19655
- const params = { ...nestedMatch.params || {} };
20526
+ const params = { ...nestedMatch.params };
19656
20527
  delete params.__farmRest;
19657
20528
  return {
19658
20529
  matched: true,
@@ -19800,6 +20671,7 @@ async function generateRouteTypes(options) {
19800
20671
  absolute: false
19801
20672
  });
19802
20673
  for (const file of pageFiles) {
20674
+ if (parseRouteSlotFile(file)) continue;
19803
20675
  const route = parseRoutePath(file);
19804
20676
  if (route.type === "page") {
19805
20677
  const pattern = createRoutePattern(route);
@@ -20534,6 +21406,12 @@ function transformError(id, message) {
20534
21406
  }
20535
21407
  __name(transformError, "transformError");
20536
21408
 
21409
+ // package.json
21410
+ var version = "0.1.0-beta.4";
21411
+
21412
+ // src/version.ts
21413
+ var FARM_VERSION = version;
21414
+
20537
21415
  // src/after.ts
20538
21416
  var import_node_async_hooks4 = require("async_hooks");
20539
21417
  var AFTER_STORAGE = /* @__PURE__ */ Symbol.for("@farm.js/core/after-storage");
@@ -21005,7 +21883,7 @@ function isResolvedEnvScope(value) {
21005
21883
  }
21006
21884
  __name(isResolvedEnvScope, "isResolvedEnvScope");
21007
21885
  function isPotentialProgrammaticRouteSourceFile(normalizedFile, srcDirSlug) {
21008
- return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) && !/\.d\.ts$/.test(normalizedFile) && !normalizedFile.endsWith("/farm-routes.d.ts") && !normalizedFile.endsWith("/farm-env.d.ts") && !normalizedFile.endsWith("/lib/api.generated.ts");
21886
+ return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) && !normalizedFile.endsWith(".d.ts") && !normalizedFile.endsWith("/farm-routes.d.ts") && !normalizedFile.endsWith("/farm-env.d.ts") && !normalizedFile.endsWith("/lib/api.generated.ts");
21009
21887
  }
21010
21888
  __name(isPotentialProgrammaticRouteSourceFile, "isPotentialProgrammaticRouteSourceFile");
21011
21889
  function fileContainsProgrammaticPageRoute(file) {
@@ -21248,7 +22126,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21248
22126
  }, "isProgrammaticRouteSourceFile");
21249
22127
  const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
21250
22128
  const normalized = file.replace(/\\/g, "/");
21251
- return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
22129
+ return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|default|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
21252
22130
  normalized
21253
22131
  );
21254
22132
  }, "isAppRuntimeFile");
@@ -21939,7 +22817,10 @@ function farmPlugin(options = {}, initialPluginManager) {
21939
22817
  method: req.method || "GET"
21940
22818
  });
21941
22819
  }
21942
- const match = routeManager3.matchRoute(targetPath);
22820
+ const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
22821
+ const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
22822
+ interceptFrom: interceptFromHeader
22823
+ });
21943
22824
  if (pm) {
21944
22825
  await pm.runHookParallel("afterRouteMatch", {
21945
22826
  pathname: targetPath,
@@ -21955,7 +22836,7 @@ function farmPlugin(options = {}, initialPluginManager) {
21955
22836
  res.end(JSON.stringify({ error: "Route not found" }));
21956
22837
  return;
21957
22838
  }
21958
- const { route, params, layouts } = match;
22839
+ const { route, params, layouts, slots } = match;
21959
22840
  if (!route) {
21960
22841
  res.statusCode = 404;
21961
22842
  res.setHeader("Content-Type", "application/json");
@@ -22010,6 +22891,54 @@ function farmPlugin(options = {}, initialPluginManager) {
22010
22891
  search: searchParams,
22011
22892
  routePath: route.pattern
22012
22893
  });
22894
+ const routeSlots = await Promise.all(
22895
+ slots.map(async (slot) => {
22896
+ const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
22897
+ const slotMetadata = getClientModuleMetadata(
22898
+ slot.route.modulePath,
22899
+ server.config.root
22900
+ );
22901
+ const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
22902
+ request,
22903
+ params: slot.params,
22904
+ search: searchParams,
22905
+ path: targetUrl.pathname
22906
+ });
22907
+ const slotProps = await parseRouteModuleProps2(slotModule, {
22908
+ props: withFarmRouteContext(
22909
+ {
22910
+ params: slot.params,
22911
+ searchParams: Promise.resolve(searchParams),
22912
+ path: targetUrl.pathname
22913
+ },
22914
+ slotContext
22915
+ ),
22916
+ search: searchParams,
22917
+ routePath: slot.route.pattern
22918
+ });
22919
+ return {
22920
+ name: slot.name,
22921
+ ownerPattern: slot.ownerPattern,
22922
+ containerId: slot.containerId,
22923
+ interception: slot.interception,
22924
+ fallback: slot.fallback,
22925
+ modulePath: slot.route.modulePath,
22926
+ isClientComponent: slotMetadata.isClientComponent,
22927
+ shouldHydrate: slotMetadata.shouldHydrate,
22928
+ props: {
22929
+ params: slotProps.params,
22930
+ search: slotProps.search,
22931
+ searchParams: slotProps.search,
22932
+ ..."data" in slotProps ? { data: slotProps.data } : {},
22933
+ ...slotProps.__farmCanonicalPath ? {
22934
+ __farmCanonicalPath: slotProps.__farmCanonicalPath
22935
+ } : {},
22936
+ ...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
22937
+ path: targetUrl.pathname
22938
+ }
22939
+ };
22940
+ })
22941
+ );
22013
22942
  const projectRoot = server.config.root;
22014
22943
  const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
22015
22944
  if (absolutePath.startsWith(projectRoot)) {
@@ -22030,13 +22959,21 @@ function farmPlugin(options = {}, initialPluginManager) {
22030
22959
  },
22031
22960
  canonicalPath: routeProps.__farmCanonicalPath,
22032
22961
  modulePath: toUrlPath(route.modulePath),
22033
- isClientComponent,
22034
- shouldHydrate,
22962
+ isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
22963
+ shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
22035
22964
  metadata: {
22036
22965
  title: mergedMetadata.title,
22037
22966
  description: mergedMetadata.description
22038
22967
  },
22039
22968
  layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
22969
+ routeSlots: routeSlots.map((slot) => ({
22970
+ ...slot,
22971
+ modulePath: toUrlPath(slot.modulePath)
22972
+ })),
22973
+ interception: routeSlots.some((slot) => slot.interception) ? {
22974
+ from: interceptFromHeader,
22975
+ slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
22976
+ } : void 0,
22040
22977
  i18n: getFarmI18nClientSnapshot()
22041
22978
  };
22042
22979
  await sendWebResponse(
@@ -22372,6 +23309,7 @@ function farmPlugin(options = {}, initialPluginManager) {
22372
23309
  export const getManifest = () => ({
22373
23310
  routes: {},
22374
23311
  layouts: {},
23312
+ slots: [],
22375
23313
  clientEntry: "/@farm/client.js",
22376
23314
  sharedAssets: []
22377
23315
  });
@@ -22382,6 +23320,7 @@ export const getManifest = () => ({
22382
23320
  clientEntry: "/@farm/client.js",
22383
23321
  routes: {},
22384
23322
  layouts: {},
23323
+ slots: [],
22385
23324
  sharedAssets: [
22386
23325
  {
22387
23326
  tag: "link",
@@ -22411,6 +23350,13 @@ export const getManifest = () => ({
22411
23350
  assets: []
22412
23351
  };
22413
23352
  }
23353
+ for (const slot of manifest.slots) {
23354
+ fullManifest.slots.push({
23355
+ ...slot,
23356
+ preloads: [slot.modulePath],
23357
+ assets: []
23358
+ });
23359
+ }
22414
23360
  return `
22415
23361
  // Auto-generated manifest for SPA navigation (TanStack Start pattern)
22416
23362
  // This manifest is inlined in the server bundle - no file on disk
@@ -23053,7 +23999,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
23053
23999
 
23054
24000
  // Get manifest from window (inlined by server in HTML)
23055
24001
  // Fallback to empty manifest if not available yet
23056
- const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
24002
+ const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
23057
24003
 
23058
24004
  // ====== CLIENT-SIDE ROUTE MATCHING ======
23059
24005
  // Matches URL to route using manifest (no server request!)
@@ -23392,6 +24338,9 @@ let LayoutComponent = null;
23392
24338
 
23393
24339
  // Track if we've taken over rendering from SSR
23394
24340
  let hasClientTakenOver = false;
24341
+ const routeSlotRoots = new Map();
24342
+ const routeSlotDefinitions = new Map();
24343
+ let activeRouteInterception = null;
23395
24344
 
23396
24345
  function normalizeServerProps(rawProps) {
23397
24346
  const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
@@ -23404,6 +24353,123 @@ function normalizeServerProps(rawProps) {
23404
24353
  return props;
23405
24354
  }
23406
24355
 
24356
+ function getRouteSlotKey(slot) {
24357
+ return slot.ownerPattern + ':' + slot.name;
24358
+ }
24359
+
24360
+ async function renderRouteSlot(slot, mode = 'render') {
24361
+ const container = document.getElementById(slot.containerId);
24362
+ if (!container || !slot.modulePath) return false;
24363
+ if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
24364
+ return false;
24365
+ }
24366
+
24367
+ let slotModule = pageModuleCache.get(slot.modulePath);
24368
+ if (!slotModule) {
24369
+ slotModule = await import(/* @vite-ignore */ slot.modulePath);
24370
+ pageModuleCache.set(slot.modulePath, slotModule);
24371
+ }
24372
+ const SlotComponent = slotModule?.default;
24373
+ if (!SlotComponent) return false;
24374
+
24375
+ const props = reviveDeferredData(
24376
+ normalizeServerProps(slot.props || {}),
24377
+ window.__FARM_DEFERRED_DATA__ || {},
24378
+ );
24379
+ const element = wrapWithIntegrationProviders(
24380
+ React.createElement(SlotComponent, props),
24381
+ );
24382
+ const key = getRouteSlotKey(slot);
24383
+ const existingRoot = routeSlotRoots.get(key);
24384
+
24385
+ if (mode === 'hydrate') {
24386
+ if (existingRoot) return true;
24387
+ const root = hydrateRoot(container, element);
24388
+ routeSlotRoots.set(key, root);
24389
+ } else {
24390
+ if (existingRoot) {
24391
+ try { existingRoot.unmount(); } catch (error) {}
24392
+ }
24393
+ const root = createRoot(container);
24394
+ root.render(element);
24395
+ routeSlotRoots.set(key, root);
24396
+ }
24397
+
24398
+ routeSlotDefinitions.set(key, slot);
24399
+ return true;
24400
+ }
24401
+
24402
+ async function hydrateInitialRouteSlots() {
24403
+ const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
24404
+ ? window.__FARM_ROUTE_SLOTS__
24405
+ : [];
24406
+ let hydrated = false;
24407
+
24408
+ for (const slot of slots) {
24409
+ routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
24410
+ if (!slot.isClientComponent && !slot.shouldHydrate) continue;
24411
+ try {
24412
+ hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
24413
+ } catch (error) {
24414
+ console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
24415
+ }
24416
+ }
24417
+
24418
+ return hydrated;
24419
+ }
24420
+
24421
+ async function renderRouteInterception(pageData) {
24422
+ const slots = Array.isArray(pageData.routeSlots)
24423
+ ? pageData.routeSlots.filter((slot) => slot.interception)
24424
+ : [];
24425
+ if (!pageData.interception || slots.length === 0) return false;
24426
+
24427
+ const previous = new Map();
24428
+ for (const slot of slots) {
24429
+ const key = getRouteSlotKey(slot);
24430
+ previous.set(key, routeSlotDefinitions.get(key) || null);
24431
+ if (!(await renderRouteSlot(slot, 'intercept'))) {
24432
+ return false;
24433
+ }
24434
+ }
24435
+
24436
+ activeRouteInterception = {
24437
+ from: pageData.interception.from,
24438
+ slots,
24439
+ previous,
24440
+ };
24441
+ return true;
24442
+ }
24443
+
24444
+ async function clearRouteInterception(destination) {
24445
+ if (!activeRouteInterception) return false;
24446
+ const active = activeRouteInterception;
24447
+ activeRouteInterception = null;
24448
+
24449
+ for (const slot of active.slots) {
24450
+ const key = getRouteSlotKey(slot);
24451
+ const root = routeSlotRoots.get(key);
24452
+ if (root) {
24453
+ try { root.unmount(); } catch (error) {}
24454
+ routeSlotRoots.delete(key);
24455
+ }
24456
+
24457
+ const previous = active.previous.get(key);
24458
+ if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
24459
+ await renderRouteSlot(previous, 'render');
24460
+ } else {
24461
+ const container = document.getElementById(slot.containerId);
24462
+ if (container) container.replaceChildren();
24463
+ if (previous) routeSlotDefinitions.set(key, previous);
24464
+ else routeSlotDefinitions.delete(key);
24465
+ }
24466
+ }
24467
+
24468
+ if (!active.from) return false;
24469
+ const background = new URL(active.from, window.location.origin);
24470
+ return destination === background.pathname + background.search;
24471
+ }
24472
+
23407
24473
  function applyCanonicalPathFromProps(props) {
23408
24474
  const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
23409
24475
  ? props.__farmCanonicalPath
@@ -23638,6 +24704,17 @@ async function tryHydrateImportedPage(
23638
24704
  async function renderPage(pageData) {
23639
24705
  const container = document.getElementById('root');
23640
24706
  if (!container) return;
24707
+ const destination = window.location.pathname + window.location.search;
24708
+
24709
+ if (pageData.interception) {
24710
+ if (await renderRouteInterception(pageData)) return;
24711
+ window.location.assign(destination);
24712
+ return;
24713
+ }
24714
+
24715
+ if (await clearRouteInterception(destination)) {
24716
+ return;
24717
+ }
23641
24718
 
23642
24719
  const route = {
23643
24720
  modulePath: pageData.modulePath,
@@ -23866,7 +24943,9 @@ async function hydrate() {
23866
24943
  window.__FARM_SHOULD_HYDRATE__ === true ||
23867
24944
  isClientComponent ||
23868
24945
  await moduleLooksClient(modulePath);
24946
+ const hydratedSlots = await hydrateInitialRouteSlots();
23869
24947
  if (!shouldHydrate) {
24948
+ if (hydratedSlots) replayPreHydrationClicks();
23870
24949
  console.log('[Farm.js] Server component - SPA router ready')
23871
24950
  return
23872
24951
  }
@@ -24131,7 +25210,7 @@ async function defineConfig2(config = {}) {
24131
25210
  const isExposed = hostConfig === true || hostConfig === "0.0.0.0";
24132
25211
  console.log("");
24133
25212
  console.log(
24134
- ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim("v1.0.0")} ${pc.dim(`ready in ${elapsed}ms`)}`
25213
+ ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim(`v${FARM_VERSION}`)} ${pc.dim(`ready in ${elapsed}ms`)}`
24135
25214
  );
24136
25215
  console.log("");
24137
25216
  console.log(
@@ -24250,7 +25329,7 @@ function createServerFn(options) {
24250
25329
  const middleware = resolveServerFnMiddleware(options.middleware);
24251
25330
  const serverFn = /* @__PURE__ */ __name(async (value) => {
24252
25331
  const formData = isFormData(value) ? value : void 0;
24253
- const rawInput = formData ? formDataToObject(formData) : value;
25332
+ const rawInput = formData ? formDataToObject2(formData) : value;
24254
25333
  const input = await _parseServerFnSchema(options.input, rawInput, "input");
24255
25334
  const executionContext = getServerActionExecutionContext();
24256
25335
  const request = executionContext?.request ?? _resolveCurrentRequest();
@@ -24262,8 +25341,21 @@ function createServerFn(options) {
24262
25341
  request,
24263
25342
  signal
24264
25343
  };
24265
- const result = await runServerFnMiddleware(middleware, handlerContext, options.handler);
24266
- return _parseServerFnSchema(options.output, result, "output");
25344
+ let resolvedContext = Object.freeze(/* @__PURE__ */ Object.create(null));
25345
+ const result = await runServerFnMiddleware(middleware, handlerContext, async (context) => {
25346
+ resolvedContext = context.context;
25347
+ return options.handler(context);
25348
+ });
25349
+ const parsedResult = await _parseServerFnSchema(options.output, result, "output");
25350
+ if (options.invalidates) {
25351
+ const declaration = typeof options.invalidates === "function" ? await options.invalidates({
25352
+ ...handlerContext,
25353
+ context: resolvedContext,
25354
+ result: parsedResult
25355
+ }) : options.invalidates;
25356
+ await applyFarmCacheInvalidationTargets(declaration);
25357
+ }
25358
+ return parsedResult;
24267
25359
  }, "serverFn");
24268
25360
  Object.defineProperties(serverFn, {
24269
25361
  [FARM_SERVER_FN_SYMBOL]: {
@@ -24285,6 +25377,10 @@ function createServerFn(options) {
24285
25377
  __farmServerFnMiddleware: {
24286
25378
  value: middleware,
24287
25379
  enumerable: false
25380
+ },
25381
+ __farmServerFnInvalidates: {
25382
+ value: options.invalidates,
25383
+ enumerable: false
24288
25384
  }
24289
25385
  });
24290
25386
  return serverFn;
@@ -24382,7 +25478,7 @@ function unwrapSafeParseResult(result) {
24382
25478
  return result;
24383
25479
  }
24384
25480
  __name(unwrapSafeParseResult, "unwrapSafeParseResult");
24385
- function formDataToObject(formData) {
25481
+ function formDataToObject2(formData) {
24386
25482
  const output = /* @__PURE__ */ Object.create(null);
24387
25483
  for (const [key, value] of formData.entries()) {
24388
25484
  if (!isSafeFormKey(key)) continue;
@@ -24397,7 +25493,7 @@ function formDataToObject(formData) {
24397
25493
  }
24398
25494
  return output;
24399
25495
  }
24400
- __name(formDataToObject, "formDataToObject");
25496
+ __name(formDataToObject2, "formDataToObject");
24401
25497
  function isSafeFormKey(key) {
24402
25498
  return !key.startsWith("$ACTION_") && !UNSAFE_FORM_KEYS.has(key);
24403
25499
  }
@@ -24459,7 +25555,7 @@ function createServerQuery(options) {
24459
25555
  tags: [createRouteDataCacheTag(routeKey)],
24460
25556
  revalidate: staleTime === false ? false : Math.max(1, Math.ceil(staleTime / 1e3))
24461
25557
  });
24462
- updatedAt = cache.getEntry(cacheKey, { allowStale: true })?.createdAt ?? Date.now();
25558
+ updatedAt = (await cache.getEntryAsync(cacheKey, { allowStale: true }))?.createdAt ?? Date.now();
24463
25559
  }
24464
25560
  return createFarmServerQueryResult(data, {
24465
25561
  key: clientKey,
@@ -25295,7 +26391,7 @@ __name(createLoggerPlugin, "createLoggerPlugin");
25295
26391
  // src/server/vite-config.ts
25296
26392
  function mergeNoExternal(farmValue, userValue) {
25297
26393
  if (farmValue === true || userValue === true) return true;
25298
- const normalize = /* @__PURE__ */ __name((value) => value == null ? [] : Array.isArray(value) ? value : [value], "normalize");
26394
+ const normalize = /* @__PURE__ */ __name((value) => value == null || value === true ? [] : Array.isArray(value) ? value : [value], "normalize");
25299
26395
  return Array.from(/* @__PURE__ */ new Set([...normalize(farmValue), ...normalize(userValue)]));
25300
26396
  }
25301
26397
  __name(mergeNoExternal, "mergeNoExternal");
@@ -25308,6 +26404,13 @@ function mergeFarmViteConfig(farmConfig, userConfig = {}) {
25308
26404
  ...farmConfig.server,
25309
26405
  ...userConfig.server
25310
26406
  },
26407
+ resolve: {
26408
+ ...farmConfig.resolve,
26409
+ ...userConfig.resolve,
26410
+ dedupe: Array.from(
26411
+ /* @__PURE__ */ new Set([...farmConfig.resolve?.dedupe || [], ...userConfig.resolve?.dedupe || []])
26412
+ )
26413
+ },
25311
26414
  optimizeDeps: {
25312
26415
  ...farmConfig.optimizeDeps,
25313
26416
  ...userConfig.optimizeDeps,
@@ -25334,6 +26437,7 @@ function mergeFarmViteConfig(farmConfig, userConfig = {}) {
25334
26437
  __name(mergeFarmViteConfig, "mergeFarmViteConfig");
25335
26438
 
25336
26439
  // src/server/create-server.ts
26440
+ var DEFAULT_FARM_DEV_SERVER_PORT = 3e3;
25337
26441
  function createBrandingPlugin() {
25338
26442
  let serverStarted = false;
25339
26443
  let startTime = Date.now();
@@ -25369,7 +26473,7 @@ function createBrandingPlugin() {
25369
26473
  const pc = getColors();
25370
26474
  console.log("");
25371
26475
  console.log(
25372
- ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim("v1.0.0")} ${pc.dim(`ready in ${elapsed}ms`)}`
26476
+ ` ${pc.bold(pc.green("Farm.js"))} ${pc.dim(`v${FARM_VERSION}`)} ${pc.dim(`ready in ${elapsed}ms`)}`
25373
26477
  );
25374
26478
  console.log("");
25375
26479
  console.log(
@@ -25495,7 +26599,13 @@ async function createServer(config = {}) {
25495
26599
  createBrandingPlugin()
25496
26600
  ],
25497
26601
  server: {
25498
- middlewareMode: false
26602
+ middlewareMode: false,
26603
+ port: DEFAULT_FARM_DEV_SERVER_PORT,
26604
+ strictPort: true
26605
+ },
26606
+ resolve: {
26607
+ // Keep framework and application modules on one React runtime.
26608
+ dedupe: ["react", "react-dom"]
25499
26609
  },
25500
26610
  optimizeDeps: {
25501
26611
  // Avoid Vite scanning server/native-only deps from framework internals.
@@ -25570,7 +26680,7 @@ async function createServer(config = {}) {
25570
26680
  }
25571
26681
  }
25572
26682
  __name(createServer, "createServer");
25573
- async function startDevServer(config = {}, port = 3e3) {
26683
+ async function startDevServer(config = {}, port) {
25574
26684
  const server = await createServer(config);
25575
26685
  await server.listen(port);
25576
26686
  const pluginManager = server.__farmPluginManager;
@@ -25651,6 +26761,7 @@ function assertFunction(value, label) {
25651
26761
  __name(assertFunction, "assertFunction");
25652
26762
  // Annotate the CommonJS export names for ESM import in node:
25653
26763
  0 && (module.exports = {
26764
+ DEFAULT_FARM_DEV_SERVER_PORT,
25654
26765
  DEFAULT_SERVER_ACTION_BODY_SIZE_LIMIT,
25655
26766
  FARM_SERVER_QUERY_SYMBOL,
25656
26767
  FarmApp,
@@ -25663,7 +26774,9 @@ __name(assertFunction, "assertFunction");
25663
26774
  _runWithAfterRequest,
25664
26775
  _withAfterNodeMiddleware,
25665
26776
  after,
26777
+ applyFarmCacheInvalidationTargets,
25666
26778
  applyFarmCacheInvalidations,
26779
+ configureFarmCache,
25667
26780
  createClientOnlyFn,
25668
26781
  createFarmApp,
25669
26782
  createFarmCacheKey,
@@ -25678,6 +26791,7 @@ __name(assertFunction, "assertFunction");
25678
26791
  createServerQuery,
25679
26792
  createStorageClient,
25680
26793
  databaseStorage,
26794
+ defineCacheKey,
25681
26795
  defineConfig,
25682
26796
  defineStorageClient,
25683
26797
  disposeStorage,
@@ -25728,6 +26842,7 @@ __name(assertFunction, "assertFunction");
25728
26842
  segmentsToPattern,
25729
26843
  sqliteStorage,
25730
26844
  startDevServer,
26845
+ storageCacheAdapter,
25731
26846
  toViteModuleId,
25732
26847
  unstable_cache,
25733
26848
  updateTag,