@farm.js/core 0.1.0-beta.3 → 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 (192) hide show
  1. package/dist/agent-runtime.d.mts +2 -1
  2. package/dist/agent-runtime.d.ts +2 -1
  3. package/dist/api/route-manager.cjs +313 -10
  4. package/dist/api/route-manager.cjs.map +1 -1
  5. package/dist/api/route-manager.d.mts +3 -2
  6. package/dist/api/route-manager.d.ts +3 -2
  7. package/dist/api/route-manager.mjs +6 -5
  8. package/dist/api/runtime.cjs +313 -10
  9. package/dist/api/runtime.cjs.map +1 -1
  10. package/dist/api/runtime.d.mts +2 -1
  11. package/dist/api/runtime.d.ts +2 -1
  12. package/dist/api/runtime.mjs +4 -3
  13. package/dist/api.cjs +642 -57
  14. package/dist/api.cjs.map +1 -1
  15. package/dist/api.d.mts +3 -2
  16. package/dist/api.d.ts +3 -2
  17. package/dist/api.mjs +29 -9
  18. package/dist/{app-DOKxo-LH.d.ts → app-BjN-da13.d.ts} +38 -3
  19. package/dist/{app-BB3Iu3xh.d.mts → app-CakAr8Be.d.mts} +38 -3
  20. package/dist/app-markdown.d.mts +2 -1
  21. package/dist/app-markdown.d.ts +2 -1
  22. package/dist/cache.cjs +395 -12
  23. package/dist/cache.cjs.map +1 -1
  24. package/dist/cache.d.mts +100 -6
  25. package/dist/cache.d.ts +100 -6
  26. package/dist/cache.mjs +8 -2
  27. package/dist/{chunk-XUBZ7JI4.mjs → chunk-2CUKEMVR.mjs} +187 -16
  28. package/dist/chunk-2CUKEMVR.mjs.map +1 -0
  29. package/dist/{chunk-5QH4IKY3.mjs → chunk-3U3ZUQAQ.mjs} +2 -2
  30. package/dist/{chunk-6WXJ54TC.mjs → chunk-65A7QIKI.mjs} +5 -5
  31. package/dist/{chunk-6WXJ54TC.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
  32. package/dist/{chunk-OHC6VCDI.mjs → chunk-AJWRO5WE.mjs} +521 -42
  33. package/dist/chunk-AJWRO5WE.mjs.map +1 -0
  34. package/dist/chunk-ALCLXXTY.mjs +187 -0
  35. package/dist/chunk-ALCLXXTY.mjs.map +1 -0
  36. package/dist/{chunk-XJSHJN4M.mjs → chunk-AOBXKNS5.mjs} +593 -49
  37. package/dist/chunk-AOBXKNS5.mjs.map +1 -0
  38. package/dist/{chunk-CSU4KJJF.mjs → chunk-C2ROET2V.mjs} +2 -2
  39. package/dist/{chunk-BIOIOWXZ.mjs → chunk-HNIQFZKB.mjs} +2 -2
  40. package/dist/{chunk-G5I34UA6.mjs → chunk-JDEOUK5V.mjs} +4 -4
  41. package/dist/{chunk-T543TMFY.mjs → chunk-NM3CRAAL.mjs} +3 -2
  42. package/dist/chunk-NM3CRAAL.mjs.map +1 -0
  43. package/dist/{chunk-LWMGIEJA.mjs → chunk-PFE6GMNE.mjs} +47 -37
  44. package/dist/chunk-PFE6GMNE.mjs.map +1 -0
  45. package/dist/{chunk-6VS6CKAV.mjs → chunk-QM746KUO.mjs} +8 -1
  46. package/dist/chunk-QM746KUO.mjs.map +1 -0
  47. package/dist/{chunk-SHRJG6OG.mjs → chunk-RBRLLZL5.mjs} +18 -3
  48. package/dist/chunk-RBRLLZL5.mjs.map +1 -0
  49. package/dist/{chunk-MH6FKW2I.mjs → chunk-SADGIRS2.mjs} +3 -3
  50. package/dist/{chunk-NRRFGX45.mjs → chunk-TQAEEJB4.mjs} +3 -3
  51. package/dist/{chunk-45LKHSHJ.mjs → chunk-UB5UOSHB.mjs} +24 -12
  52. package/dist/chunk-UB5UOSHB.mjs.map +1 -0
  53. package/dist/chunk-V3XURYJO.mjs +756 -0
  54. package/dist/chunk-V3XURYJO.mjs.map +1 -0
  55. package/dist/{chunk-5FW6PQ3J.mjs → chunk-VVKWFZAH.mjs} +41 -16
  56. package/dist/chunk-VVKWFZAH.mjs.map +1 -0
  57. package/dist/{chunk-HZYXGV4K.mjs → chunk-VY2UYN5R.mjs} +24 -4
  58. package/dist/chunk-VY2UYN5R.mjs.map +1 -0
  59. package/dist/{chunk-C33RALN7.mjs → chunk-W2CRQFF6.mjs} +79 -15
  60. package/dist/chunk-W2CRQFF6.mjs.map +1 -0
  61. package/dist/{chunk-JNYVN7YP.mjs → chunk-W4UIVMVI.mjs} +2 -2
  62. package/dist/{chunk-JNYVN7YP.mjs.map → chunk-W4UIVMVI.mjs.map} +1 -1
  63. package/dist/{chunk-LG3YINQN.mjs → chunk-Z5CQMP54.mjs} +3 -3
  64. package/dist/{client-DiViK9yK.d.mts → client-BT1mFQas.d.mts} +23 -4
  65. package/dist/{client-DpEBJbts.d.ts → client-Nn0q4eO4.d.ts} +23 -4
  66. package/dist/{client-plugins-CTnsZz_A.d.ts → client-plugins-Cw4qUGsw.d.ts} +6 -0
  67. package/dist/{client-plugins-Cnr0D3kk.d.mts → client-plugins-DQQ1adXM.d.mts} +6 -0
  68. package/dist/client-plugins.d.mts +2 -1
  69. package/dist/client-plugins.d.ts +2 -1
  70. package/dist/client.cjs +665 -82
  71. package/dist/client.cjs.map +1 -1
  72. package/dist/client.d.mts +70 -4
  73. package/dist/client.d.ts +70 -4
  74. package/dist/client.mjs +10 -7
  75. package/dist/config.d.mts +2 -1
  76. package/dist/config.d.ts +2 -1
  77. package/dist/{devtools-HE4FTUDN.mjs → devtools-LVC3VB5P.mjs} +4 -4
  78. package/dist/docs.cjs +11 -1
  79. package/dist/docs.cjs.map +1 -1
  80. package/dist/docs.mjs +4 -4
  81. package/dist/index.cjs +2112 -197
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.mts +12 -11
  84. package/dist/index.d.ts +12 -11
  85. package/dist/index.mjs +49 -21
  86. package/dist/index.mjs.map +1 -1
  87. package/dist/integrations.d.mts +2 -1
  88. package/dist/integrations.d.ts +2 -1
  89. package/dist/internal/build-runtime.cjs +1455 -90
  90. package/dist/internal/build-runtime.cjs.map +1 -1
  91. package/dist/internal/build-runtime.d.mts +4 -3
  92. package/dist/internal/build-runtime.d.ts +4 -3
  93. package/dist/internal/build-runtime.mjs +15 -14
  94. package/dist/internal/config-runtime.cjs +12 -1
  95. package/dist/internal/config-runtime.cjs.map +1 -1
  96. package/dist/internal/config-runtime.d.mts +3 -2
  97. package/dist/internal/config-runtime.d.ts +3 -2
  98. package/dist/internal/config-runtime.mjs +3 -3
  99. package/dist/internal/production-runtime.cjs +282 -6
  100. package/dist/internal/production-runtime.cjs.map +1 -1
  101. package/dist/internal/production-runtime.d.mts +4 -4
  102. package/dist/internal/production-runtime.d.ts +4 -4
  103. package/dist/internal/production-runtime.mjs +4 -2
  104. package/dist/{metadata-eoVmHoyv.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
  105. package/dist/{metadata-Dp8AdvsB.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
  106. package/dist/middleware.d.mts +4 -3
  107. package/dist/middleware.d.ts +4 -3
  108. package/dist/navigation.cjs +40 -15
  109. package/dist/navigation.cjs.map +1 -1
  110. package/dist/navigation.mjs +2 -2
  111. package/dist/plugin.cjs +913 -53
  112. package/dist/plugin.cjs.map +1 -1
  113. package/dist/plugin.d.mts +2 -1
  114. package/dist/plugin.d.ts +2 -1
  115. package/dist/plugin.mjs +11 -10
  116. package/dist/{production-runtime-BqTnUTai.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
  117. package/dist/{production-runtime-DtDdG9fc.d.mts → production-runtime-DPfgMV9Y.d.mts} +1 -1
  118. package/dist/routes.cjs +276 -6
  119. package/dist/routes.cjs.map +1 -1
  120. package/dist/routes.d.mts +1 -1
  121. package/dist/routes.d.ts +1 -1
  122. package/dist/routes.mjs +3 -3
  123. package/dist/{runtime-C1B7pSGT.d.mts → runtime-9nQjVM7X.d.mts} +8 -9
  124. package/dist/{runtime-CdPHt0bv.d.ts → runtime-DgeS2skB.d.ts} +8 -9
  125. package/dist/server-action-security.cjs +28 -10
  126. package/dist/server-action-security.cjs.map +1 -1
  127. package/dist/server-action-security.d.mts +2 -1
  128. package/dist/server-action-security.d.ts +2 -1
  129. package/dist/server-action-security.mjs +2 -2
  130. package/dist/server-fn-client.d.mts +1 -0
  131. package/dist/server-fn-client.d.ts +1 -0
  132. package/dist/server-fn.cjs +785 -3
  133. package/dist/server-fn.cjs.map +1 -1
  134. package/dist/server-fn.d.mts +10 -1
  135. package/dist/server-fn.d.ts +10 -1
  136. package/dist/server-fn.mjs +6 -3
  137. package/dist/server-plugins.d.mts +3 -2
  138. package/dist/server-plugins.d.ts +3 -2
  139. package/dist/server-query-client.cjs +278 -7
  140. package/dist/server-query-client.cjs.map +1 -1
  141. package/dist/server-query-client.mjs +4 -4
  142. package/dist/server-query.cjs +381 -10
  143. package/dist/server-query.cjs.map +1 -1
  144. package/dist/server-query.mjs +5 -5
  145. package/dist/server.cjs +1086 -76
  146. package/dist/server.cjs.map +1 -1
  147. package/dist/server.d.mts +8 -7
  148. package/dist/server.d.ts +8 -7
  149. package/dist/server.mjs +31 -16
  150. package/dist/server.mjs.map +1 -1
  151. package/dist/testing.cjs +341 -20
  152. package/dist/testing.cjs.map +1 -1
  153. package/dist/testing.d.mts +3 -2
  154. package/dist/testing.d.ts +3 -2
  155. package/dist/testing.mjs +7 -6
  156. package/dist/testing.mjs.map +1 -1
  157. package/dist/transport-BmbGTXA5.d.mts +49 -0
  158. package/dist/transport-BmbGTXA5.d.ts +49 -0
  159. package/dist/{utils-8USa5BiY.d.mts → utils-CHXlMDkg.d.mts} +1 -1
  160. package/dist/{utils-DKJb6K6G.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
  161. package/dist/version.cjs +1 -1
  162. package/dist/version.cjs.map +1 -1
  163. package/dist/version.mjs +1 -1
  164. package/dist/vite.cjs +914 -54
  165. package/dist/vite.cjs.map +1 -1
  166. package/dist/vite.d.mts +2 -1
  167. package/dist/vite.d.ts +2 -1
  168. package/dist/vite.mjs +11 -10
  169. package/package.json +1 -1
  170. package/types/api.d.ts +44 -0
  171. package/types/client.d.ts +85 -4
  172. package/dist/chunk-45LKHSHJ.mjs.map +0 -1
  173. package/dist/chunk-5FW6PQ3J.mjs.map +0 -1
  174. package/dist/chunk-6VS6CKAV.mjs.map +0 -1
  175. package/dist/chunk-C33RALN7.mjs.map +0 -1
  176. package/dist/chunk-GZWT6VI5.mjs +0 -382
  177. package/dist/chunk-GZWT6VI5.mjs.map +0 -1
  178. package/dist/chunk-HZYXGV4K.mjs.map +0 -1
  179. package/dist/chunk-LWMGIEJA.mjs.map +0 -1
  180. package/dist/chunk-OHC6VCDI.mjs.map +0 -1
  181. package/dist/chunk-SHRJG6OG.mjs.map +0 -1
  182. package/dist/chunk-T543TMFY.mjs.map +0 -1
  183. package/dist/chunk-XJSHJN4M.mjs.map +0 -1
  184. package/dist/chunk-XUBZ7JI4.mjs.map +0 -1
  185. /package/dist/{chunk-5QH4IKY3.mjs.map → chunk-3U3ZUQAQ.mjs.map} +0 -0
  186. /package/dist/{chunk-CSU4KJJF.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
  187. /package/dist/{chunk-BIOIOWXZ.mjs.map → chunk-HNIQFZKB.mjs.map} +0 -0
  188. /package/dist/{chunk-G5I34UA6.mjs.map → chunk-JDEOUK5V.mjs.map} +0 -0
  189. /package/dist/{chunk-MH6FKW2I.mjs.map → chunk-SADGIRS2.mjs.map} +0 -0
  190. /package/dist/{chunk-NRRFGX45.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
  191. /package/dist/{chunk-LG3YINQN.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
  192. /package/dist/{devtools-HE4FTUDN.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
package/dist/index.cjs CHANGED
@@ -4705,7 +4705,8 @@ var init_route_rules = __esm({
4705
4705
  // src/cache-invalidation.ts
4706
4706
  function getFarmCacheInvalidationState() {
4707
4707
  return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
4708
- listeners: /* @__PURE__ */ new Set()
4708
+ listeners: /* @__PURE__ */ new Set(),
4709
+ taskListeners: /* @__PURE__ */ new Set()
4709
4710
  });
4710
4711
  }
4711
4712
  function notifyFarmCacheInvalidation(key) {
@@ -4714,6 +4715,11 @@ function notifyFarmCacheInvalidation(key) {
4714
4715
  listener(key);
4715
4716
  }
4716
4717
  }
4718
+ function notifyFarmCacheTask(task) {
4719
+ for (const listener of getFarmCacheInvalidationState().taskListeners) {
4720
+ listener(task);
4721
+ }
4722
+ }
4717
4723
  function applyFarmCacheInvalidations(keys) {
4718
4724
  if (!Array.isArray(keys)) return;
4719
4725
  for (const key of keys) {
@@ -4745,6 +4751,11 @@ function subscribeFarmCacheInvalidation(listener) {
4745
4751
  state.listeners.add(listener);
4746
4752
  return () => state.listeners.delete(listener);
4747
4753
  }
4754
+ function subscribeFarmCacheTask(listener) {
4755
+ const state = getFarmCacheInvalidationState();
4756
+ state.taskListeners.add(listener);
4757
+ return () => state.taskListeners.delete(listener);
4758
+ }
4748
4759
  var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
4749
4760
  var init_cache_invalidation = __esm({
4750
4761
  "src/cache-invalidation.ts"() {
@@ -4754,10 +4765,12 @@ var init_cache_invalidation = __esm({
4754
4765
  globalState = globalThis;
4755
4766
  __name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
4756
4767
  __name(notifyFarmCacheInvalidation, "notifyFarmCacheInvalidation");
4768
+ __name(notifyFarmCacheTask, "notifyFarmCacheTask");
4757
4769
  __name(applyFarmCacheInvalidations, "applyFarmCacheInvalidations");
4758
4770
  __name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
4759
4771
  __name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
4760
4772
  __name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
4773
+ __name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
4761
4774
  }
4762
4775
  });
4763
4776
 
@@ -4853,16 +4866,24 @@ function sanitizeServerActionError(_error) {
4853
4866
  message: "Server function failed"
4854
4867
  };
4855
4868
  }
4856
- function runWithServerActionRequest(request, callback) {
4869
+ async function runWithServerActionRequest(request, callback) {
4857
4870
  throwIfAborted(request.signal);
4858
- return getServerActionStorage().run(
4859
- {
4860
- request,
4861
- signal: request.signal,
4862
- invalidations: /* @__PURE__ */ new Set()
4863
- },
4864
- callback
4865
- );
4871
+ const context = {
4872
+ request,
4873
+ signal: request.signal,
4874
+ invalidations: /* @__PURE__ */ new Set(),
4875
+ cacheTasks: /* @__PURE__ */ new Set()
4876
+ };
4877
+ return getServerActionStorage().run(context, async () => {
4878
+ try {
4879
+ const result = await callback();
4880
+ await Promise.all(context.cacheTasks);
4881
+ return result;
4882
+ } catch (error) {
4883
+ await Promise.allSettled(context.cacheTasks);
4884
+ throw error;
4885
+ }
4886
+ });
4866
4887
  }
4867
4888
  function getServerActionExecutionContext() {
4868
4889
  return getServerActionStorage().getStore();
@@ -5173,6 +5194,9 @@ var init_server_action_security = __esm({
5173
5194
  subscribeFarmCacheInvalidation((key) => {
5174
5195
  getServerActionExecutionContext()?.invalidations.add(key);
5175
5196
  });
5197
+ subscribeFarmCacheTask((task) => {
5198
+ getServerActionExecutionContext()?.cacheTasks.add(task);
5199
+ });
5176
5200
  __name(getServerActionStorage, "getServerActionStorage");
5177
5201
  __name(getFallbackAbortController, "getFallbackAbortController");
5178
5202
  __name(parseBodySizeLimit, "parseBodySizeLimit");
@@ -6231,9 +6255,51 @@ function defineCacheKey() {
6231
6255
  });
6232
6256
  };
6233
6257
  }
6258
+ function storageCacheAdapter(storage, options = {}) {
6259
+ if (!storage || typeof storage.getItem !== "function" || typeof storage.setItem !== "function") {
6260
+ throw new TypeError("storageCacheAdapter expects a compatible storage client.");
6261
+ }
6262
+ const base = normalizeCacheNamespace(options.base || "farm-cache");
6263
+ const entryKey = /* @__PURE__ */ __name((key) => `${base}:entry:${key}`, "entryKey");
6264
+ const tagKey = /* @__PURE__ */ __name((tag) => `${base}:tag:${tag}`, "tagKey");
6265
+ return {
6266
+ name: "storage",
6267
+ get: /* @__PURE__ */ __name((key) => storage.getItem(entryKey(key)), "get"),
6268
+ set: /* @__PURE__ */ __name(async (key, entry) => {
6269
+ await storage.setItem(entryKey(key), entry);
6270
+ }, "set"),
6271
+ delete: /* @__PURE__ */ __name(async (key) => {
6272
+ await storage.removeItem(entryKey(key));
6273
+ }, "delete"),
6274
+ clear: storage.clear ? async () => {
6275
+ await storage.clear(base);
6276
+ } : void 0,
6277
+ getTagVersions: /* @__PURE__ */ __name(async (tags) => {
6278
+ const versions = await Promise.all(
6279
+ tags.map(async (tag) => {
6280
+ const value = await storage.getItem(tagKey(tag));
6281
+ return [tag, normalizeAdapterVersion(value)];
6282
+ })
6283
+ );
6284
+ return Object.fromEntries(versions);
6285
+ }, "getTagVersions"),
6286
+ invalidateTags: /* @__PURE__ */ __name(async (tags) => {
6287
+ await Promise.all(
6288
+ tags.map(async (tag) => {
6289
+ const key = tagKey(tag);
6290
+ const current = normalizeAdapterVersion(await storage.getItem(key));
6291
+ await storage.setItem(key, Math.max(Date.now(), current + 1));
6292
+ })
6293
+ );
6294
+ }, "invalidateTags")
6295
+ };
6296
+ }
6234
6297
  function getFarmDataCache() {
6235
6298
  return sharedFarmDataCache;
6236
6299
  }
6300
+ function configureFarmCache(config) {
6301
+ sharedFarmDataCache.configure(config);
6302
+ }
6237
6303
  function unstable_cache(fn, keyParts = [], options = {}) {
6238
6304
  return async (...args) => {
6239
6305
  const locale = getActiveFarmI18nSnapshot()?.locale;
@@ -6248,24 +6314,64 @@ function unstable_cache(fn, keyParts = [], options = {}) {
6248
6314
  };
6249
6315
  }
6250
6316
  function revalidateTag(_tag, _profile) {
6251
- getFarmDataCache().revalidateTag(_tag, {
6317
+ const cache = getFarmDataCache();
6318
+ if (cache.hasAdapter) {
6319
+ const task = cache.revalidateTagAsync(_tag, {
6320
+ source: "revalidateTag",
6321
+ profile: _profile
6322
+ }).then(() => void 0);
6323
+ notifyFarmCacheTask(task);
6324
+ return task;
6325
+ }
6326
+ cache.revalidateTag(_tag, {
6252
6327
  source: "revalidateTag",
6253
6328
  profile: _profile
6254
6329
  });
6255
6330
  }
6256
6331
  function updateTag(tag) {
6257
- getFarmDataCache().revalidateTag(tag, { source: "updateTag" });
6332
+ const cache = getFarmDataCache();
6333
+ if (cache.hasAdapter) {
6334
+ const task = cache.revalidateTagAsync(tag, { source: "updateTag" }).then(() => void 0);
6335
+ notifyFarmCacheTask(task);
6336
+ return task;
6337
+ }
6338
+ cache.revalidateTag(tag, { source: "updateTag" });
6258
6339
  }
6259
6340
  function revalidatePath(routePath) {
6260
- getFarmDataCache().revalidatePath(routePath);
6341
+ const cache = getFarmDataCache();
6342
+ if (cache.hasAdapter) {
6343
+ const task = cache.revalidatePathAsync(routePath).then(() => void 0);
6344
+ notifyFarmCacheTask(task);
6345
+ return task;
6346
+ }
6347
+ cache.revalidatePath(routePath);
6261
6348
  }
6262
6349
  function invalidate(key) {
6263
6350
  const clientKey = createRouteDataCacheKey(key);
6264
- getFarmDataCache().revalidateTag(createRouteDataCacheTag(key), { source: "updateTag" });
6351
+ const task = updateTag(createRouteDataCacheTag(key));
6265
6352
  notifyFarmCacheInvalidation(clientKey);
6353
+ return task;
6266
6354
  }
6267
6355
  function invalidateRouteData(key) {
6268
- invalidate(key);
6356
+ return invalidate(key);
6357
+ }
6358
+ async function applyFarmCacheInvalidationTargets(targets) {
6359
+ if (!Array.isArray(targets)) {
6360
+ throw new TypeError("Cache invalidations must resolve to an array of targets.");
6361
+ }
6362
+ const clientKeys = [];
6363
+ for (const target of targets) {
6364
+ assertFarmCacheInvalidationTarget(target);
6365
+ if ("key" in target) {
6366
+ await invalidate(target.key);
6367
+ clientKeys.push(createRouteDataCacheKey(target.key));
6368
+ } else if ("path" in target) {
6369
+ await revalidatePath(target.path);
6370
+ } else {
6371
+ await updateTag(target.tag);
6372
+ }
6373
+ }
6374
+ return Array.from(new Set(clientKeys));
6269
6375
  }
6270
6376
  function createPathCacheTag(routePath) {
6271
6377
  return `path:${normalizeRevalidatePath(routePath)}`;
@@ -6320,6 +6426,60 @@ function normalizeCacheTag(tag) {
6320
6426
  }
6321
6427
  return normalized;
6322
6428
  }
6429
+ function normalizeCacheNamespace(namespace) {
6430
+ if (typeof namespace !== "string") {
6431
+ throw new TypeError("Cache namespace must be a string.");
6432
+ }
6433
+ const normalized = namespace.trim().replace(/:+$/g, "");
6434
+ if (!normalized) {
6435
+ throw new Error("Cache namespace cannot be empty.");
6436
+ }
6437
+ return normalized;
6438
+ }
6439
+ function normalizeAdapterVersion(value) {
6440
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
6441
+ }
6442
+ function normalizePositiveDuration(value, fallback, name) {
6443
+ if (value === void 0) return fallback;
6444
+ if (!Number.isFinite(value) || value <= 0) {
6445
+ throw new TypeError(`${name} must be a positive number of milliseconds.`);
6446
+ }
6447
+ return Math.floor(value);
6448
+ }
6449
+ function delay(ms) {
6450
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
6451
+ }
6452
+ function normalizeCacheOptionsTags(options) {
6453
+ const tags = /* @__PURE__ */ new Set();
6454
+ for (const tag of options.tags ?? []) {
6455
+ tags.add(normalizeCacheTag(tag));
6456
+ }
6457
+ for (const routePath of options.paths ?? []) {
6458
+ tags.add(createPathCacheTag(routePath));
6459
+ }
6460
+ return tags;
6461
+ }
6462
+ function assertFarmCacheEntry(entry, expectedKey) {
6463
+ if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
6464
+ throw new TypeError(
6465
+ `Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
6466
+ );
6467
+ }
6468
+ }
6469
+ function assertFarmCacheInvalidationTarget(target) {
6470
+ if (!target || typeof target !== "object") {
6471
+ throw new TypeError("Cache invalidation targets must be { key }, { path }, or { tag }.");
6472
+ }
6473
+ if ("key" in target) {
6474
+ const key = target.key;
6475
+ if (typeof key === "string" || Array.isArray(key)) return;
6476
+ } else if ("path" in target && typeof target.path === "string") {
6477
+ return;
6478
+ } else if ("tag" in target && typeof target.tag === "string") {
6479
+ return;
6480
+ }
6481
+ throw new TypeError("Cache invalidation targets must contain a string/array key, path, or tag.");
6482
+ }
6323
6483
  function getFunctionCacheIdentity(fn) {
6324
6484
  if (fn.name) {
6325
6485
  return `name:${fn.name}`;
@@ -6380,12 +6540,53 @@ var init_cache = __esm({
6380
6540
  init_bridge();
6381
6541
  init_cache_invalidation();
6382
6542
  __name(defineCacheKey, "defineCacheKey");
6543
+ __name(storageCacheAdapter, "storageCacheAdapter");
6383
6544
  _FarmDataCache = class _FarmDataCache {
6384
- constructor() {
6545
+ constructor(config = {}) {
6385
6546
  this.entries = /* @__PURE__ */ new Map();
6386
6547
  this.inflight = /* @__PURE__ */ new Map();
6387
6548
  this.invalidatedTagVersions = /* @__PURE__ */ new Map();
6388
6549
  this.version = 0;
6550
+ this.namespace = "farm";
6551
+ this.local = true;
6552
+ this.lease = {
6553
+ enabled: true,
6554
+ ttlMs: 1e4,
6555
+ waitTimeoutMs: 1e4,
6556
+ pollIntervalMs: 25
6557
+ };
6558
+ this.configure(config);
6559
+ }
6560
+ configure(config = {}) {
6561
+ this.adapter = config.adapter;
6562
+ this.namespace = normalizeCacheNamespace(config.namespace || "farm");
6563
+ this.local = !config.adapter;
6564
+ this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
6565
+ enabled: true,
6566
+ ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
6567
+ waitTimeoutMs: normalizePositiveDuration(
6568
+ config.lease?.waitTimeoutMs,
6569
+ 1e4,
6570
+ "cache.lease.waitTimeoutMs"
6571
+ ),
6572
+ pollIntervalMs: normalizePositiveDuration(
6573
+ config.lease?.pollIntervalMs,
6574
+ 25,
6575
+ "cache.lease.pollIntervalMs"
6576
+ )
6577
+ };
6578
+ if (!this.local) {
6579
+ this.entries.clear();
6580
+ this.inflight.clear();
6581
+ this.invalidatedTagVersions.clear();
6582
+ this.version = 0;
6583
+ }
6584
+ }
6585
+ get adapterName() {
6586
+ return this.adapter?.name || (this.adapter ? "custom" : "memory");
6587
+ }
6588
+ get hasAdapter() {
6589
+ return this.adapter !== void 0;
6389
6590
  }
6390
6591
  get size() {
6391
6592
  return this.entries.size;
@@ -6421,6 +6622,45 @@ var init_cache = __esm({
6421
6622
  });
6422
6623
  return this.toPublicEntry(entry);
6423
6624
  }
6625
+ async getEntryAsync(key, options = {}) {
6626
+ if (this.local) {
6627
+ const localEntry = this.getEntry(key, options);
6628
+ if (localEntry) return localEntry;
6629
+ }
6630
+ if (!this.adapter) {
6631
+ return this.local ? void 0 : this.getEntry(key, options);
6632
+ }
6633
+ const entry = await this.adapter.get(this.createAdapterKey(key));
6634
+ if (!entry) {
6635
+ emitFarmEvent({ type: "cache.miss", key });
6636
+ return void 0;
6637
+ }
6638
+ assertFarmCacheEntry(entry, key);
6639
+ const stale = await this.isAdapterEntryStale(entry, options.now);
6640
+ if (stale) {
6641
+ emitFarmEvent({
6642
+ type: "cache.stale",
6643
+ key,
6644
+ tags: [...entry.tags],
6645
+ revalidate: entry.revalidate
6646
+ });
6647
+ if (!options.allowStale) {
6648
+ emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
6649
+ return void 0;
6650
+ }
6651
+ }
6652
+ emitFarmEvent({
6653
+ type: "cache.hit",
6654
+ key,
6655
+ tags: [...entry.tags],
6656
+ revalidate: entry.revalidate,
6657
+ stale
6658
+ });
6659
+ if (this.local && !stale) {
6660
+ this.hydrateLocalEntry(entry);
6661
+ }
6662
+ return { ...entry, key };
6663
+ }
6424
6664
  set(key, value, options = {}) {
6425
6665
  const tags = /* @__PURE__ */ new Set();
6426
6666
  for (const tag of options.tags ?? []) {
@@ -6433,6 +6673,7 @@ var init_cache = __esm({
6433
6673
  key,
6434
6674
  value,
6435
6675
  tags,
6676
+ tagVersions: void 0,
6436
6677
  createdAt: options.createdAt ?? Date.now(),
6437
6678
  createdVersion: ++this.version,
6438
6679
  revalidate: normalizeRevalidate(options.revalidate)
@@ -6446,11 +6687,45 @@ var init_cache = __esm({
6446
6687
  });
6447
6688
  return this.toPublicEntry(entry);
6448
6689
  }
6690
+ async setAsync(key, value, options = {}, tagVersions) {
6691
+ const tags = normalizeCacheOptionsTags(options);
6692
+ const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
6693
+ const entry = {
6694
+ key,
6695
+ value,
6696
+ tags: Array.from(tags),
6697
+ tagVersions: capturedVersions,
6698
+ createdAt: options.createdAt ?? Date.now(),
6699
+ createdVersion: ++this.version,
6700
+ revalidate: normalizeRevalidate(options.revalidate)
6701
+ };
6702
+ if (this.local) {
6703
+ this.hydrateLocalEntry(entry);
6704
+ }
6705
+ if (this.adapter) {
6706
+ await this.adapter.set(this.createAdapterKey(key), entry);
6707
+ }
6708
+ emitFarmEvent({
6709
+ type: "cache.set",
6710
+ key,
6711
+ tags: [...entry.tags],
6712
+ revalidate: entry.revalidate
6713
+ });
6714
+ return entry;
6715
+ }
6449
6716
  delete(key) {
6450
6717
  const deleted = this.entries.delete(key);
6451
6718
  emitFarmEvent({ type: "cache.delete", key, deleted });
6452
6719
  return deleted;
6453
6720
  }
6721
+ async deleteAsync(key) {
6722
+ const deleted = this.entries.delete(key);
6723
+ if (this.adapter) {
6724
+ await this.adapter.delete(this.createAdapterKey(key));
6725
+ }
6726
+ emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
6727
+ return this.adapter ? true : deleted;
6728
+ }
6454
6729
  clear() {
6455
6730
  const count = this.entries.size;
6456
6731
  this.entries.clear();
@@ -6459,6 +6734,10 @@ var init_cache = __esm({
6459
6734
  this.version = 0;
6460
6735
  emitFarmEvent({ type: "cache.clear", count });
6461
6736
  }
6737
+ async clearAsync() {
6738
+ this.clear();
6739
+ await this.adapter?.clear?.();
6740
+ }
6462
6741
  isStale(entry, now2 = Date.now()) {
6463
6742
  if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now2 - entry.createdAt >= entry.revalidate * 1e3) {
6464
6743
  return true;
@@ -6471,6 +6750,12 @@ var init_cache = __esm({
6471
6750
  }
6472
6751
  return false;
6473
6752
  }
6753
+ async isStaleAsync(entry, now2 = Date.now()) {
6754
+ if (this.adapter) {
6755
+ return this.isAdapterEntryStale(entry, now2);
6756
+ }
6757
+ return this.isStale(entry, now2);
6758
+ }
6474
6759
  revalidateTag(tag, options = {}) {
6475
6760
  const normalized = normalizeCacheTag(tag);
6476
6761
  const count = this.invalidateTag(normalized);
@@ -6479,6 +6764,15 @@ var init_cache = __esm({
6479
6764
  );
6480
6765
  return count;
6481
6766
  }
6767
+ async revalidateTagAsync(tag, options = {}) {
6768
+ const normalized = normalizeCacheTag(tag);
6769
+ const count = this.invalidateTag(normalized);
6770
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
6771
+ emitFarmEvent(
6772
+ options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
6773
+ );
6774
+ return count;
6775
+ }
6482
6776
  revalidatePath(routePath) {
6483
6777
  const normalizedPath = normalizeRevalidatePath(routePath);
6484
6778
  const pathTag = createPathCacheTag(normalizedPath);
@@ -6495,8 +6789,25 @@ var init_cache = __esm({
6495
6789
  }
6496
6790
  return count;
6497
6791
  }
6792
+ async revalidatePathAsync(routePath) {
6793
+ const normalizedPath = normalizeRevalidatePath(routePath);
6794
+ const pathTag = createPathCacheTag(normalizedPath);
6795
+ const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
6796
+ const count = this.invalidateTag(pathTag);
6797
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
6798
+ emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
6799
+ if (pprCount > 0) {
6800
+ emitFarmEvent({
6801
+ type: "ppr.shell.invalidated",
6802
+ route: normalizedPath,
6803
+ reason: "revalidatePath",
6804
+ count: pprCount
6805
+ });
6806
+ }
6807
+ return count;
6808
+ }
6498
6809
  async getOrSet(key, producer, options = {}) {
6499
- const cached = this.getEntry(key);
6810
+ const cached = await this.getEntryAsync(key);
6500
6811
  if (cached) {
6501
6812
  return cached.value;
6502
6813
  }
@@ -6505,10 +6816,8 @@ var init_cache = __esm({
6505
6816
  emitFarmEvent({ type: "cache.dedupe", key });
6506
6817
  return inflight;
6507
6818
  }
6508
- const promise = Promise.resolve().then(producer).then((value) => {
6509
- this.set(key, value, options);
6510
- return value;
6511
- }).catch((error) => {
6819
+ const tags = Array.from(normalizeCacheOptionsTags(options));
6820
+ const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
6512
6821
  emitFarmEvent({ type: "cache.error", key, operation: "set", error });
6513
6822
  throw error;
6514
6823
  }).finally(() => {
@@ -6517,6 +6826,40 @@ var init_cache = __esm({
6517
6826
  this.inflight.set(key, promise);
6518
6827
  return promise;
6519
6828
  }
6829
+ async fillCacheEntry(key, producer, options, tags) {
6830
+ const leaseKey = `${this.namespace}:lease:${key}`;
6831
+ let leaseToken;
6832
+ if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
6833
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
6834
+ if (!leaseToken) {
6835
+ const shared = await this.waitForAdapterEntry(key);
6836
+ if (shared) {
6837
+ emitFarmEvent({ type: "cache.dedupe", key });
6838
+ return shared.value;
6839
+ }
6840
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
6841
+ }
6842
+ }
6843
+ try {
6844
+ const initialTagVersions = await this.getAdapterTagVersions(tags);
6845
+ const value = await producer();
6846
+ await this.setAsync(key, value, options, initialTagVersions);
6847
+ return value;
6848
+ } finally {
6849
+ if (leaseToken && this.adapter?.releaseLease) {
6850
+ await this.adapter.releaseLease(leaseKey, leaseToken);
6851
+ }
6852
+ }
6853
+ }
6854
+ async waitForAdapterEntry(key) {
6855
+ const deadline = Date.now() + this.lease.waitTimeoutMs;
6856
+ while (Date.now() < deadline) {
6857
+ await delay(this.lease.pollIntervalMs);
6858
+ const entry = await this.getEntryAsync(key);
6859
+ if (entry) return entry;
6860
+ }
6861
+ return void 0;
6862
+ }
6520
6863
  countEntriesForTag(tag) {
6521
6864
  let count = 0;
6522
6865
  for (const entry of this.entries.values()) {
@@ -6544,11 +6887,53 @@ var init_cache = __esm({
6544
6887
  key: entry.key,
6545
6888
  value: entry.value,
6546
6889
  tags: Array.from(entry.tags),
6890
+ tagVersions: entry.tagVersions,
6547
6891
  createdAt: entry.createdAt,
6548
6892
  createdVersion: entry.createdVersion,
6549
6893
  revalidate: entry.revalidate
6550
6894
  };
6551
6895
  }
6896
+ hydrateLocalEntry(entry) {
6897
+ this.entries.set(entry.key, {
6898
+ key: entry.key,
6899
+ value: entry.value,
6900
+ tags: new Set(entry.tags.map(normalizeCacheTag)),
6901
+ tagVersions: entry.tagVersions,
6902
+ createdAt: entry.createdAt,
6903
+ createdVersion: entry.createdVersion ?? ++this.version,
6904
+ revalidate: normalizeRevalidate(entry.revalidate)
6905
+ });
6906
+ }
6907
+ createAdapterKey(key) {
6908
+ return `${this.namespace}:entry:${key}`;
6909
+ }
6910
+ createAdapterTag(tag) {
6911
+ return `${this.namespace}:tag:${tag}`;
6912
+ }
6913
+ async getAdapterTagVersions(tags) {
6914
+ if (!this.adapter?.getTagVersions || tags.length === 0) return {};
6915
+ const normalized = tags.map(normalizeCacheTag);
6916
+ const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
6917
+ const versions = await this.adapter.getTagVersions(physicalTags);
6918
+ return Object.fromEntries(
6919
+ normalized.map((tag, index) => [
6920
+ tag,
6921
+ normalizeAdapterVersion(versions[physicalTags[index]])
6922
+ ])
6923
+ );
6924
+ }
6925
+ async isAdapterEntryStale(entry, now2 = Date.now()) {
6926
+ if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now2 - entry.createdAt >= entry.revalidate * 1e3) {
6927
+ return true;
6928
+ }
6929
+ const currentVersions = await this.getAdapterTagVersions(entry.tags);
6930
+ for (const tag of entry.tags) {
6931
+ if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
6932
+ return true;
6933
+ }
6934
+ }
6935
+ return false;
6936
+ }
6552
6937
  };
6553
6938
  __name(_FarmDataCache, "FarmDataCache");
6554
6939
  FarmDataCache = _FarmDataCache;
@@ -6558,12 +6943,14 @@ var init_cache = __esm({
6558
6943
  functionIds = /* @__PURE__ */ new WeakMap();
6559
6944
  nextFunctionId = 0;
6560
6945
  __name(getFarmDataCache, "getFarmDataCache");
6946
+ __name(configureFarmCache, "configureFarmCache");
6561
6947
  __name(unstable_cache, "unstable_cache");
6562
6948
  __name(revalidateTag, "revalidateTag");
6563
6949
  __name(updateTag, "updateTag");
6564
6950
  __name(revalidatePath, "revalidatePath");
6565
6951
  __name(invalidate, "invalidate");
6566
6952
  __name(invalidateRouteData, "invalidateRouteData");
6953
+ __name(applyFarmCacheInvalidationTargets, "applyFarmCacheInvalidationTargets");
6567
6954
  __name(createPathCacheTag, "createPathCacheTag");
6568
6955
  __name(createRouteDataCacheTag, "createRouteDataCacheTag");
6569
6956
  __name(createRouteDataCacheKey, "createRouteDataCacheKey");
@@ -6571,6 +6958,13 @@ var init_cache = __esm({
6571
6958
  __name(createFarmCacheKey, "createFarmCacheKey");
6572
6959
  __name(normalizeRevalidate, "normalizeRevalidate");
6573
6960
  __name(normalizeCacheTag, "normalizeCacheTag");
6961
+ __name(normalizeCacheNamespace, "normalizeCacheNamespace");
6962
+ __name(normalizeAdapterVersion, "normalizeAdapterVersion");
6963
+ __name(normalizePositiveDuration, "normalizePositiveDuration");
6964
+ __name(delay, "delay");
6965
+ __name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
6966
+ __name(assertFarmCacheEntry, "assertFarmCacheEntry");
6967
+ __name(assertFarmCacheInvalidationTarget, "assertFarmCacheInvalidationTarget");
6574
6968
  __name(getFunctionCacheIdentity, "getFunctionCacheIdentity");
6575
6969
  __name(stableSerialize, "stableSerialize");
6576
6970
  }
@@ -7696,6 +8090,83 @@ var init_routing = __esm({
7696
8090
  }
7697
8091
  });
7698
8092
 
8093
+ // src/routing/route-slots.ts
8094
+ function parseRouteSlotFile(filePath) {
8095
+ const normalized = filePath.replace(/\\/g, "/");
8096
+ const parts = normalized.split("/").filter(Boolean);
8097
+ const fileName = parts.at(-1) ?? "";
8098
+ const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
8099
+ if (baseName !== "page" && baseName !== "default") return null;
8100
+ const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
8101
+ if (slotIndex < 0) return null;
8102
+ if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
8103
+ throw new Error(`Nested route slots are not supported in "${filePath}"`);
8104
+ }
8105
+ const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
8106
+ const name = slotMatch?.[1];
8107
+ if (!name) return null;
8108
+ const ownerParts = parts.slice(0, slotIndex);
8109
+ const contentParts = parts.slice(slotIndex + 1, -1);
8110
+ const marker = parseInterceptionMarker(contentParts[0]);
8111
+ let targetBase = ownerParts;
8112
+ let targetParts = contentParts;
8113
+ if (marker) {
8114
+ targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
8115
+ targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
8116
+ }
8117
+ const ownerFile = [...ownerParts, "layout.tsx"].join("/");
8118
+ const routeFile = [
8119
+ ...baseName === "default" ? ownerParts : targetBase,
8120
+ ...baseName === "default" ? [] : targetParts,
8121
+ "page.tsx"
8122
+ ].join("/");
8123
+ return {
8124
+ name,
8125
+ ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
8126
+ route: parseRoutePath(routeFile || "page.tsx"),
8127
+ interception: marker !== null,
8128
+ fallback: baseName === "default"
8129
+ };
8130
+ }
8131
+ function createRouteSlotContainerId(name, ownerPattern) {
8132
+ const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
8133
+ return `__farm_slot_${name}_${owner || "root"}__`;
8134
+ }
8135
+ function parseInterceptionMarker(segment) {
8136
+ if (!segment) return null;
8137
+ if (segment.startsWith("(...)")) {
8138
+ return {
8139
+ up: 0,
8140
+ root: true,
8141
+ remainder: segment.slice(5)
8142
+ };
8143
+ }
8144
+ if (segment.startsWith("(.)")) {
8145
+ return {
8146
+ up: 0,
8147
+ remainder: segment.slice(3)
8148
+ };
8149
+ }
8150
+ let remainder = segment;
8151
+ let up = 0;
8152
+ while (remainder.startsWith("(..)")) {
8153
+ up += 1;
8154
+ remainder = remainder.slice(4);
8155
+ }
8156
+ return up > 0 ? { up, remainder } : null;
8157
+ }
8158
+ var SLOT_SEGMENT;
8159
+ var init_route_slots = __esm({
8160
+ "src/routing/route-slots.ts"() {
8161
+ "use strict";
8162
+ init_utils();
8163
+ SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
8164
+ __name(parseRouteSlotFile, "parseRouteSlotFile");
8165
+ __name(createRouteSlotContainerId, "createRouteSlotContainerId");
8166
+ __name(parseInterceptionMarker, "parseInterceptionMarker");
8167
+ }
8168
+ });
8169
+
7699
8170
  // src/routing/route-manager.ts
7700
8171
  function routeSpecificity(entry) {
7701
8172
  return entry.route.segments.reduce((score, segment) => {
@@ -7767,11 +8238,13 @@ var init_route_manager = __esm({
7767
8238
  init_static_metadata_image();
7768
8239
  init_route_runtime();
7769
8240
  init_routing();
8241
+ init_route_slots();
7770
8242
  __name(routeSpecificity, "routeSpecificity");
7771
8243
  _RouteManager = class _RouteManager {
7772
8244
  constructor(config, viteServer) {
7773
8245
  this.routes = /* @__PURE__ */ new Map();
7774
8246
  this.layouts = /* @__PURE__ */ new Map();
8247
+ this.routeSlots = /* @__PURE__ */ new Map();
7775
8248
  this.loadings = /* @__PURE__ */ new Map();
7776
8249
  this.errors = /* @__PURE__ */ new Map();
7777
8250
  this.metadataImages = /* @__PURE__ */ new Map();
@@ -7787,6 +8260,7 @@ var init_route_manager = __esm({
7787
8260
  async discoverRoutes() {
7788
8261
  this.routes.clear();
7789
8262
  this.layouts.clear();
8263
+ this.routeSlots.clear();
7790
8264
  this.loadings.clear();
7791
8265
  this.errors.clear();
7792
8266
  this.metadataImages.clear();
@@ -7797,6 +8271,13 @@ var init_route_manager = __esm({
7797
8271
  await this.discoverFileRoutes(source);
7798
8272
  await this.discoverProgrammaticRoutes(source);
7799
8273
  }
8274
+ for (const slot of this.routeSlots.values()) {
8275
+ if (slot.interception && !this.routes.has(slot.pattern)) {
8276
+ throw new Error(
8277
+ `Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
8278
+ );
8279
+ }
8280
+ }
7800
8281
  this.routes = new Map(
7801
8282
  Array.from(this.routes.entries()).sort(
7802
8283
  ([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
@@ -7812,7 +8293,7 @@ var init_route_manager = __esm({
7812
8293
  /**
7813
8294
  * Find matching route for a given URL path
7814
8295
  */
7815
- matchRoute(pathname) {
8296
+ matchRoute(pathname, options = {}) {
7816
8297
  const routePathname = this.toRoutePathname(pathname);
7817
8298
  const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
7818
8299
  let matchedRoute = null;
@@ -7826,10 +8307,12 @@ var init_route_manager = __esm({
7826
8307
  }
7827
8308
  }
7828
8309
  const layouts = this.findMatchingLayouts(normalizedPath);
8310
+ const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
7829
8311
  return {
7830
8312
  route: matchedRoute,
7831
8313
  params,
7832
- layouts
8314
+ layouts,
8315
+ slots
7833
8316
  };
7834
8317
  }
7835
8318
  /**
@@ -7844,6 +8327,9 @@ var init_route_manager = __esm({
7844
8327
  getLayouts() {
7845
8328
  return new Map(this.layouts);
7846
8329
  }
8330
+ getRouteSlots() {
8331
+ return new Map(this.routeSlots);
8332
+ }
7847
8333
  /** Resolve route rules, inherited layouts, and the page export in precedence order. */
7848
8334
  async resolveRouteRuntimeConfig(pattern) {
7849
8335
  const routeEntry = this.routes.get(pattern);
@@ -8002,7 +8488,22 @@ var init_route_manager = __esm({
8002
8488
  pattern: entry.pattern,
8003
8489
  modulePath: toUrlPath(entry.modulePath)
8004
8490
  }));
8005
- return { routes, layouts };
8491
+ const slots = Array.from(this.routeSlots.values()).map((entry) => {
8492
+ const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
8493
+ return {
8494
+ name: entry.name,
8495
+ ownerPattern: entry.ownerPattern,
8496
+ pattern: entry.pattern,
8497
+ modulePath: toUrlPath(entry.modulePath),
8498
+ containerId: entry.containerId,
8499
+ interception: entry.interception,
8500
+ fallback: entry.fallback,
8501
+ shouldHydrate: metadata.shouldHydrate,
8502
+ isClientComponent: metadata.isClientComponent,
8503
+ segments: entry.route.segments
8504
+ };
8505
+ });
8506
+ return { routes, layouts, slots };
8006
8507
  }
8007
8508
  /**
8008
8509
  * Load a route module dynamically
@@ -8079,6 +8580,7 @@ var init_route_manager = __esm({
8079
8580
  async discoverFileRoutes(source) {
8080
8581
  const appDir = resolveAppPath(source.root, source.srcDir, "app");
8081
8582
  const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
8583
+ const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
8082
8584
  const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
8083
8585
  const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
8084
8586
  const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
@@ -8087,7 +8589,7 @@ var init_route_manager = __esm({
8087
8589
  appDir
8088
8590
  );
8089
8591
  for (const [kind, files, target] of [
8090
- ["page", pageFiles, this.routes],
8592
+ ["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
8091
8593
  ["layout", layoutFiles, this.layouts],
8092
8594
  ["loading", loadingFiles, this.loadings],
8093
8595
  ["error", errorFiles, this.errors]
@@ -8111,6 +8613,32 @@ var init_route_manager = __esm({
8111
8613
  });
8112
8614
  }
8113
8615
  }
8616
+ for (const file of [...pageFiles, ...slotDefaultFiles]) {
8617
+ const slot = parseRouteSlotFile(file);
8618
+ if (!slot) continue;
8619
+ const modulePath = import_path5.default.join(appDir, file);
8620
+ const pattern = this.createRoutePattern(slot.route);
8621
+ const ownerPattern = this.createRoutePattern(slot.ownerRoute);
8622
+ const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
8623
+ const existing = this.routeSlots.get(key);
8624
+ if (existing?.sourceRoot === source.root) {
8625
+ throw new Error(
8626
+ `Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
8627
+ );
8628
+ }
8629
+ this.routeSlots.set(key, {
8630
+ route: slot.route,
8631
+ modulePath,
8632
+ pattern,
8633
+ source: "file",
8634
+ sourceRoot: source.root,
8635
+ name: slot.name,
8636
+ ownerPattern,
8637
+ interception: slot.interception,
8638
+ fallback: slot.fallback,
8639
+ containerId: createRouteSlotContainerId(slot.name, ownerPattern)
8640
+ });
8641
+ }
8114
8642
  for (const file of metadataImageFiles) {
8115
8643
  const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
8116
8644
  const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
@@ -8236,6 +8764,71 @@ var init_route_manager = __esm({
8236
8764
  }
8237
8765
  return matchingLayouts;
8238
8766
  }
8767
+ findMatchingRouteSlots(pathname, interceptFrom) {
8768
+ const groups = /* @__PURE__ */ new Map();
8769
+ for (const entry of this.routeSlots.values()) {
8770
+ if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
8771
+ const key = `${entry.ownerPattern}:${entry.name}`;
8772
+ const entries = groups.get(key) ?? [];
8773
+ entries.push(entry);
8774
+ groups.set(key, entries);
8775
+ }
8776
+ const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
8777
+ const matches = [];
8778
+ for (const entries of groups.values()) {
8779
+ const candidates = entries.filter((entry) => !entry.fallback).filter(
8780
+ (entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
8781
+ ).map((entry) => ({
8782
+ entry,
8783
+ match: matchRoute(pathname, entry.route.segments)
8784
+ })).filter((candidate) => candidate.match.matches).sort((left, right) => {
8785
+ if (left.entry.interception !== right.entry.interception) {
8786
+ return left.entry.interception ? -1 : 1;
8787
+ }
8788
+ return routeSpecificity(right.entry) - routeSpecificity(left.entry);
8789
+ });
8790
+ const selected = candidates[0];
8791
+ if (selected) {
8792
+ matches.push({
8793
+ name: selected.entry.name,
8794
+ ownerPattern: selected.entry.ownerPattern,
8795
+ containerId: selected.entry.containerId,
8796
+ interception: selected.entry.interception,
8797
+ fallback: false,
8798
+ route: selected.entry,
8799
+ params: selected.match.params
8800
+ });
8801
+ continue;
8802
+ }
8803
+ const fallback = entries.find((entry) => entry.fallback);
8804
+ if (fallback) {
8805
+ matches.push({
8806
+ name: fallback.name,
8807
+ ownerPattern: fallback.ownerPattern,
8808
+ containerId: fallback.containerId,
8809
+ interception: false,
8810
+ fallback: true,
8811
+ route: fallback,
8812
+ params: {}
8813
+ });
8814
+ }
8815
+ }
8816
+ return matches.sort((left, right) => {
8817
+ const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
8818
+ return ownerDifference || left.name.localeCompare(right.name);
8819
+ });
8820
+ }
8821
+ matchesRoutePrefix(pathname, pattern) {
8822
+ if (pattern === "/") return true;
8823
+ const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
8824
+ const pathSegments = pathname.split("/").filter(Boolean);
8825
+ if (patternSegments.length > pathSegments.length) return false;
8826
+ for (let index = 0; index < patternSegments.length; index++) {
8827
+ const segment = patternSegments[index];
8828
+ if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
8829
+ }
8830
+ return true;
8831
+ }
8239
8832
  findNearestBoundary(pathname, boundaries) {
8240
8833
  const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
8241
8834
  const pathSegments = normalizedPath.split("/").filter(Boolean);
@@ -9408,13 +10001,23 @@ function readPageState() {
9408
10001
  if (!state || typeof state !== "object") return null;
9409
10002
  return state[FARM_PAGE_STATE_KEY] ?? null;
9410
10003
  }
9411
- function createHistoryState(path28, pageState, currentState) {
10004
+ function createHistoryState(path28, pageState, currentState, interceptFrom) {
9412
10005
  const base = currentState && typeof currentState === "object" ? { ...currentState } : {};
9413
- return {
10006
+ const nextState = {
9414
10007
  ...base,
9415
10008
  path: path28,
9416
10009
  [FARM_PAGE_STATE_KEY]: pageState
9417
10010
  };
10011
+ if (interceptFrom === null) {
10012
+ delete nextState[FARM_INTERCEPT_FROM_KEY];
10013
+ } else if (interceptFrom) {
10014
+ nextState[FARM_INTERCEPT_FROM_KEY] = interceptFrom;
10015
+ }
10016
+ return nextState;
10017
+ }
10018
+ function getPageDataCacheKey(path28, interceptFrom) {
10019
+ return interceptFrom ? `${path28}
10020
+ intercept:${interceptFrom}` : path28;
9418
10021
  }
9419
10022
  function createNavigationLocation(url) {
9420
10023
  return {
@@ -9427,7 +10030,7 @@ function createNavigationLocation(url) {
9427
10030
  function getScrollElementStorageKey(path28, key) {
9428
10031
  return `farm-scroll-${path28}:${key}`;
9429
10032
  }
9430
- var FARM_PAGE_STATE_KEY, IDLE_NAVIGATION_STATE, routerInstance, _SPARouter, SPARouter;
10033
+ var FARM_PAGE_STATE_KEY, FARM_INTERCEPT_FROM_KEY, IDLE_NAVIGATION_STATE, routerInstance, _SPARouter, SPARouter;
9431
10034
  var init_spa_router = __esm({
9432
10035
  "src/client/spa-router.ts"() {
9433
10036
  "use strict";
@@ -9436,6 +10039,7 @@ var init_spa_router = __esm({
9436
10039
  init_deployment();
9437
10040
  init_client_runtime();
9438
10041
  FARM_PAGE_STATE_KEY = "__farmPageState";
10042
+ FARM_INTERCEPT_FROM_KEY = "__farmInterceptFrom";
9439
10043
  IDLE_NAVIGATION_STATE = {
9440
10044
  state: "idle",
9441
10045
  pending: false,
@@ -9506,7 +10110,11 @@ var init_spa_router = __esm({
9506
10110
  return;
9507
10111
  }
9508
10112
  const from = window.location.pathname + window.location.search;
9509
- if (await this.shouldBlockNavigation({ from, to: fullPath, action: replace ? "replace" : "push" })) {
10113
+ if (await this.shouldBlockNavigation({
10114
+ from,
10115
+ to: fullPath,
10116
+ action: replace ? "replace" : "push"
10117
+ })) {
9510
10118
  return;
9511
10119
  }
9512
10120
  if (this.options.scrollRestoration) {
@@ -9524,11 +10132,11 @@ var init_spa_router = __esm({
9524
10132
  to: url,
9525
10133
  action: replace ? "replace" : "push"
9526
10134
  });
9527
- const pageData = await this.fetchPageData(fullPath);
10135
+ const pageData = await this.fetchPageData(fullPath, true, from);
9528
10136
  if (clientNavigation) {
9529
10137
  await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);
9530
10138
  }
9531
- if (pageData.isClientComponent === false) {
10139
+ if (pageData.isClientComponent === false && !pageData.interception) {
9532
10140
  this.finishNavigation();
9533
10141
  window.location.assign(pageData.canonicalPath || fullPath);
9534
10142
  return;
@@ -9566,11 +10174,12 @@ var init_spa_router = __esm({
9566
10174
  if (isFarmLocaleChangeHref(href)) return;
9567
10175
  const url = new URL(href, window.location.origin);
9568
10176
  const fullPath = url.pathname + url.search;
10177
+ const interceptFrom = window.location.pathname + window.location.search;
9569
10178
  if (this.prefetchingUrls.has(fullPath)) return;
9570
- if (this.isCached(fullPath)) return;
10179
+ if (this.isCached(fullPath, interceptFrom)) return;
9571
10180
  this.prefetchingUrls.add(fullPath);
9572
10181
  try {
9573
- await this.fetchPageData(fullPath, false);
10182
+ await this.fetchPageData(fullPath, false, interceptFrom);
9574
10183
  } catch (error) {
9575
10184
  console.warn("[Farm.js] Prefetch failed:", href, error);
9576
10185
  } finally {
@@ -9645,7 +10254,12 @@ var init_spa_router = __esm({
9645
10254
  }
9646
10255
  async commitNavigation(options) {
9647
10256
  const historyPath = options.pageData.canonicalPath || options.fullPath;
9648
- const historyState = createHistoryState(historyPath, options.state);
10257
+ const historyState = createHistoryState(
10258
+ historyPath,
10259
+ options.state,
10260
+ void 0,
10261
+ options.pageData.interception?.from ?? null
10262
+ );
9649
10263
  if (options.replace) {
9650
10264
  window.history.replaceState(historyState, "", historyPath);
9651
10265
  } else {
@@ -9700,15 +10314,17 @@ var init_spa_router = __esm({
9700
10314
  /**
9701
10315
  * Fetch page data from cache or server
9702
10316
  */
9703
- async fetchPageData(path28, recover = true) {
9704
- const cached = this.cache.get(path28);
10317
+ async fetchPageData(path28, recover = true, interceptFrom) {
10318
+ const cacheKey = getPageDataCacheKey(path28, interceptFrom);
10319
+ const cached = this.cache.get(cacheKey);
9705
10320
  if (cached && Date.now() - cached.timestamp < this.options.cacheMaxAge) {
9706
10321
  return cached.data;
9707
10322
  }
9708
10323
  const response = await fetch(`/__farm/page-data?path=${encodeURIComponent(path28)}`, {
9709
10324
  headers: createFarmDeploymentRequestHeaders(this.options.deploymentId, {
9710
10325
  Accept: "application/x-farm-deferred+json, application/json",
9711
- "X-Farm-SPA": "1"
10326
+ "X-Farm-SPA": "1",
10327
+ ...interceptFrom ? { "X-Farm-Intercept-From": interceptFrom } : {}
9712
10328
  })
9713
10329
  });
9714
10330
  if (isFarmDeploymentMismatchResponse(response, this.options.deploymentId)) {
@@ -9726,7 +10342,7 @@ var init_spa_router = __esm({
9726
10342
  throw new Error(`Failed to fetch page data: ${response.status}`);
9727
10343
  }
9728
10344
  const data = await readDeferredDataResponse(response);
9729
- this.cache.set(path28, {
10345
+ this.cache.set(cacheKey, {
9730
10346
  data,
9731
10347
  timestamp: Date.now()
9732
10348
  });
@@ -9757,7 +10373,8 @@ var init_spa_router = __esm({
9757
10373
  to: window.location.href,
9758
10374
  action: "pop"
9759
10375
  });
9760
- const pageData = await this.fetchPageData(path28);
10376
+ const interceptFrom = typeof event.state?.[FARM_INTERCEPT_FROM_KEY] === "string" ? event.state[FARM_INTERCEPT_FROM_KEY] : void 0;
10377
+ const pageData = await this.fetchPageData(path28, true, interceptFrom);
9761
10378
  if (clientNavigation) {
9762
10379
  await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);
9763
10380
  }
@@ -9788,8 +10405,8 @@ var init_spa_router = __esm({
9788
10405
  /**
9789
10406
  * Check if URL is cached
9790
10407
  */
9791
- isCached(path28) {
9792
- const cached = this.cache.get(path28);
10408
+ isCached(path28, interceptFrom) {
10409
+ const cached = this.cache.get(getPageDataCacheKey(path28, interceptFrom));
9793
10410
  return cached !== void 0 && Date.now() - cached.timestamp < this.options.cacheMaxAge;
9794
10411
  }
9795
10412
  /**
@@ -9904,6 +10521,7 @@ var init_spa_router = __esm({
9904
10521
  __name(replaceState, "replaceState");
9905
10522
  __name(readPageState, "readPageState");
9906
10523
  __name(createHistoryState, "createHistoryState");
10524
+ __name(getPageDataCacheKey, "getPageDataCacheKey");
9907
10525
  __name(createNavigationLocation, "createNavigationLocation");
9908
10526
  __name(getScrollElementStorageKey, "getScrollElementStorageKey");
9909
10527
  }
@@ -11279,7 +11897,9 @@ var init_renderer = __esm({
11279
11897
  async runWithRequestContext(request, fn) {
11280
11898
  return _runWithCurrentRequest(
11281
11899
  request,
11282
- () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, { redirect: false }) : fn()
11900
+ () => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
11901
+ redirect: false
11902
+ }) : fn()
11283
11903
  );
11284
11904
  }
11285
11905
  async resolveRouteContext(input) {
@@ -11302,11 +11922,11 @@ var init_renderer = __esm({
11302
11922
  /**
11303
11923
  * Check if a path should be served from SSG cache
11304
11924
  */
11305
- shouldServeSSG(pathname) {
11925
+ async shouldServeSSG(pathname) {
11306
11926
  const ssgPage = matchSSGPage(pathname, this.ssgManifest);
11307
11927
  if (!ssgPage) return null;
11308
- const cached = this.getCachedSSGPage(pathname);
11309
- if (cached && this.dataCache.isStale(cached)) {
11928
+ const cached = await this.getCachedSSGPage(pathname);
11929
+ if (cached && await this.dataCache.isStaleAsync(cached)) {
11310
11930
  this.regenerateSSGPage(ssgPage);
11311
11931
  }
11312
11932
  return ssgPage;
@@ -11318,12 +11938,12 @@ var init_renderer = __esm({
11318
11938
  return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
11319
11939
  }
11320
11940
  getCachedSSGPage(urlPath) {
11321
- return this.dataCache.getEntry(this.getSSGCacheKey(urlPath), {
11941
+ return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
11322
11942
  allowStale: true
11323
11943
  });
11324
11944
  }
11325
- cacheSSGPage(page2, html, options) {
11326
- this.dataCache.set(
11945
+ async cacheSSGPage(page2, html, options) {
11946
+ await this.dataCache.setAsync(
11327
11947
  this.getSSGCacheKey(page2.urlPath),
11328
11948
  { html, document: options.document },
11329
11949
  {
@@ -11335,11 +11955,11 @@ var init_renderer = __esm({
11335
11955
  );
11336
11956
  }
11337
11957
  getCachedPPRShell(pathname, search) {
11338
- return this.dataCache.getEntry(this.getPPRCacheKey(pathname, search));
11958
+ return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
11339
11959
  }
11340
- cachePPRShell(options, html) {
11960
+ async cachePPRShell(options, html) {
11341
11961
  const key = this.getPPRCacheKey(options.pathname, options.search);
11342
- this.dataCache.set(
11962
+ await this.dataCache.setAsync(
11343
11963
  key,
11344
11964
  { html },
11345
11965
  {
@@ -11437,7 +12057,7 @@ var init_renderer = __esm({
11437
12057
  }
11438
12058
  const { renderToString } = await import("react-dom/server");
11439
12059
  const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
11440
- this.cacheSSGPage(page2, html, { document: false });
12060
+ await this.cacheSSGPage(page2, html, { document: false });
11441
12061
  logger.info(`ISR: Regenerated ${page2.urlPath}`);
11442
12062
  } catch (error) {
11443
12063
  logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
@@ -11451,7 +12071,7 @@ var init_renderer = __esm({
11451
12071
  * Serve a pre-rendered SSG page
11452
12072
  */
11453
12073
  async serveSSGPage(req, res, page2) {
11454
- const cached = this.getCachedSSGPage(page2.urlPath);
12074
+ const cached = await this.getCachedSSGPage(page2.urlPath);
11455
12075
  if (cached) {
11456
12076
  res.setHeader("Content-Type", "text/html; charset=utf-8");
11457
12077
  res.setHeader("X-Farm-SSG", "cached");
@@ -11469,9 +12089,12 @@ var init_renderer = __esm({
11469
12089
  if (fs2.existsSync(htmlPath)) {
11470
12090
  const stat = fs2.statSync(htmlPath);
11471
12091
  const html = fs2.readFileSync(htmlPath, "utf-8");
11472
- this.cacheSSGPage(page2, html, { document: true, createdAt: stat.mtimeMs });
11473
- const fileCacheEntry = this.getCachedSSGPage(page2.urlPath);
11474
- if (fileCacheEntry && this.dataCache.isStale(fileCacheEntry)) {
12092
+ await this.cacheSSGPage(page2, html, {
12093
+ document: true,
12094
+ createdAt: stat.mtimeMs
12095
+ });
12096
+ const fileCacheEntry = await this.getCachedSSGPage(page2.urlPath);
12097
+ if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
11475
12098
  this.regenerateSSGPage(page2);
11476
12099
  }
11477
12100
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -11517,6 +12140,7 @@ var init_renderer = __esm({
11517
12140
  let pathname = "/";
11518
12141
  let params = {};
11519
12142
  let layouts = [];
12143
+ let routeSlots = [];
11520
12144
  let searchParamsObject = {};
11521
12145
  let middlewareMap = /* @__PURE__ */ new Map();
11522
12146
  let middlewareContext = /* @__PURE__ */ new Map();
@@ -11549,7 +12173,7 @@ var init_renderer = __esm({
11549
12173
  }
11550
12174
  this.applyDeploymentHeaders(req, res);
11551
12175
  if (process.env.NODE_ENV === "production") {
11552
- const ssgPage = this.shouldServeSSG(pathname);
12176
+ const ssgPage = await this.shouldServeSSG(pathname);
11553
12177
  if (ssgPage) {
11554
12178
  const served = await this.serveSSGPage(req, res, ssgPage);
11555
12179
  if (served) {
@@ -11562,6 +12186,7 @@ var init_renderer = __esm({
11562
12186
  const route2 = match.route;
11563
12187
  params = match.params;
11564
12188
  layouts = match.layouts;
12189
+ routeSlots = match.slots ?? [];
11565
12190
  if (!route2) {
11566
12191
  emitFarmEvent({ type: "route.notFound", pathname });
11567
12192
  await this.render404(req, res);
@@ -11578,7 +12203,9 @@ var init_renderer = __esm({
11578
12203
  errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
11579
12204
  middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
11580
12205
  middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
11581
- pluginExposedContext = getRequestContextSnapshot(req, { exposedOnly: true });
12206
+ pluginExposedContext = getRequestContextSnapshot(req, {
12207
+ exposedOnly: true
12208
+ });
11582
12209
  const currentRequest = createWebRequestFromFarmRequest(req);
11583
12210
  const routeContext = await this.resolveRouteContext({
11584
12211
  request: currentRequest,
@@ -11642,8 +12269,16 @@ var init_renderer = __esm({
11642
12269
  revalidate: renderingConfig.revalidate
11643
12270
  } : void 0;
11644
12271
  if (renderingConfig.ppr && pprBypassReason) {
11645
- emitFarmEvent({ type: "ppr.shell.bypass", route: pathname, reason: pprBypassReason });
11646
- emitFarmEvent({ type: "cache.bypass", route: pathname, reason: pprBypassReason });
12272
+ emitFarmEvent({
12273
+ type: "ppr.shell.bypass",
12274
+ route: pathname,
12275
+ reason: pprBypassReason
12276
+ });
12277
+ emitFarmEvent({
12278
+ type: "cache.bypass",
12279
+ route: pathname,
12280
+ reason: pprBypassReason
12281
+ });
11647
12282
  if (pprBypassReason === "refresh") {
11648
12283
  pprRefreshRoute = pathname;
11649
12284
  emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
@@ -11651,14 +12286,22 @@ var init_renderer = __esm({
11651
12286
  }
11652
12287
  if (pprShellOptions) {
11653
12288
  const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
11654
- const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
12289
+ const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
11655
12290
  if (cachedPPRShell) {
11656
- emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
12291
+ emitFarmEvent({
12292
+ type: "ppr.shell.hit",
12293
+ route: pathname,
12294
+ key: pprCacheKey
12295
+ });
11657
12296
  this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
11658
12297
  completeRender(res.statusCode || 200, pathname);
11659
12298
  return;
11660
12299
  }
11661
- emitFarmEvent({ type: "ppr.shell.miss", route: pathname, key: pprCacheKey });
12300
+ emitFarmEvent({
12301
+ type: "ppr.shell.miss",
12302
+ route: pathname,
12303
+ key: pprCacheKey
12304
+ });
11662
12305
  }
11663
12306
  let LoadingFallbackComponent = null;
11664
12307
  if (loadingBoundaryEntry) {
@@ -11682,14 +12325,77 @@ var init_renderer = __esm({
11682
12325
  );
11683
12326
  const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route2.modulePath, this.config.root);
11684
12327
  const isClientComponent = moduleMetadata.isClientComponent;
12328
+ const renderedRouteSlots = await Promise.all(
12329
+ routeSlots.map(async (slot) => {
12330
+ const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
12331
+ if (!slotModule.default) {
12332
+ throw new Error(
12333
+ `Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
12334
+ );
12335
+ }
12336
+ const slotContext = await this.resolveRouteContext({
12337
+ request: currentRequest,
12338
+ rawRequest: req,
12339
+ params: slot.params,
12340
+ search: searchParamsObject,
12341
+ path: pathname
12342
+ });
12343
+ const rawSlotProps = withFarmRouteContext(
12344
+ {
12345
+ params: slot.params,
12346
+ searchParams: Promise.resolve(searchParamsObject),
12347
+ path: pathname,
12348
+ middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
12349
+ context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
12350
+ },
12351
+ slotContext
12352
+ );
12353
+ const slotProps = await parseRouteModuleProps(slotModule, {
12354
+ props: rawSlotProps,
12355
+ search: searchParamsObject,
12356
+ routePath: slot.route.pattern
12357
+ });
12358
+ const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
12359
+ return {
12360
+ ...slot,
12361
+ module: slotModule,
12362
+ props: slotProps,
12363
+ isClientComponent: metadata.isClientComponent,
12364
+ shouldHydrate: metadata.shouldHydrate
12365
+ };
12366
+ })
12367
+ );
11685
12368
  const shouldHydrate = moduleMetadata.shouldHydrate;
12369
+ const hasHydratableRouteSlots = renderedRouteSlots.some(
12370
+ (slot) => slot.isClientComponent || slot.shouldHydrate
12371
+ );
11686
12372
  req.__FARM_PAGE_PATH__ = route2.modulePath;
11687
12373
  req.__FARM_ROUTE__ = pathname;
11688
12374
  req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
11689
12375
  req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
12376
+ req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
11690
12377
  req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
11691
12378
  loadingBoundaryEntry.modulePath.indexOf("/src/app/")
11692
12379
  ) : null;
12380
+ req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
12381
+ name: slot.name,
12382
+ ownerPattern: slot.ownerPattern,
12383
+ containerId: slot.containerId,
12384
+ interception: slot.interception,
12385
+ fallback: slot.fallback,
12386
+ modulePath: slot.route.modulePath,
12387
+ isClientComponent: slot.isClientComponent,
12388
+ shouldHydrate: slot.shouldHydrate,
12389
+ props: {
12390
+ params: slot.props.params,
12391
+ search: slot.props.search,
12392
+ searchParams: slot.props.search,
12393
+ ..."data" in slot.props ? { data: slot.props.data } : {},
12394
+ ...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
12395
+ ...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
12396
+ path: pathname
12397
+ }
12398
+ }));
11693
12399
  req.__FARM_PROPS__ = {
11694
12400
  params: pageProps.params,
11695
12401
  search: pageProps.search,
@@ -11749,12 +12455,32 @@ var init_renderer = __esm({
11749
12455
  let wrappedElement = pageElement;
11750
12456
  for (let i = layoutModules.length - 1; i >= 0; i--) {
11751
12457
  const layoutModule = layoutModules[i];
12458
+ const layoutEntry = layouts[i];
11752
12459
  const LayoutComponent = layoutModule.default;
12460
+ const slotProps = {};
12461
+ for (const slot of renderedRouteSlots) {
12462
+ if (slot.ownerPattern !== layoutEntry.pattern) continue;
12463
+ let slotElement = import_react4.default.createElement(
12464
+ slot.module.default,
12465
+ slot.props
12466
+ );
12467
+ slotElement = import_react4.default.createElement(
12468
+ "div",
12469
+ {
12470
+ id: slot.containerId,
12471
+ "data-farm-route-slot": slot.name,
12472
+ "data-farm-slot-owner": slot.ownerPattern
12473
+ },
12474
+ slotElement
12475
+ );
12476
+ slotProps[slot.name] = slotElement;
12477
+ }
11753
12478
  wrappedElement = import_react4.default.createElement(
11754
12479
  LayoutComponent,
11755
12480
  {
11756
12481
  children: wrappedElement,
11757
- params
12482
+ params,
12483
+ ...slotProps
11758
12484
  }
11759
12485
  );
11760
12486
  }
@@ -11791,7 +12517,10 @@ var init_renderer = __esm({
11791
12517
  routeManifest,
11792
12518
  captureStaticShell: Boolean(pprShellOptions),
11793
12519
  observabilityRoute: pathname,
11794
- onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({ type: "ppr.suspense.holeDetected", route: pathname }) : void 0,
12520
+ onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
12521
+ type: "ppr.suspense.holeDetected",
12522
+ route: pathname
12523
+ }) : void 0,
11795
12524
  onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
11796
12525
  }
11797
12526
  );
@@ -11839,7 +12568,11 @@ var init_renderer = __esm({
11839
12568
  }
11840
12569
  emitFarmEvent({ type: "render.error", route: pathname, error });
11841
12570
  if (pprRefreshRoute) {
11842
- emitFarmEvent({ type: "ppr.refresh.error", route: pprRefreshRoute, error });
12571
+ emitFarmEvent({
12572
+ type: "ppr.refresh.error",
12573
+ route: pprRefreshRoute,
12574
+ error
12575
+ });
11843
12576
  }
11844
12577
  logger.error(`Error rendering page: ${error}`);
11845
12578
  if (res.headersSent || res.writableEnded) {
@@ -11892,7 +12625,9 @@ var init_renderer = __esm({
11892
12625
  if (typeof layoutModule.generateMetadata === "function") {
11893
12626
  metadata = mergeMetadata(
11894
12627
  metadata,
11895
- await layoutModule.generateMetadata({ params: options.pageProps.params })
12628
+ await layoutModule.generateMetadata({
12629
+ params: options.pageProps.params
12630
+ })
11896
12631
  );
11897
12632
  }
11898
12633
  }
@@ -12123,7 +12858,13 @@ var init_renderer = __esm({
12123
12858
  clientEntry: "/@farm/client.js",
12124
12859
  routes: {},
12125
12860
  layouts: {},
12126
- sharedAssets: [{ tag: "link", attrs: { rel: "stylesheet", href: "/src/app/globals.css" } }]
12861
+ slots: [],
12862
+ sharedAssets: [
12863
+ {
12864
+ tag: "link",
12865
+ attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
12866
+ }
12867
+ ]
12127
12868
  };
12128
12869
  for (const routeEntry of manifest.routes) {
12129
12870
  clientManifest.routes[routeEntry.pattern] = {
@@ -12145,9 +12886,26 @@ var init_renderer = __esm({
12145
12886
  assets: []
12146
12887
  };
12147
12888
  }
12148
- const deferredProps = prepareDeferredData(req.__FARM_PROPS__ || {});
12889
+ for (const slotEntry of manifest.slots ?? []) {
12890
+ clientManifest.slots.push({
12891
+ ...slotEntry,
12892
+ preloads: [slotEntry.modulePath],
12893
+ assets: []
12894
+ });
12895
+ }
12896
+ const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
12897
+ (slot) => ({
12898
+ ...slot,
12899
+ modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
12900
+ })
12901
+ );
12902
+ const deferredProps = prepareDeferredData({
12903
+ page: req.__FARM_PROPS__ || {},
12904
+ slots: routeSlotPayload
12905
+ });
12149
12906
  const propsScript = `<script>
12150
- window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
12907
+ window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
12908
+ window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
12151
12909
  window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
12152
12910
  window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
12153
12911
  window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
@@ -12160,7 +12918,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
12160
12918
  window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
12161
12919
  ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
12162
12920
  </script>`;
12163
- const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
12921
+ const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
12164
12922
  const {
12165
12923
  title,
12166
12924
  tags: metaTags,
@@ -12271,7 +13029,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
12271
13029
  didError = true;
12272
13030
  if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
12273
13031
  logger.error(`SSR shell error: ${error}`);
12274
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
13032
+ emitFarmEvent({
13033
+ type: "render.error",
13034
+ route: observabilityRoute,
13035
+ error
13036
+ });
12275
13037
  }
12276
13038
  if (clearMiddlewareData) {
12277
13039
  clearMiddlewareData();
@@ -12282,7 +13044,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
12282
13044
  didError = true;
12283
13045
  if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
12284
13046
  logger.error(`SSR streaming error: ${error}`);
12285
- emitFarmEvent({ type: "render.error", route: observabilityRoute, error });
13047
+ emitFarmEvent({
13048
+ type: "render.error",
13049
+ route: observabilityRoute,
13050
+ error
13051
+ });
12286
13052
  }
12287
13053
  }
12288
13054
  });
@@ -12488,6 +13254,7 @@ var init_app = __esm({
12488
13254
  init_devtools_config();
12489
13255
  init_config();
12490
13256
  init_server2();
13257
+ init_cache();
12491
13258
  defaultDocsConfig = {
12492
13259
  enabled: false,
12493
13260
  entry: "/docs",
@@ -12509,6 +13276,7 @@ var init_app = __esm({
12509
13276
  logger.info("Initializing Farm.js application...");
12510
13277
  }
12511
13278
  await initStorage(this.config.storage);
13279
+ await configureFarmCache(this.config.cache);
12512
13280
  await this.i18nRuntime.initialize();
12513
13281
  await this.verifyAppStructure();
12514
13282
  await this.routeManager.discoverRoutes();
@@ -12540,6 +13308,7 @@ var init_app = __esm({
12540
13308
  preset: config.preset ?? "node-server",
12541
13309
  deploy: config.deploy || {},
12542
13310
  storage: config.storage || {},
13311
+ cache: config.cache || {},
12543
13312
  integrations: config.integrations || {},
12544
13313
  plugins: config.plugins || [],
12545
13314
  migrations: config.migrations || { commands: [] },
@@ -13138,6 +13907,184 @@ var init_hmr = __esm({
13138
13907
  }
13139
13908
  });
13140
13909
 
13910
+ // src/api/transport.ts
13911
+ function multipart(schema) {
13912
+ if (!Object.isExtensible(schema) && !isMultipartSchema(schema)) {
13913
+ throw new TypeError("multipart() requires an extensible schema object");
13914
+ }
13915
+ if (!isMultipartSchema(schema)) {
13916
+ Object.defineProperty(schema, "__farmMultipartSchema", {
13917
+ value: true,
13918
+ configurable: false,
13919
+ enumerable: false,
13920
+ writable: false
13921
+ });
13922
+ }
13923
+ return schema;
13924
+ }
13925
+ function isMultipartSchema(value) {
13926
+ return typeof value === "object" && value !== null && value.__farmMultipartSchema === true && typeof value.parse === "function";
13927
+ }
13928
+ function toFormData(values) {
13929
+ const formData = new FormData();
13930
+ for (const [key, value] of Object.entries(values)) {
13931
+ if (isUnsafeFormKey(key)) continue;
13932
+ if (Array.isArray(value)) {
13933
+ for (const entry of value) appendFormValue(formData, key, entry);
13934
+ continue;
13935
+ }
13936
+ appendFormValue(formData, key, value);
13937
+ }
13938
+ return formData;
13939
+ }
13940
+ function jsonStream(source, init = {}) {
13941
+ const iterator = toAsyncIterator(source);
13942
+ const encoder = new TextEncoder();
13943
+ let finished = false;
13944
+ const body = new ReadableStream(
13945
+ {
13946
+ async pull(controller) {
13947
+ if (finished) return;
13948
+ try {
13949
+ const next = await iterator.next();
13950
+ if (next.done) {
13951
+ finished = true;
13952
+ controller.close();
13953
+ return;
13954
+ }
13955
+ controller.enqueue(encoder.encode(`${JSON.stringify(next.value)}
13956
+ `));
13957
+ } catch (error) {
13958
+ finished = true;
13959
+ controller.error(error);
13960
+ }
13961
+ },
13962
+ async cancel(reason) {
13963
+ finished = true;
13964
+ await iterator.return?.(reason);
13965
+ }
13966
+ },
13967
+ {
13968
+ // Do not read the next application event until the response consumer
13969
+ // requests another chunk.
13970
+ highWaterMark: 0
13971
+ }
13972
+ );
13973
+ const headers2 = new Headers(init.headers);
13974
+ if (!headers2.has("content-type")) {
13975
+ headers2.set("content-type", "application/x-ndjson; charset=utf-8");
13976
+ }
13977
+ headers2.set("cache-control", headers2.get("cache-control") ?? "no-store");
13978
+ return new Response(body, {
13979
+ ...init,
13980
+ headers: headers2
13981
+ });
13982
+ }
13983
+ function isJSONStreamResponse(response) {
13984
+ const contentType = response.headers?.get?.("content-type")?.toLowerCase() ?? "";
13985
+ return contentType.includes("application/x-ndjson") || contentType.includes("application/ndjson");
13986
+ }
13987
+ function readJSONStream(response) {
13988
+ if (!response.body) {
13989
+ throw new TypeError("Cannot read a JSON stream response without a body");
13990
+ }
13991
+ const reader = response.body.getReader();
13992
+ const decoder = new TextDecoder();
13993
+ let buffer = "";
13994
+ let completed = false;
13995
+ let claimed = false;
13996
+ const iterator = {
13997
+ async next() {
13998
+ while (true) {
13999
+ const lineEnd = buffer.indexOf("\n");
14000
+ if (lineEnd >= 0) {
14001
+ const line = buffer.slice(0, lineEnd).trim();
14002
+ buffer = buffer.slice(lineEnd + 1);
14003
+ if (!line) continue;
14004
+ return { done: false, value: JSON.parse(line) };
14005
+ }
14006
+ if (completed) {
14007
+ const line = buffer.trim();
14008
+ buffer = "";
14009
+ if (!line) return { done: true, value: void 0 };
14010
+ return { done: false, value: JSON.parse(line) };
14011
+ }
14012
+ const chunk = await reader.read();
14013
+ completed = chunk.done;
14014
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
14015
+ }
14016
+ },
14017
+ async return() {
14018
+ completed = true;
14019
+ buffer = "";
14020
+ await reader.cancel();
14021
+ return { done: true, value: void 0 };
14022
+ }
14023
+ };
14024
+ return {
14025
+ response,
14026
+ async cancel(reason) {
14027
+ completed = true;
14028
+ buffer = "";
14029
+ await reader.cancel(reason);
14030
+ },
14031
+ [Symbol.asyncIterator]() {
14032
+ if (claimed) {
14033
+ throw new TypeError("Farm API streams can only be consumed once");
14034
+ }
14035
+ claimed = true;
14036
+ return iterator;
14037
+ }
14038
+ };
14039
+ }
14040
+ function isFarmAPIStream(value) {
14041
+ return typeof value === "object" && value !== null && "response" in value && typeof value.cancel === "function" && typeof value[Symbol.asyncIterator] === "function";
14042
+ }
14043
+ function appendFormValue(formData, key, value) {
14044
+ if (value === void 0) return;
14045
+ if (value === null) {
14046
+ formData.append(key, "");
14047
+ return;
14048
+ }
14049
+ if (value instanceof Blob) {
14050
+ formData.append(key, value);
14051
+ return;
14052
+ }
14053
+ if (value instanceof Date) {
14054
+ formData.append(key, value.toISOString());
14055
+ return;
14056
+ }
14057
+ formData.append(key, String(value));
14058
+ }
14059
+ function isUnsafeFormKey(key) {
14060
+ return key === "__proto__" || key === "constructor" || key === "prototype";
14061
+ }
14062
+ function toAsyncIterator(source) {
14063
+ if (Symbol.asyncIterator in Object(source)) {
14064
+ return source[Symbol.asyncIterator]();
14065
+ }
14066
+ const iterator = source[Symbol.iterator]();
14067
+ return {
14068
+ next: /* @__PURE__ */ __name(async () => iterator.next(), "next"),
14069
+ return: iterator.return ? async (value) => iterator.return(value) : void 0
14070
+ };
14071
+ }
14072
+ var init_transport = __esm({
14073
+ "src/api/transport.ts"() {
14074
+ "use strict";
14075
+ __name(multipart, "multipart");
14076
+ __name(isMultipartSchema, "isMultipartSchema");
14077
+ __name(toFormData, "toFormData");
14078
+ __name(jsonStream, "jsonStream");
14079
+ __name(isJSONStreamResponse, "isJSONStreamResponse");
14080
+ __name(readJSONStream, "readJSONStream");
14081
+ __name(isFarmAPIStream, "isFarmAPIStream");
14082
+ __name(appendFormValue, "appendFormValue");
14083
+ __name(isUnsafeFormKey, "isUnsafeFormKey");
14084
+ __name(toAsyncIterator, "toAsyncIterator");
14085
+ }
14086
+ });
14087
+
13141
14088
  // src/api/endpoint.ts
13142
14089
  function isEndpointFailure(value) {
13143
14090
  return value instanceof EndpointFailure;
@@ -13193,6 +14140,7 @@ function createEndpoint(pathOrOptions, optionsOrHandler, maybeHandler) {
13193
14140
  endpoint2.__errors = errors;
13194
14141
  endpoint2.__types = {
13195
14142
  body: options.body,
14143
+ inputBody: isMultipartSchema(options.body) ? "form-data" : options.body,
13196
14144
  query: options.query,
13197
14145
  headers: options.headers,
13198
14146
  response: null,
@@ -13303,34 +14251,10 @@ async function applyEndpointInvalidations(declaration, context, result) {
13303
14251
  const targets = typeof declaration === "function" ? await declaration(context) : declaration;
13304
14252
  if (!Array.isArray(targets)) {
13305
14253
  throw new TypeError(
13306
- "Endpoint invalidates must resolve to an array of { key } or { path } targets"
14254
+ "Endpoint invalidates must resolve to an array of { key }, { path }, or { tag } targets"
13307
14255
  );
13308
14256
  }
13309
- const clientKeys = [];
13310
- for (const target of targets) {
13311
- assertEndpointInvalidationTarget(target);
13312
- if ("key" in target) {
13313
- invalidate(target.key);
13314
- clientKeys.push(createRouteDataCacheKey(target.key));
13315
- } else {
13316
- revalidatePath(target.path);
13317
- }
13318
- }
13319
- return Array.from(new Set(clientKeys));
13320
- }
13321
- function assertEndpointInvalidationTarget(target) {
13322
- if (!target || typeof target !== "object") {
13323
- throw new TypeError("Endpoint invalidation targets must be { key } or { path } objects");
13324
- }
13325
- if ("key" in target) {
13326
- const key = target.key;
13327
- if (typeof key === "string" || Array.isArray(key)) return;
13328
- } else if ("path" in target && typeof target.path === "string") {
13329
- return;
13330
- }
13331
- throw new TypeError(
13332
- "Endpoint invalidation targets must contain a string/array key or a path string"
13333
- );
14257
+ return applyFarmCacheInvalidationTargets(targets);
13334
14258
  }
13335
14259
  function createInitialEndpointContext(value) {
13336
14260
  if (value === void 0 || value === null) return EMPTY_ENDPOINT_CONTEXT;
@@ -13416,6 +14340,7 @@ var init_endpoint = __esm({
13416
14340
  "use strict";
13417
14341
  import_better_call = require("better-call");
13418
14342
  init_cache();
14343
+ init_transport();
13419
14344
  _EndpointFailure = class _EndpointFailure extends Error {
13420
14345
  constructor(code, data, options) {
13421
14346
  super(options.message);
@@ -13437,7 +14362,6 @@ var init_endpoint = __esm({
13437
14362
  __name(normalizeEndpointMiddleware, "normalizeEndpointMiddleware");
13438
14363
  __name(runEndpointMiddleware, "runEndpointMiddleware");
13439
14364
  __name(applyEndpointInvalidations, "applyEndpointInvalidations");
13440
- __name(assertEndpointInvalidationTarget, "assertEndpointInvalidationTarget");
13441
14365
  __name(createInitialEndpointContext, "createInitialEndpointContext");
13442
14366
  __name(mergeEndpointContext, "mergeEndpointContext");
13443
14367
  __name(isPlainEndpointContext, "isPlainEndpointContext");
@@ -13495,7 +14419,7 @@ async function invokeAPIRouteEndpointInContext(endpoint2, request, params) {
13495
14419
  });
13496
14420
  let body = void 0;
13497
14421
  if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
13498
- body = await readJSONBody(request);
14422
+ body = await readRequestBody2(request);
13499
14423
  }
13500
14424
  const headers2 = Object.fromEntries(request.headers.entries());
13501
14425
  const types = endpoint2.__types || {};
@@ -13593,16 +14517,46 @@ function isFarmContextHandler(endpoint2) {
13593
14517
  const firstParameter = (arrowMatch?.[1] || arrowMatch?.[2] || functionMatch?.[1] || "").split(",")[0].trim();
13594
14518
  return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
13595
14519
  }
13596
- async function readJSONBody(request) {
14520
+ async function readRequestBody2(request) {
14521
+ const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
13597
14522
  try {
14523
+ if (contentType === "multipart/form-data") {
14524
+ return formDataToObject(await request.clone().formData());
14525
+ }
13598
14526
  const text2 = await request.clone().text();
13599
- if (text2) {
14527
+ if (!text2) return void 0;
14528
+ if (contentType === "application/x-www-form-urlencoded") {
14529
+ return searchParamsToObject2(new URLSearchParams(text2));
14530
+ }
14531
+ if (contentType === "application/json" || contentType?.endsWith("+json")) {
13600
14532
  return JSON.parse(text2);
13601
14533
  }
14534
+ return JSON.parse(text2);
13602
14535
  } catch {
13603
14536
  }
13604
14537
  return void 0;
13605
14538
  }
14539
+ function formDataToObject(formData) {
14540
+ return entriesToObject(formData.entries());
14541
+ }
14542
+ function searchParamsToObject2(searchParams) {
14543
+ return entriesToObject(searchParams.entries());
14544
+ }
14545
+ function entriesToObject(entries) {
14546
+ const output = /* @__PURE__ */ Object.create(null);
14547
+ for (const [key, value] of entries) {
14548
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
14549
+ const current = output[key];
14550
+ if (current === void 0) {
14551
+ output[key] = value;
14552
+ } else if (Array.isArray(current)) {
14553
+ current.push(value);
14554
+ } else {
14555
+ output[key] = [current, value];
14556
+ }
14557
+ }
14558
+ return output;
14559
+ }
13606
14560
  function validateInput(schema, value, error) {
13607
14561
  if (!schema || typeof schema.parse !== "function") {
13608
14562
  return value;
@@ -13701,7 +14655,10 @@ var init_runtime2 = __esm({
13701
14655
  __name(attachEndpointInvalidations, "attachEndpointInvalidations");
13702
14656
  __name(createEndpointFailureResponse, "createEndpointFailureResponse");
13703
14657
  __name(isFarmContextHandler, "isFarmContextHandler");
13704
- __name(readJSONBody, "readJSONBody");
14658
+ __name(readRequestBody2, "readRequestBody");
14659
+ __name(formDataToObject, "formDataToObject");
14660
+ __name(searchParamsToObject2, "searchParamsToObject");
14661
+ __name(entriesToObject, "entriesToObject");
13705
14662
  __name(validateInput, "validateInput");
13706
14663
  __name(matchRoutePath, "matchRoutePath");
13707
14664
  __name(getPathSegments, "getPathSegments");
@@ -15034,6 +15991,7 @@ async function generateRouteTypes(options) {
15034
15991
  absolute: false
15035
15992
  });
15036
15993
  for (const file of pageFiles) {
15994
+ if (parseRouteSlotFile(file)) continue;
15037
15995
  const route2 = parseRoutePath(file);
15038
15996
  if (route2.type === "page") {
15039
15997
  const pattern = createRoutePattern(route2);
@@ -15099,6 +16057,7 @@ var init_generate_route_types = __esm({
15099
16057
  path12 = __toESM(require("path"));
15100
16058
  fs5 = __toESM(require("fs"));
15101
16059
  init_utils();
16060
+ init_route_slots();
15102
16061
  init_routes_server();
15103
16062
  init_write_file_if_changed();
15104
16063
  __name(routeSegmentsToTsTypeLiteral, "routeSegmentsToTsTypeLiteral");
@@ -15816,7 +16775,7 @@ var init_environment_vite = __esm({
15816
16775
  var version;
15817
16776
  var init_package = __esm({
15818
16777
  "package.json"() {
15819
- version = "0.1.0-beta.3";
16778
+ version = "0.1.0-beta.4";
15820
16779
  }
15821
16780
  });
15822
16781
 
@@ -20003,6 +20962,7 @@ async function resolveConfig(userConfig, mode) {
20003
20962
  observability: userConfig.observability ?? false,
20004
20963
  devtools: resolveFarmDevtoolsConfig(userConfig.devtools, mode),
20005
20964
  storage: userConfig.storage || {},
20965
+ cache: userConfig.cache || {},
20006
20966
  suppressLintOnLink: userConfig.suppressLintOnLink ?? false,
20007
20967
  experimental: {
20008
20968
  serverComponents: false,
@@ -23644,7 +24604,7 @@ function farmPlugin(options = {}, initialPluginManager) {
23644
24604
  }, "isProgrammaticRouteSourceFile");
23645
24605
  const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
23646
24606
  const normalized = file.replace(/\\/g, "/");
23647
- 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(
24607
+ 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(
23648
24608
  normalized
23649
24609
  );
23650
24610
  }, "isAppRuntimeFile");
@@ -24335,7 +25295,10 @@ function farmPlugin(options = {}, initialPluginManager) {
24335
25295
  method: req.method || "GET"
24336
25296
  });
24337
25297
  }
24338
- const match = routeManager3.matchRoute(targetPath);
25298
+ const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
25299
+ const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
25300
+ interceptFrom: interceptFromHeader
25301
+ });
24339
25302
  if (pm) {
24340
25303
  await pm.runHookParallel("afterRouteMatch", {
24341
25304
  pathname: targetPath,
@@ -24351,7 +25314,7 @@ function farmPlugin(options = {}, initialPluginManager) {
24351
25314
  res.end(JSON.stringify({ error: "Route not found" }));
24352
25315
  return;
24353
25316
  }
24354
- const { route: route2, params, layouts } = match;
25317
+ const { route: route2, params, layouts, slots } = match;
24355
25318
  if (!route2) {
24356
25319
  res.statusCode = 404;
24357
25320
  res.setHeader("Content-Type", "application/json");
@@ -24406,6 +25369,54 @@ function farmPlugin(options = {}, initialPluginManager) {
24406
25369
  search: searchParams,
24407
25370
  routePath: route2.pattern
24408
25371
  });
25372
+ const routeSlots = await Promise.all(
25373
+ slots.map(async (slot) => {
25374
+ const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
25375
+ const slotMetadata = getClientModuleMetadata(
25376
+ slot.route.modulePath,
25377
+ server.config.root
25378
+ );
25379
+ const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
25380
+ request,
25381
+ params: slot.params,
25382
+ search: searchParams,
25383
+ path: targetUrl.pathname
25384
+ });
25385
+ const slotProps = await parseRouteModuleProps2(slotModule, {
25386
+ props: withFarmRouteContext(
25387
+ {
25388
+ params: slot.params,
25389
+ searchParams: Promise.resolve(searchParams),
25390
+ path: targetUrl.pathname
25391
+ },
25392
+ slotContext
25393
+ ),
25394
+ search: searchParams,
25395
+ routePath: slot.route.pattern
25396
+ });
25397
+ return {
25398
+ name: slot.name,
25399
+ ownerPattern: slot.ownerPattern,
25400
+ containerId: slot.containerId,
25401
+ interception: slot.interception,
25402
+ fallback: slot.fallback,
25403
+ modulePath: slot.route.modulePath,
25404
+ isClientComponent: slotMetadata.isClientComponent,
25405
+ shouldHydrate: slotMetadata.shouldHydrate,
25406
+ props: {
25407
+ params: slotProps.params,
25408
+ search: slotProps.search,
25409
+ searchParams: slotProps.search,
25410
+ ..."data" in slotProps ? { data: slotProps.data } : {},
25411
+ ...slotProps.__farmCanonicalPath ? {
25412
+ __farmCanonicalPath: slotProps.__farmCanonicalPath
25413
+ } : {},
25414
+ ...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
25415
+ path: targetUrl.pathname
25416
+ }
25417
+ };
25418
+ })
25419
+ );
24409
25420
  const projectRoot = server.config.root;
24410
25421
  const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
24411
25422
  if (absolutePath.startsWith(projectRoot)) {
@@ -24426,13 +25437,21 @@ function farmPlugin(options = {}, initialPluginManager) {
24426
25437
  },
24427
25438
  canonicalPath: routeProps.__farmCanonicalPath,
24428
25439
  modulePath: toUrlPath(route2.modulePath),
24429
- isClientComponent,
24430
- shouldHydrate,
25440
+ isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
25441
+ shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
24431
25442
  metadata: {
24432
25443
  title: mergedMetadata.title,
24433
25444
  description: mergedMetadata.description
24434
25445
  },
24435
25446
  layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
25447
+ routeSlots: routeSlots.map((slot) => ({
25448
+ ...slot,
25449
+ modulePath: toUrlPath(slot.modulePath)
25450
+ })),
25451
+ interception: routeSlots.some((slot) => slot.interception) ? {
25452
+ from: interceptFromHeader,
25453
+ slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
25454
+ } : void 0,
24436
25455
  i18n: getFarmI18nClientSnapshot()
24437
25456
  };
24438
25457
  await sendWebResponse(
@@ -24768,6 +25787,7 @@ function farmPlugin(options = {}, initialPluginManager) {
24768
25787
  export const getManifest = () => ({
24769
25788
  routes: {},
24770
25789
  layouts: {},
25790
+ slots: [],
24771
25791
  clientEntry: "/@farm/client.js",
24772
25792
  sharedAssets: []
24773
25793
  });
@@ -24778,6 +25798,7 @@ export const getManifest = () => ({
24778
25798
  clientEntry: "/@farm/client.js",
24779
25799
  routes: {},
24780
25800
  layouts: {},
25801
+ slots: [],
24781
25802
  sharedAssets: [
24782
25803
  {
24783
25804
  tag: "link",
@@ -24807,6 +25828,13 @@ export const getManifest = () => ({
24807
25828
  assets: []
24808
25829
  };
24809
25830
  }
25831
+ for (const slot of manifest.slots) {
25832
+ fullManifest.slots.push({
25833
+ ...slot,
25834
+ preloads: [slot.modulePath],
25835
+ assets: []
25836
+ });
25837
+ }
24810
25838
  return `
24811
25839
  // Auto-generated manifest for SPA navigation (TanStack Start pattern)
24812
25840
  // This manifest is inlined in the server bundle - no file on disk
@@ -25443,7 +26471,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
25443
26471
 
25444
26472
  // Get manifest from window (inlined by server in HTML)
25445
26473
  // Fallback to empty manifest if not available yet
25446
- const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
26474
+ const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
25447
26475
 
25448
26476
  // ====== CLIENT-SIDE ROUTE MATCHING ======
25449
26477
  // Matches URL to route using manifest (no server request!)
@@ -25782,6 +26810,9 @@ let LayoutComponent = null;
25782
26810
 
25783
26811
  // Track if we've taken over rendering from SSR
25784
26812
  let hasClientTakenOver = false;
26813
+ const routeSlotRoots = new Map();
26814
+ const routeSlotDefinitions = new Map();
26815
+ let activeRouteInterception = null;
25785
26816
 
25786
26817
  function normalizeServerProps(rawProps) {
25787
26818
  const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
@@ -25794,6 +26825,123 @@ function normalizeServerProps(rawProps) {
25794
26825
  return props;
25795
26826
  }
25796
26827
 
26828
+ function getRouteSlotKey(slot) {
26829
+ return slot.ownerPattern + ':' + slot.name;
26830
+ }
26831
+
26832
+ async function renderRouteSlot(slot, mode = 'render') {
26833
+ const container = document.getElementById(slot.containerId);
26834
+ if (!container || !slot.modulePath) return false;
26835
+ if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
26836
+ return false;
26837
+ }
26838
+
26839
+ let slotModule = pageModuleCache.get(slot.modulePath);
26840
+ if (!slotModule) {
26841
+ slotModule = await import(/* @vite-ignore */ slot.modulePath);
26842
+ pageModuleCache.set(slot.modulePath, slotModule);
26843
+ }
26844
+ const SlotComponent = slotModule?.default;
26845
+ if (!SlotComponent) return false;
26846
+
26847
+ const props = reviveDeferredData(
26848
+ normalizeServerProps(slot.props || {}),
26849
+ window.__FARM_DEFERRED_DATA__ || {},
26850
+ );
26851
+ const element = wrapWithIntegrationProviders(
26852
+ React.createElement(SlotComponent, props),
26853
+ );
26854
+ const key = getRouteSlotKey(slot);
26855
+ const existingRoot = routeSlotRoots.get(key);
26856
+
26857
+ if (mode === 'hydrate') {
26858
+ if (existingRoot) return true;
26859
+ const root = hydrateRoot(container, element);
26860
+ routeSlotRoots.set(key, root);
26861
+ } else {
26862
+ if (existingRoot) {
26863
+ try { existingRoot.unmount(); } catch (error) {}
26864
+ }
26865
+ const root = createRoot(container);
26866
+ root.render(element);
26867
+ routeSlotRoots.set(key, root);
26868
+ }
26869
+
26870
+ routeSlotDefinitions.set(key, slot);
26871
+ return true;
26872
+ }
26873
+
26874
+ async function hydrateInitialRouteSlots() {
26875
+ const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
26876
+ ? window.__FARM_ROUTE_SLOTS__
26877
+ : [];
26878
+ let hydrated = false;
26879
+
26880
+ for (const slot of slots) {
26881
+ routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
26882
+ if (!slot.isClientComponent && !slot.shouldHydrate) continue;
26883
+ try {
26884
+ hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
26885
+ } catch (error) {
26886
+ console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
26887
+ }
26888
+ }
26889
+
26890
+ return hydrated;
26891
+ }
26892
+
26893
+ async function renderRouteInterception(pageData) {
26894
+ const slots = Array.isArray(pageData.routeSlots)
26895
+ ? pageData.routeSlots.filter((slot) => slot.interception)
26896
+ : [];
26897
+ if (!pageData.interception || slots.length === 0) return false;
26898
+
26899
+ const previous = new Map();
26900
+ for (const slot of slots) {
26901
+ const key = getRouteSlotKey(slot);
26902
+ previous.set(key, routeSlotDefinitions.get(key) || null);
26903
+ if (!(await renderRouteSlot(slot, 'intercept'))) {
26904
+ return false;
26905
+ }
26906
+ }
26907
+
26908
+ activeRouteInterception = {
26909
+ from: pageData.interception.from,
26910
+ slots,
26911
+ previous,
26912
+ };
26913
+ return true;
26914
+ }
26915
+
26916
+ async function clearRouteInterception(destination) {
26917
+ if (!activeRouteInterception) return false;
26918
+ const active = activeRouteInterception;
26919
+ activeRouteInterception = null;
26920
+
26921
+ for (const slot of active.slots) {
26922
+ const key = getRouteSlotKey(slot);
26923
+ const root = routeSlotRoots.get(key);
26924
+ if (root) {
26925
+ try { root.unmount(); } catch (error) {}
26926
+ routeSlotRoots.delete(key);
26927
+ }
26928
+
26929
+ const previous = active.previous.get(key);
26930
+ if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
26931
+ await renderRouteSlot(previous, 'render');
26932
+ } else {
26933
+ const container = document.getElementById(slot.containerId);
26934
+ if (container) container.replaceChildren();
26935
+ if (previous) routeSlotDefinitions.set(key, previous);
26936
+ else routeSlotDefinitions.delete(key);
26937
+ }
26938
+ }
26939
+
26940
+ if (!active.from) return false;
26941
+ const background = new URL(active.from, window.location.origin);
26942
+ return destination === background.pathname + background.search;
26943
+ }
26944
+
25797
26945
  function applyCanonicalPathFromProps(props) {
25798
26946
  const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
25799
26947
  ? props.__farmCanonicalPath
@@ -26028,6 +27176,17 @@ async function tryHydrateImportedPage(
26028
27176
  async function renderPage(pageData) {
26029
27177
  const container = document.getElementById('root');
26030
27178
  if (!container) return;
27179
+ const destination = window.location.pathname + window.location.search;
27180
+
27181
+ if (pageData.interception) {
27182
+ if (await renderRouteInterception(pageData)) return;
27183
+ window.location.assign(destination);
27184
+ return;
27185
+ }
27186
+
27187
+ if (await clearRouteInterception(destination)) {
27188
+ return;
27189
+ }
26031
27190
 
26032
27191
  const route = {
26033
27192
  modulePath: pageData.modulePath,
@@ -26256,7 +27415,9 @@ async function hydrate() {
26256
27415
  window.__FARM_SHOULD_HYDRATE__ === true ||
26257
27416
  isClientComponent ||
26258
27417
  await moduleLooksClient(modulePath);
27418
+ const hydratedSlots = await hydrateInitialRouteSlots();
26259
27419
  if (!shouldHydrate) {
27420
+ if (hydratedSlots) replayPreHydrationClicks();
26260
27421
  console.log('[Farm.js] Server component - SPA router ready')
26261
27422
  return
26262
27423
  }
@@ -28023,6 +29184,7 @@ __export(src_exports, {
28023
29184
  DeferredDataError: () => DeferredDataError,
28024
29185
  DocsRoute: () => DocsRoute,
28025
29186
  EndpointFailure: () => EndpointFailure,
29187
+ FARM_API_ROUTE_META_SYMBOL: () => FARM_API_ROUTE_META_SYMBOL,
28026
29188
  FARM_API_ROUTE_REF_SYMBOL: () => FARM_API_ROUTE_REF_SYMBOL,
28027
29189
  FARM_CRON_MANIFEST: () => FARM_CRON_MANIFEST,
28028
29190
  FARM_DEFERRED_BRAND: () => FARM_DEFERRED_BRAND,
@@ -28067,6 +29229,7 @@ __export(src_exports, {
28067
29229
  _withAfterNodeMiddleware: () => _withAfterNodeMiddleware,
28068
29230
  after: () => after,
28069
29231
  api: () => api,
29232
+ applyFarmCacheInvalidationTargets: () => applyFarmCacheInvalidationTargets,
28070
29233
  applyFarmCacheInvalidations: () => applyFarmCacheInvalidations,
28071
29234
  applyFarmCronVercelCrons: () => applyFarmCronVercelCrons,
28072
29235
  applyFarmWorkflowVercelCrons: () => applyFarmWorkflowVercelCrons,
@@ -28084,6 +29247,7 @@ __export(src_exports, {
28084
29247
  buildFarmRoutePath: () => buildFarmRoutePath,
28085
29248
  collectSSGPages: () => collectSSGPages,
28086
29249
  completeFarmServerQueryAction: () => completeFarmServerQueryAction,
29250
+ configureFarmCache: () => configureFarmCache,
28087
29251
  configureFarmObservability: () => configureFarmObservability,
28088
29252
  cookies: () => cookies,
28089
29253
  createAPIClient: () => createAPIClient,
@@ -28183,6 +29347,7 @@ __export(src_exports, {
28183
29347
  generateFarmTypeArtifacts: () => generateFarmTypeArtifacts,
28184
29348
  generateRouteTypes: () => generateRouteTypes,
28185
29349
  generateSSGManifest: () => generateSSGManifest,
29350
+ getAPIRouteRefMetadata: () => getAPIRouteRefMetadata,
28186
29351
  getCurrentRequest: () => getCurrentRequest,
28187
29352
  getDeployTargetForPreset: () => getDeployTargetForPreset,
28188
29353
  getEnv: () => getEnv,
@@ -28242,6 +29407,7 @@ __export(src_exports, {
28242
29407
  isCronRequestAuthorized: () => isCronRequestAuthorized,
28243
29408
  isDeferred: () => isDeferred,
28244
29409
  isEndpointFailure: () => isEndpointFailure,
29410
+ isFarmAPIStream: () => isFarmAPIStream,
28245
29411
  isFarmDeploymentMismatchResponse: () => isFarmDeploymentMismatchResponse,
28246
29412
  isFarmDocsAPIRequest: () => isFarmDocsAPIRequest,
28247
29413
  isFarmDocsRequest: () => isFarmDocsRequest,
@@ -28250,10 +29416,13 @@ __export(src_exports, {
28250
29416
  isFarmNotFoundError: () => isFarmNotFoundError,
28251
29417
  isFarmRedirectError: () => isFarmRedirectError,
28252
29418
  isFarmRouteActive: () => isFarmRouteActive,
29419
+ isJSONStreamResponse: () => isJSONStreamResponse,
29420
+ isMultipartSchema: () => isMultipartSchema,
28253
29421
  isProgrammaticRouteManifest: () => isProgrammaticRouteManifest,
28254
29422
  isProgrammaticRoutesFileName: () => isProgrammaticRoutesFileName,
28255
29423
  isSSGModule: () => isSSGModule,
28256
29424
  isWebResponse: () => isWebResponse2,
29425
+ jsonStream: () => jsonStream,
28257
29426
  layout: () => layout,
28258
29427
  libsqlStorage: () => libsqlStorage,
28259
29428
  loadConfig: () => loadConfig,
@@ -28273,6 +29442,7 @@ __export(src_exports, {
28273
29442
  mergeScheduledTasks: () => mergeScheduledTasks,
28274
29443
  middleware: () => middleware,
28275
29444
  mongodbStorage: () => mongodbStorage,
29445
+ multipart: () => multipart,
28276
29446
  mysql2Storage: () => mysql2Storage,
28277
29447
  mysqlStorage: () => mysqlStorage,
28278
29448
  navigateTo: () => navigateTo,
@@ -28309,6 +29479,7 @@ __export(src_exports, {
28309
29479
  publicEnv: () => publicEnv,
28310
29480
  pushState: () => pushState,
28311
29481
  readDeferredDataResponse: () => readDeferredDataResponse,
29482
+ readJSONStream: () => readJSONStream,
28312
29483
  readPageState: () => readPageState,
28313
29484
  redirect: () => redirect2,
28314
29485
  redisStorage: () => redisStorage,
@@ -28353,13 +29524,16 @@ __export(src_exports, {
28353
29524
  setEnv: () => setEnv,
28354
29525
  snapshotDeferredData: () => snapshotDeferredData,
28355
29526
  sqliteStorage: () => sqliteStorage,
29527
+ storageCacheAdapter: () => storageCacheAdapter,
28356
29528
  titleFromMarkdown: () => titleFromMarkdown,
29529
+ toFormData: () => toFormData,
28357
29530
  toViteModuleId: () => toViteModuleId,
28358
29531
  unstable_cache: () => unstable_cache,
28359
29532
  unwrapMiddleware: () => unwrapMiddleware,
28360
29533
  updateTag: () => updateTag,
28361
29534
  upstashStorage: () => upstashStorage,
28362
29535
  useBlocker: () => useBlocker,
29536
+ useFetcher: () => useFetcher,
28363
29537
  useMutation: () => useMutation,
28364
29538
  useNavigation: () => useNavigation,
28365
29539
  usePageState: () => usePageState,
@@ -29540,7 +30714,9 @@ __name(normalizeFarmClientCacheKey, "normalizeFarmClientCacheKey");
29540
30714
 
29541
30715
  // src/api/client.ts
29542
30716
  init_cache_invalidation();
30717
+ init_transport();
29543
30718
  var FARM_API_ROUTE_REF_SYMBOL = /* @__PURE__ */ Symbol.for("farm.api.route-ref");
30719
+ var FARM_API_ROUTE_META_SYMBOL = /* @__PURE__ */ Symbol.for("farm.api.route-meta");
29544
30720
  var _APIClientError = class _APIClientError extends Error {
29545
30721
  constructor(code, data, options) {
29546
30722
  super(options.message);
@@ -29578,16 +30754,22 @@ function createAPIClient(options = {}) {
29578
30754
  }
29579
30755
  });
29580
30756
  }
30757
+ const headers2 = {
30758
+ "Content-Type": "application/json",
30759
+ ...options.headers,
30760
+ ...requestOptions.headers
30761
+ };
29581
30762
  const fetchOptions = {
29582
30763
  method: requestOptions.method || "GET",
29583
- headers: {
29584
- "Content-Type": "application/json",
29585
- ...options.headers,
29586
- ...requestOptions.headers
29587
- }
30764
+ headers: headers2
29588
30765
  };
29589
- if (requestOptions.body) {
29590
- fetchOptions.body = JSON.stringify(requestOptions.body);
30766
+ if (requestOptions.body !== void 0) {
30767
+ if (isFormData(requestOptions.body)) {
30768
+ deleteHeader(headers2, "content-type");
30769
+ fetchOptions.body = requestOptions.body;
30770
+ } else {
30771
+ fetchOptions.body = JSON.stringify(requestOptions.body);
30772
+ }
29591
30773
  }
29592
30774
  const response = await fetch(url.toString(), fetchOptions);
29593
30775
  applyFarmCacheInvalidations(
@@ -29595,7 +30777,7 @@ function createAPIClient(options = {}) {
29595
30777
  );
29596
30778
  let data = void 0;
29597
30779
  if (response.status !== 204 && response.status !== 205) {
29598
- data = await response.json();
30780
+ data = isJSONStreamResponse(response) ? readJSONStream(response) : await response.json();
29599
30781
  }
29600
30782
  return { response, data };
29601
30783
  }, "fetchClient");
@@ -29741,16 +30923,16 @@ function createAPIClient(options = {}) {
29741
30923
  }
29742
30924
  }
29743
30925
  attempt += 1;
29744
- const delay = typeof clientOptions?.retry?.delay === "function" ? clientOptions.retry.delay(attempt) : clientOptions?.retry?.delay ?? 0;
29745
- if (delay > 0) {
29746
- await new Promise((resolve5) => setTimeout(resolve5, delay));
30926
+ const delay2 = typeof clientOptions?.retry?.delay === "function" ? clientOptions.retry.delay(attempt) : clientOptions?.retry?.delay ?? 0;
30927
+ if (delay2 > 0) {
30928
+ await new Promise((resolve5) => setTimeout(resolve5, delay2));
29747
30929
  }
29748
30930
  }
29749
30931
  })();
29750
30932
  inflightState.set(cacheKey, { promise, startedAt: now2 });
29751
30933
  try {
29752
30934
  const result2 = await promise;
29753
- if (!result2.error && isCacheEnabled) {
30935
+ if (!result2.error && isCacheEnabled && !isFarmAPIStream(result2.data)) {
29754
30936
  const updatedAt = Date.now();
29755
30937
  cacheState.set(cacheKey, {
29756
30938
  data: result2.data,
@@ -29823,10 +31005,17 @@ function createAPIClient(options = {}) {
29823
31005
  clientOptions?.onSettled?.(result.data, result.error);
29824
31006
  return result;
29825
31007
  }, "request");
29826
- return createNestedProxy([], request, routeMeta, baseURL, rootAliases);
31008
+ return createNestedProxy(
31009
+ [],
31010
+ request,
31011
+ routeMeta,
31012
+ baseURL,
31013
+ options.baseURL === void 0,
31014
+ rootAliases
31015
+ );
29827
31016
  }
29828
31017
  __name(createAPIClient, "createAPIClient");
29829
- function createNestedProxy(path28, client, routeMeta, baseURL, rootAliases) {
31018
+ function createNestedProxy(path28, client, routeMeta, baseURL, sameOrigin, rootAliases) {
29830
31019
  const target = /* @__PURE__ */ __name(() => {
29831
31020
  }, "target");
29832
31021
  const proxy = new Proxy(target, {
@@ -29835,13 +31024,29 @@ function createNestedProxy(path28, client, routeMeta, baseURL, rootAliases) {
29835
31024
  if (prop === FARM_API_ROUTE_REF_SYMBOL) {
29836
31025
  return path28.length > 0;
29837
31026
  }
31027
+ if (prop === FARM_API_ROUTE_META_SYMBOL) {
31028
+ const metadata = resolveRouteMeta({ path: path28, baseURL });
31029
+ return Object.freeze({
31030
+ path: metadata.routePath,
31031
+ method: metadata.method,
31032
+ baseURL,
31033
+ sameOrigin
31034
+ });
31035
+ }
29838
31036
  if (path28.length === 0 && typeof prop === "string" && rootAliases && prop in rootAliases) {
29839
31037
  return rootAliases[prop];
29840
31038
  }
29841
31039
  if (typeof prop !== "string") {
29842
31040
  return Reflect.get(_target, prop);
29843
31041
  }
29844
- return createNestedProxy([...path28, prop], client, routeMeta, baseURL, rootAliases);
31042
+ return createNestedProxy(
31043
+ [...path28, prop],
31044
+ client,
31045
+ routeMeta,
31046
+ baseURL,
31047
+ sameOrigin,
31048
+ rootAliases
31049
+ );
29845
31050
  },
29846
31051
  // When calling as a function
29847
31052
  apply(_target, _thisArg, args) {
@@ -29867,6 +31072,22 @@ function isAPIRouteRef(value) {
29867
31072
  return typeof value === "function" && value[FARM_API_ROUTE_REF_SYMBOL] === true;
29868
31073
  }
29869
31074
  __name(isAPIRouteRef, "isAPIRouteRef");
31075
+ function getAPIRouteRefMetadata(value) {
31076
+ if (!isAPIRouteRef(value)) return null;
31077
+ const metadata = value[FARM_API_ROUTE_META_SYMBOL];
31078
+ if (!metadata || typeof metadata !== "object") return null;
31079
+ const candidate = metadata;
31080
+ if (typeof candidate.path !== "string" || typeof candidate.method !== "string" || typeof candidate.baseURL !== "string" || typeof candidate.sameOrigin !== "boolean") {
31081
+ return null;
31082
+ }
31083
+ return {
31084
+ path: candidate.path,
31085
+ method: candidate.method,
31086
+ baseURL: candidate.baseURL,
31087
+ sameOrigin: candidate.sameOrigin
31088
+ };
31089
+ }
31090
+ __name(getAPIRouteRefMetadata, "getAPIRouteRefMetadata");
29870
31091
  function createServerAPIClient(endpoints, options = {}) {
29871
31092
  if (options.integrations === false || Object.prototype.hasOwnProperty.call(endpoints, "integrations")) {
29872
31093
  return endpoints;
@@ -29971,6 +31192,17 @@ function normalizeError(error) {
29971
31192
  return normalized;
29972
31193
  }
29973
31194
  __name(normalizeError, "normalizeError");
31195
+ function isFormData(value) {
31196
+ return typeof value === "object" && value !== null && (typeof FormData !== "undefined" && value instanceof FormData || Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function");
31197
+ }
31198
+ __name(isFormData, "isFormData");
31199
+ function deleteHeader(headers2, name) {
31200
+ const normalized = name.toLowerCase();
31201
+ for (const key of Object.keys(headers2)) {
31202
+ if (key.toLowerCase() === normalized) delete headers2[key];
31203
+ }
31204
+ }
31205
+ __name(deleteHeader, "deleteHeader");
29974
31206
  function createResponseError2(response, data) {
29975
31207
  const expected = readEndpointErrorEnvelope(data);
29976
31208
  if (expected) {
@@ -30002,6 +31234,9 @@ function readEndpointErrorEnvelope(data) {
30002
31234
  }
30003
31235
  __name(readEndpointErrorEnvelope, "readEndpointErrorEnvelope");
30004
31236
 
31237
+ // src/api/index.ts
31238
+ init_transport();
31239
+
30005
31240
  // src/api/vite-plugin.ts
30006
31241
  init_route_manager2();
30007
31242
  init_response();
@@ -31728,6 +32963,7 @@ init_image_types();
31728
32963
  // src/server-fn.ts
31729
32964
  init_server_action_security();
31730
32965
  init_request_bridge();
32966
+ init_cache();
31731
32967
  var FARM_SERVER_FN_SYMBOL = /* @__PURE__ */ Symbol.for("farm.server-fn");
31732
32968
  var UNSAFE_FORM_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
31733
32969
  function createServerMiddleware(options) {
@@ -31751,8 +32987,8 @@ function createServerFn(options) {
31751
32987
  }
31752
32988
  const middleware2 = resolveServerFnMiddleware(options.middleware);
31753
32989
  const serverFn = /* @__PURE__ */ __name(async (value) => {
31754
- const formData = isFormData(value) ? value : void 0;
31755
- const rawInput = formData ? formDataToObject(formData) : value;
32990
+ const formData = isFormData2(value) ? value : void 0;
32991
+ const rawInput = formData ? formDataToObject2(formData) : value;
31756
32992
  const input = await _parseServerFnSchema(options.input, rawInput, "input");
31757
32993
  const executionContext = getServerActionExecutionContext();
31758
32994
  const request = executionContext?.request ?? _resolveCurrentRequest();
@@ -31764,8 +33000,21 @@ function createServerFn(options) {
31764
33000
  request,
31765
33001
  signal
31766
33002
  };
31767
- const result = await runServerFnMiddleware(middleware2, handlerContext, options.handler);
31768
- return _parseServerFnSchema(options.output, result, "output");
33003
+ let resolvedContext = Object.freeze(/* @__PURE__ */ Object.create(null));
33004
+ const result = await runServerFnMiddleware(middleware2, handlerContext, async (context) => {
33005
+ resolvedContext = context.context;
33006
+ return options.handler(context);
33007
+ });
33008
+ const parsedResult = await _parseServerFnSchema(options.output, result, "output");
33009
+ if (options.invalidates) {
33010
+ const declaration = typeof options.invalidates === "function" ? await options.invalidates({
33011
+ ...handlerContext,
33012
+ context: resolvedContext,
33013
+ result: parsedResult
33014
+ }) : options.invalidates;
33015
+ await applyFarmCacheInvalidationTargets(declaration);
33016
+ }
33017
+ return parsedResult;
31769
33018
  }, "serverFn");
31770
33019
  Object.defineProperties(serverFn, {
31771
33020
  [FARM_SERVER_FN_SYMBOL]: {
@@ -31787,6 +33036,10 @@ function createServerFn(options) {
31787
33036
  __farmServerFnMiddleware: {
31788
33037
  value: middleware2,
31789
33038
  enumerable: false
33039
+ },
33040
+ __farmServerFnInvalidates: {
33041
+ value: options.invalidates,
33042
+ enumerable: false
31790
33043
  }
31791
33044
  });
31792
33045
  return serverFn;
@@ -31884,7 +33137,7 @@ function unwrapSafeParseResult(result) {
31884
33137
  return result;
31885
33138
  }
31886
33139
  __name(unwrapSafeParseResult, "unwrapSafeParseResult");
31887
- function formDataToObject(formData) {
33140
+ function formDataToObject2(formData) {
31888
33141
  const output = /* @__PURE__ */ Object.create(null);
31889
33142
  for (const [key, value] of formData.entries()) {
31890
33143
  if (!isSafeFormKey(key)) continue;
@@ -31899,19 +33152,19 @@ function formDataToObject(formData) {
31899
33152
  }
31900
33153
  return output;
31901
33154
  }
31902
- __name(formDataToObject, "formDataToObject");
33155
+ __name(formDataToObject2, "formDataToObject");
31903
33156
  function isSafeFormKey(key) {
31904
33157
  return !key.startsWith("$ACTION_") && !UNSAFE_FORM_KEYS.has(key);
31905
33158
  }
31906
33159
  __name(isSafeFormKey, "isSafeFormKey");
31907
- function isFormData(value) {
33160
+ function isFormData2(value) {
31908
33161
  if (!value || typeof value !== "object") return false;
31909
33162
  if (typeof FormData !== "undefined" && value instanceof FormData) {
31910
33163
  return true;
31911
33164
  }
31912
33165
  return Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function";
31913
33166
  }
31914
- __name(isFormData, "isFormData");
33167
+ __name(isFormData2, "isFormData");
31915
33168
 
31916
33169
  // src/server-fn-client.ts
31917
33170
  var import_react7 = require("react");
@@ -31946,7 +33199,7 @@ function useServerFn(serverFn, options = {}) {
31946
33199
  const submit = (0, import_react7.useCallback)(
31947
33200
  async (input) => {
31948
33201
  const requestId = ++requestIdRef.current;
31949
- const formData = isFormData2(input) ? input : void 0;
33202
+ const formData = isFormData3(input) ? input : void 0;
31950
33203
  const previousResult = stateRef.current.result;
31951
33204
  const optimisticResult = options.optimistic?.({
31952
33205
  input,
@@ -32054,14 +33307,14 @@ function normalizeServerFnError(error) {
32054
33307
  return normalized;
32055
33308
  }
32056
33309
  __name(normalizeServerFnError, "normalizeServerFnError");
32057
- function isFormData2(value) {
33310
+ function isFormData3(value) {
32058
33311
  if (!value || typeof value !== "object") return false;
32059
33312
  if (typeof FormData !== "undefined" && value instanceof FormData) {
32060
33313
  return true;
32061
33314
  }
32062
33315
  return Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function";
32063
33316
  }
32064
- __name(isFormData2, "isFormData");
33317
+ __name(isFormData3, "isFormData");
32065
33318
 
32066
33319
  // src/server-query.ts
32067
33320
  init_cache();
@@ -32121,7 +33374,7 @@ function createServerQuery(options) {
32121
33374
  tags: [createRouteDataCacheTag(routeKey)],
32122
33375
  revalidate: staleTime === false ? false : Math.max(1, Math.ceil(staleTime / 1e3))
32123
33376
  });
32124
- updatedAt = cache.getEntry(cacheKey, { allowStale: true })?.createdAt ?? Date.now();
33377
+ updatedAt = (await cache.getEntryAsync(cacheKey, { allowStale: true }))?.createdAt ?? Date.now();
32125
33378
  }
32126
33379
  return createFarmServerQueryResult(data, {
32127
33380
  key: clientKey,
@@ -33151,6 +34404,18 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
33151
34404
  ...isFarmMarkdownPageFile(entry.modulePath) ? { source: (0, import_fs5.readFileSync)(entry.modulePath, "utf8") } : {}
33152
34405
  });
33153
34406
  }
34407
+ const routeSlots = Array.from(
34408
+ routeManager.getRouteSlots().values(),
34409
+ (entry) => ({
34410
+ name: entry.name,
34411
+ ownerPattern: entry.ownerPattern,
34412
+ pattern: entry.pattern,
34413
+ modulePath: entry.modulePath,
34414
+ containerId: entry.containerId,
34415
+ interception: entry.interception,
34416
+ fallback: entry.fallback
34417
+ })
34418
+ );
33154
34419
  logger.info(`\u{1F4CB} Found ${pageRoutes.length} page routes`);
33155
34420
  const fs9 = await import("fs/promises");
33156
34421
  const layoutRoutes = [];
@@ -33194,7 +34459,16 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
33194
34459
  logger.info("\u{1F4E6} Building client and SSR bundles in parallel...");
33195
34460
  const [clientBuildResult, ssrBuildResult] = await Promise.allSettled([
33196
34461
  // Client build (to disk)
33197
- buildClient(productionVite, config, root, srcDir, clientOutputDir, pageRoutes, layoutRoutes),
34462
+ buildClient(
34463
+ productionVite,
34464
+ config,
34465
+ root,
34466
+ srcDir,
34467
+ clientOutputDir,
34468
+ pageRoutes,
34469
+ layoutRoutes,
34470
+ routeSlots
34471
+ ),
33198
34472
  // SSR build (in memory)
33199
34473
  buildSSRInMemory(
33200
34474
  productionVite,
@@ -33205,7 +34479,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
33205
34479
  serverRenderer,
33206
34480
  preset,
33207
34481
  pageRoutes,
33208
- layoutRoutes
34482
+ layoutRoutes,
34483
+ routeSlots
33209
34484
  )
33210
34485
  ]);
33211
34486
  const [routeRuntimeManifestResult] = await routeRuntimeManifestResultPromise;
@@ -33225,7 +34500,8 @@ async function buildUniversal(config, routeManager, apiRouteManager, serverRende
33225
34500
  srcDir,
33226
34501
  clientOutputDir,
33227
34502
  pageRoutes,
33228
- layoutRoutes
34503
+ layoutRoutes,
34504
+ routeSlots
33229
34505
  );
33230
34506
  }
33231
34507
  const ssrResult = ssrBuildResult.value;
@@ -33328,7 +34604,7 @@ async function validateClientBuildOutput(root, srcDir, outputDir) {
33328
34604
  }
33329
34605
  }
33330
34606
  __name(validateClientBuildOutput, "validateClientBuildOutput");
33331
- async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = []) {
34607
+ async function buildClient(productionVite, config, root, srcDir, outputDir, pageRoutes, layoutRoutes = [], routeSlots = []) {
33332
34608
  const viteBuild = productionVite.build;
33333
34609
  const { farmPlugin: farmPlugin2 } = await Promise.resolve().then(() => (init_vite(), vite_exports));
33334
34610
  const { PluginManager: PluginManager2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
@@ -33355,8 +34631,16 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
33355
34631
  logger.warn(`\u26A0\uFE0F Could not inspect route file ${route2.modulePath}: ${error}`);
33356
34632
  }
33357
34633
  }
34634
+ const clientRouteSlots = routeSlots.filter((slot) => {
34635
+ try {
34636
+ return getClientModuleMetadata(slot.modulePath, root).shouldHydrate;
34637
+ } catch (error) {
34638
+ logger.warn(`\u26A0\uFE0F Could not inspect route slot ${slot.modulePath}: ${error}`);
34639
+ return false;
34640
+ }
34641
+ });
33358
34642
  logger.info(
33359
- `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} out of ${pageRoutes.length} pages`
34643
+ `\u{1F4F1} Total hydratable routes detected: ${clientPages.length} pages and ${clientRouteSlots.length} slots`
33360
34644
  );
33361
34645
  const clientEntryRoot = import_path12.default.join(root, ".farm", "tmp");
33362
34646
  await fs9.mkdir(clientEntryRoot, { recursive: true });
@@ -33365,6 +34649,7 @@ async function buildClient(productionVite, config, root, srcDir, outputDir, page
33365
34649
  const clientHydrationCode = generateClientHydrationEntry(
33366
34650
  clientPages,
33367
34651
  layoutRoutes,
34652
+ clientRouteSlots,
33368
34653
  root,
33369
34654
  srcDir,
33370
34655
  isFarmDocsSearchEnabled(config.docs),
@@ -33697,7 +34982,7 @@ function generateUniversalRouterStateProperties() {
33697
34982
  `.trim();
33698
34983
  }
33699
34984
  __name(generateUniversalRouterStateProperties, "generateUniversalRouterStateProperties");
33700
- function generateClientHydrationEntry(clientPages, layoutRoutes, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
34985
+ function generateClientHydrationEntry(clientPages, layoutRoutes, clientRouteSlots, root, srcDir, docsSearchEnabled, docsSearchModuleId, i18nConfig = {
33701
34986
  enabled: false,
33702
34987
  locales: ["en"],
33703
34988
  defaultLocale: "en",
@@ -33765,7 +35050,7 @@ function isFarmLocaleDocumentChange() {
33765
35050
  return false;
33766
35051
  }
33767
35052
  `;
33768
- if (clientPages.length === 0) {
35053
+ if (clientPages.length === 0 && clientRouteSlots.length === 0) {
33769
35054
  return `
33770
35055
  // Farm.js Client Runtime (no client components)
33771
35056
  ${cssImport}
@@ -34015,11 +35300,25 @@ document.addEventListener("click", function(e) {
34015
35300
  }
34016
35301
  const imports = [];
34017
35302
  const routeEntries = [];
35303
+ const routeSlotEntries = [];
34018
35304
  clientPages.forEach((page2, index) => {
34019
35305
  const importPath = toImportPath(page2.modulePath);
34020
35306
  imports.push(`import Page${index} from "${importPath}";`);
34021
35307
  routeEntries.push(` { pattern: ${JSON.stringify(page2.pattern)}, Component: Page${index} }`);
34022
35308
  });
35309
+ clientRouteSlots.forEach((slot, index) => {
35310
+ const importPath = toImportPath(slot.modulePath);
35311
+ imports.push(`import RouteSlot${index} from "${importPath}";`);
35312
+ routeSlotEntries.push(` {
35313
+ name: ${JSON.stringify(slot.name)},
35314
+ ownerPattern: ${JSON.stringify(slot.ownerPattern)},
35315
+ pattern: ${JSON.stringify(slot.pattern)},
35316
+ containerId: ${JSON.stringify(slot.containerId)},
35317
+ interception: ${JSON.stringify(slot.interception)},
35318
+ fallback: ${JSON.stringify(slot.fallback)},
35319
+ Component: RouteSlot${index},
35320
+ }`);
35321
+ });
34023
35322
  return `
34024
35323
  // Farm.js Client Runtime - SPA with Hydration
34025
35324
  ${cssImport}
@@ -34041,6 +35340,10 @@ const clientRoutes = [
34041
35340
  ${routeEntries.join(",\n")}
34042
35341
  ];
34043
35342
 
35343
+ const clientRouteSlots = [
35344
+ ${routeSlotEntries.join(",\n")}
35345
+ ];
35346
+
34044
35347
  // Layout routes for wrapping client components
34045
35348
  const layoutRoutes = [
34046
35349
  ${layoutRegistrations.join(",\n")}
@@ -34095,6 +35398,146 @@ function matchRoute(pathname) {
34095
35398
  return null;
34096
35399
  }
34097
35400
 
35401
+ function matchesRoutePrefix(pathname, pattern) {
35402
+ if (pattern === "/") return true;
35403
+ const pathSegments = getFarmRoutePathname(pathname).split("/").filter(Boolean);
35404
+ const patternSegments = pattern.split("/").filter(Boolean);
35405
+ if (patternSegments.length > pathSegments.length) return false;
35406
+ const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
35407
+ return matchFarmRoute(pattern, candidate) !== null;
35408
+ }
35409
+
35410
+ function matchInterceptedRouteSlot(pathname, from) {
35411
+ for (const slot of clientRouteSlots) {
35412
+ if (!slot.interception || !matchesRoutePrefix(from, slot.ownerPattern)) continue;
35413
+ const params = matchFarmRoute(slot.pattern, getFarmRoutePathname(pathname));
35414
+ if (params !== null) return { slot: slot, params: params };
35415
+ }
35416
+ return null;
35417
+ }
35418
+
35419
+ function routeSlotKey(slot) {
35420
+ return slot.ownerPattern + ":" + slot.name;
35421
+ }
35422
+
35423
+ function findClientRouteSlot(slot) {
35424
+ return clientRouteSlots.find(function(candidate) {
35425
+ return candidate.name === slot.name &&
35426
+ candidate.ownerPattern === slot.ownerPattern &&
35427
+ candidate.pattern === slot.pattern &&
35428
+ candidate.interception === slot.interception &&
35429
+ candidate.fallback === slot.fallback;
35430
+ });
35431
+ }
35432
+
35433
+ function readRouteSlotPayload(doc) {
35434
+ const script = doc.getElementById("__farm_route_slots_data__");
35435
+ if (!script?.textContent) return [];
35436
+ try {
35437
+ const parsed = JSON.parse(script.textContent);
35438
+ return Array.isArray(parsed) ? parsed : [];
35439
+ } catch {
35440
+ return [];
35441
+ }
35442
+ }
35443
+
35444
+ const routeSlotRoots = new Map();
35445
+ let activeRouteInterception = null;
35446
+
35447
+ function resetRouteSlotRoots() {
35448
+ for (const root of routeSlotRoots.values()) {
35449
+ try { root.unmount(); } catch {}
35450
+ }
35451
+ routeSlotRoots.clear();
35452
+ activeRouteInterception = null;
35453
+ }
35454
+
35455
+ function renderClientRouteSlot(slot, registration, mode) {
35456
+ const container = document.getElementById(slot.containerId);
35457
+ if (!container || !registration?.Component) return false;
35458
+ const key = routeSlotKey(slot);
35459
+ const existingRoot = routeSlotRoots.get(key);
35460
+ const props = slot.props && typeof slot.props === "object" ? slot.props : {};
35461
+ const element = React.createElement(registration.Component, props);
35462
+
35463
+ if (mode === "hydrate") {
35464
+ if (existingRoot) return true;
35465
+ const root = hydrateRoot(container, element);
35466
+ routeSlotRoots.set(key, root);
35467
+ return true;
35468
+ }
35469
+
35470
+ if (existingRoot) {
35471
+ try { existingRoot.unmount(); } catch {}
35472
+ routeSlotRoots.delete(key);
35473
+ } else {
35474
+ container.replaceChildren();
35475
+ }
35476
+ const root = createRoot(container);
35477
+ root.render(element);
35478
+ routeSlotRoots.set(key, root);
35479
+ return true;
35480
+ }
35481
+
35482
+ function hydrateInitialRouteSlots() {
35483
+ const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
35484
+ ? window.__FARM_ROUTE_SLOTS__
35485
+ : [];
35486
+ for (const slot of slots) {
35487
+ const registration = findClientRouteSlot(slot);
35488
+ if (!registration) continue;
35489
+ try {
35490
+ renderClientRouteSlot(slot, registration, "hydrate");
35491
+ } catch (error) {
35492
+ console.warn("[Farm.js] Could not hydrate route slot:", slot.name, error);
35493
+ }
35494
+ }
35495
+ }
35496
+
35497
+ function renderRouteInterception(slot, registration, from) {
35498
+ const container = document.getElementById(slot.containerId);
35499
+ if (!container) return false;
35500
+ const key = routeSlotKey(slot);
35501
+ const previousSlot = (window.__FARM_ROUTE_SLOTS__ || []).find(function(candidate) {
35502
+ return routeSlotKey(candidate) === key;
35503
+ }) || null;
35504
+ const previousHtml = container.innerHTML;
35505
+
35506
+ if (!renderClientRouteSlot(slot, registration, "render")) return false;
35507
+ activeRouteInterception = {
35508
+ from: from,
35509
+ key: key,
35510
+ slot: slot,
35511
+ previousSlot: previousSlot,
35512
+ previousHtml: previousHtml,
35513
+ };
35514
+ return true;
35515
+ }
35516
+
35517
+ function clearRouteInterception(destination) {
35518
+ if (!activeRouteInterception) return false;
35519
+ const active = activeRouteInterception;
35520
+ activeRouteInterception = null;
35521
+ const root = routeSlotRoots.get(active.key);
35522
+ if (root) {
35523
+ try { root.unmount(); } catch {}
35524
+ routeSlotRoots.delete(active.key);
35525
+ }
35526
+ const container = document.getElementById(active.slot.containerId);
35527
+ if (container) {
35528
+ container.innerHTML = active.previousHtml;
35529
+ if (active.previousSlot) {
35530
+ const registration = findClientRouteSlot(active.previousSlot);
35531
+ if (registration) {
35532
+ try {
35533
+ renderClientRouteSlot(active.previousSlot, registration, "hydrate");
35534
+ } catch {}
35535
+ }
35536
+ }
35537
+ }
35538
+ return destination === active.from;
35539
+ }
35540
+
34098
35541
  // State
34099
35542
  let reactRoot = null;
34100
35543
  let currentPathname = null;
@@ -34113,12 +35556,17 @@ function resetReactRoot() {
34113
35556
  async function hydrate() {
34114
35557
  const pathname = window.location.pathname;
34115
35558
  const matched = matchRoute(pathname);
34116
-
35559
+ hydrateInitialRouteSlots();
35560
+
34117
35561
  if (!matched) {
34118
35562
  return;
34119
35563
  }
34120
35564
 
34121
- const container = document.getElementById("root");
35565
+ const hasRouteSlots =
35566
+ Array.isArray(window.__FARM_ROUTE_SLOTS__) && window.__FARM_ROUTE_SLOTS__.length > 0;
35567
+ const container =
35568
+ (hasRouteSlots ? document.getElementById("__farm_page__") : null) ||
35569
+ document.getElementById("root");
34122
35570
  if (!container) {
34123
35571
  console.error("[Farm.js] No root element found");
34124
35572
  return;
@@ -34132,7 +35580,9 @@ async function hydrate() {
34132
35580
 
34133
35581
  // Create page element and wrap with layouts
34134
35582
  const pageElement = React.createElement(Component, props);
34135
- const wrappedElement = wrapWithLayouts(pageElement, pathname, params);
35583
+ const wrappedElement = hasRouteSlots
35584
+ ? pageElement
35585
+ : wrapWithLayouts(pageElement, pathname, params);
34136
35586
 
34137
35587
  const shouldHydrate = !isHydrated && Boolean(container.innerHTML.trim());
34138
35588
  const hydrationSession = await farmClientRuntime.beginHydration({
@@ -34197,6 +35647,57 @@ ${generateUniversalRouterStateProperties()}
34197
35647
  : undefined,
34198
35648
  });
34199
35649
 
35650
+ if (activeRouteInterception && clearRouteInterception(to)) {
35651
+ await farmClientRuntime.markNavigationLoaded(clientNavigation, {
35652
+ routeSlots: "restored",
35653
+ });
35654
+ await farmClientRuntime.resolveNavigation(clientNavigation);
35655
+ void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
35656
+ this.currentPath = to;
35657
+ this.finishNavigation();
35658
+ return;
35659
+ }
35660
+ if (activeRouteInterception) {
35661
+ clearRouteInterception(to);
35662
+ }
35663
+
35664
+ const intercepted = matchInterceptedRouteSlot(pathname, from);
35665
+ if (intercepted) {
35666
+ const html = await this.fetchPage(to, from);
35667
+ const doc = new DOMParser().parseFromString(html, "text/html");
35668
+ const slotPayload = readRouteSlotPayload(doc);
35669
+ const selectedSlot = slotPayload.find(function(slot) {
35670
+ return slot.interception &&
35671
+ slot.name === intercepted.slot.name &&
35672
+ slot.ownerPattern === intercepted.slot.ownerPattern;
35673
+ });
35674
+
35675
+ if (
35676
+ selectedSlot &&
35677
+ renderRouteInterception(selectedSlot, intercepted.slot, from)
35678
+ ) {
35679
+ await farmClientRuntime.markNavigationLoaded(clientNavigation, {
35680
+ route: intercepted.slot.pattern,
35681
+ params: intercepted.params,
35682
+ });
35683
+ const historyState = createHistoryState(
35684
+ to,
35685
+ options.state,
35686
+ window.history.state,
35687
+ );
35688
+ if (action === "replace") {
35689
+ window.history.replaceState(historyState, "", url);
35690
+ } else if (action !== "pop") {
35691
+ window.history.pushState(historyState, "", url);
35692
+ }
35693
+ await farmClientRuntime.resolveNavigation(clientNavigation);
35694
+ void farmClientRuntime.scheduleNavigationRendered(clientNavigation);
35695
+ this.currentPath = to;
35696
+ this.finishNavigation();
35697
+ return;
35698
+ }
35699
+ }
35700
+
34200
35701
  if (matched) {
34201
35702
  const Component = matched.route.Component;
34202
35703
  const params = matched.params;
@@ -34273,21 +35774,28 @@ ${generateUniversalRouterStateProperties()}
34273
35774
  }
34274
35775
  },
34275
35776
 
34276
- fetchPage: async function(url) {
34277
- const cached = this.prefetchCache.get(url);
35777
+ fetchPage: async function(url, interceptFrom) {
35778
+ const cacheKey = interceptFrom ? url + "\\nintercept:" + interceptFrom : url;
35779
+ const cached = this.prefetchCache.get(cacheKey);
34278
35780
  if (cached) return cached;
34279
35781
 
34280
35782
  const response = await fetch(url, {
34281
- headers: { "Accept": "text/html" }
35783
+ headers: {
35784
+ "Accept": "text/html",
35785
+ ...(interceptFrom ? { "X-Farm-Intercept-From": interceptFrom } : {}),
35786
+ }
34282
35787
  });
34283
35788
  if (!response.ok) throw new Error("Failed to fetch page");
34284
- return response.text();
35789
+ const html = await response.text();
35790
+ this.prefetchCache.set(cacheKey, html);
35791
+ return html;
34285
35792
  },
34286
35793
 
34287
35794
  swapContent: function(html, targetPath) {
34288
35795
  const parser = new DOMParser();
34289
35796
  const doc = parser.parseFromString(html, "text/html");
34290
35797
  if (isFarmLocaleDocumentChange(doc)) return false;
35798
+ const nextRouteSlots = readRouteSlotPayload(doc);
34291
35799
 
34292
35800
  // Update title
34293
35801
  const newTitle = doc.querySelector("title");
@@ -34312,7 +35820,10 @@ ${generateUniversalRouterStateProperties()}
34312
35820
  const currentRoot = document.getElementById("root");
34313
35821
  if (!newRoot || !currentRoot) return this.swapDocument(doc);
34314
35822
  resetReactRoot();
35823
+ resetRouteSlotRoots();
34315
35824
  currentRoot.innerHTML = newRoot.innerHTML;
35825
+ window.__FARM_ROUTE_SLOTS__ = nextRouteSlots;
35826
+ hydrateInitialRouteSlots();
34316
35827
 
34317
35828
  // Check if new page has a client component
34318
35829
  const targetUrl = new URL(targetPath || window.location.href, window.location.origin);
@@ -34324,13 +35835,15 @@ ${generateUniversalRouterStateProperties()}
34324
35835
  const params = matched.params;
34325
35836
  const searchParams = Object.fromEntries(targetUrl.searchParams);
34326
35837
  const props = { params: params, searchParams: Promise.resolve(searchParams) };
34327
-
34328
- if (!reactRoot) {
34329
- reactRoot = createRoot(currentRoot);
34330
- }
34331
35838
  const pageElement = React.createElement(Component, props);
34332
- const wrappedElement = wrapWithLayouts(pageElement, newPathname, params);
34333
- reactRoot.render(wrappedElement);
35839
+ const hasRouteSlots = nextRouteSlots.length > 0;
35840
+ const pageContainer =
35841
+ (hasRouteSlots ? document.getElementById("__farm_page__") : null) || currentRoot;
35842
+ const wrappedElement = hasRouteSlots
35843
+ ? pageElement
35844
+ : wrapWithLayouts(pageElement, newPathname, params);
35845
+ reactRoot = hydrateRoot(pageContainer, wrappedElement);
35846
+ isHydrated = true;
34334
35847
  }
34335
35848
  return true;
34336
35849
  },
@@ -34339,6 +35852,7 @@ ${generateUniversalRouterStateProperties()}
34339
35852
  if (!doc.documentElement || !doc.body) return false;
34340
35853
 
34341
35854
  resetReactRoot();
35855
+ resetRouteSlotRoots();
34342
35856
 
34343
35857
  Array.from(document.documentElement.attributes).forEach(function(attr) {
34344
35858
  if (!doc.documentElement.hasAttribute(attr.name)) {
@@ -34372,10 +35886,12 @@ ${generateUniversalRouterStateProperties()}
34372
35886
  if (url.origin !== window.location.origin) return;
34373
35887
 
34374
35888
  const pathname = url.pathname + url.search;
34375
- if (this.prefetchCache.has(pathname)) return;
35889
+ const interceptFrom = this.currentPath;
35890
+ const cacheKey = pathname + "\\nintercept:" + interceptFrom;
35891
+ if (this.prefetchCache.has(cacheKey)) return;
34376
35892
 
34377
- this.fetchPage(pathname)
34378
- .then(function(html) { spaRouter.prefetchCache.set(pathname, html); })
35893
+ this.fetchPage(pathname, interceptFrom)
35894
+ .then(function(html) { spaRouter.prefetchCache.set(cacheKey, html); })
34379
35895
  .catch(function() {});
34380
35896
  },
34381
35897
 
@@ -34466,7 +35982,7 @@ if (isFarmDocsSearchPage()) {
34466
35982
  `.trim();
34467
35983
  }
34468
35984
  __name(generateClientHydrationEntry, "generateClientHydrationEntry");
34469
- async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes) {
35985
+ async function buildSSRInMemory(productionVite, config, root, routeManager, apiRouteManager, serverRenderer, preset, collectedPageRoutes, collectedLayoutRoutes, collectedRouteSlots) {
34470
35986
  const viteBuild = productionVite.build;
34471
35987
  const { farmPlugin: farmPlugin2 } = await Promise.resolve().then(() => (init_vite(), vite_exports));
34472
35988
  const { PluginManager: PluginManager2 } = await Promise.resolve().then(() => (init_plugin(), plugin_exports));
@@ -34499,6 +36015,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
34499
36015
  let ssrEntryFile;
34500
36016
  const pageRoutes = collectedPageRoutes.map((route2) => ({ ...route2 }));
34501
36017
  const layoutRoutes = collectedLayoutRoutes.map((route2) => ({ ...route2 }));
36018
+ const routeSlots = collectedRouteSlots.map((slot) => ({ ...slot }));
34502
36019
  const metadataImageRoutes = [];
34503
36020
  for (const entry of routeManager.getMetadataImages().values()) {
34504
36021
  if (entry.sourceType === "static") {
@@ -34599,6 +36116,7 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
34599
36116
  apiRoutes,
34600
36117
  pageRoutes,
34601
36118
  layoutRoutes,
36119
+ routeSlots,
34602
36120
  errorRoutes,
34603
36121
  metadataImageRoutes,
34604
36122
  middlewareRoutes,
@@ -34769,10 +36287,14 @@ async function buildSSRInMemory(productionVite, config, root, routeManager, apiR
34769
36287
  }
34770
36288
  }
34771
36289
  }
34772
- return { bundle: ssrBundle, entryFile: ssrEntryFile, configuredHeaderRoutes };
36290
+ return {
36291
+ bundle: ssrBundle,
36292
+ entryFile: ssrEntryFile,
36293
+ configuredHeaderRoutes
36294
+ };
34773
36295
  }
34774
36296
  __name(buildSSRInMemory, "buildSSRInMemory");
34775
- function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
36297
+ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, routeSlots, errorRoutes, metadataImageRoutes, middlewareRoutes, redirectRoutes, configuredRewriteRoutes, configuredHeaderRoutes, notFoundPath, config, configModulePath, hasServerRuntimeIntegrations, hasRuntimeIntegrationConfig, hasConfiguredRuntimePlugins, preset, i18nCatalogs) {
34776
36298
  const hasPluginRuntime = hasRuntimeIntegrationConfig || hasConfiguredRuntimePlugins;
34777
36299
  const hasMiddlewareRuntime = middlewareRoutes.length > 0 || hasFarmMiddlewareConfig(config.middleware);
34778
36300
  const farmDocsBaseConfig = config.docs?.enabled ? { ...config.docs, config: void 0 } : void 0;
@@ -34816,10 +36338,12 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
34816
36338
  return;
34817
36339
  }
34818
36340
  pageImports.push(`import * as ${varName} from "${route2.modulePath}";`);
36341
+ const shouldHydrate = getClientModuleMetadata(route2.modulePath, config.root).shouldHydrate;
34819
36342
  pageRegistrations.push(`
34820
36343
  {
34821
36344
  pattern: ${JSON.stringify(route2.pattern)},
34822
36345
  module: ${varName},
36346
+ shouldHydrate: ${JSON.stringify(shouldHydrate)},
34823
36347
  }`);
34824
36348
  });
34825
36349
  const layoutImports = [];
@@ -34833,6 +36357,22 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
34833
36357
  module: ${varName},
34834
36358
  }`);
34835
36359
  });
36360
+ const routeSlotImports = [];
36361
+ const routeSlotRegistrations = [];
36362
+ routeSlots.forEach((slot, index) => {
36363
+ const varName = `routeSlot${index}`;
36364
+ routeSlotImports.push(`import * as ${varName} from "${slot.modulePath}";`);
36365
+ routeSlotRegistrations.push(`
36366
+ {
36367
+ name: ${JSON.stringify(slot.name)},
36368
+ ownerPattern: ${JSON.stringify(slot.ownerPattern)},
36369
+ pattern: ${JSON.stringify(slot.pattern)},
36370
+ containerId: ${JSON.stringify(slot.containerId)},
36371
+ interception: ${JSON.stringify(slot.interception)},
36372
+ fallback: ${JSON.stringify(slot.fallback)},
36373
+ module: ${varName},
36374
+ }`);
36375
+ });
34836
36376
  const errorImports = [];
34837
36377
  const errorRegistrations = [];
34838
36378
  errorRoutes.forEach((errorRoute, index) => {
@@ -34883,6 +36423,7 @@ function generateVirtualEntryCode(apiRoutes, pageRoutes, layoutRoutes, errorRout
34883
36423
  _runWithMiddlewareData,
34884
36424
  addMetadataImageReference,
34885
36425
  applyProductionMiddlewareHeaders,
36426
+ configureFarmCache,
34886
36427
  configureFarmObservability,
34887
36428
  createFarmCacheKey,
34888
36429
  createFarmLocaleCookie,
@@ -34985,6 +36526,7 @@ async function handleAPIRequest(request) {
34985
36526
  ${apiImports.join("\n")}
34986
36527
  ${pageImports.join("\n")}
34987
36528
  ${layoutImports.join("\n")}
36529
+ ${routeSlotImports.join("\n")}
34988
36530
  ${errorImports.join("\n")}
34989
36531
  ${metadataImageImports.join("\n")}
34990
36532
  ${middlewareImports.join("\n")}
@@ -35062,6 +36604,7 @@ const farmObservabilityConfig = farmUserConfig?.observability ?? ${JSON.stringif
35062
36604
  config.observability ?? false
35063
36605
  )};
35064
36606
  configureFarmObservability(farmObservabilityConfig);
36607
+ configureFarmCache(farmResolvedRuntimeConfig.cache);
35065
36608
  const farmI18nConfig = ${JSON.stringify(config.i18n)};
35066
36609
  const farmI18nRuntime = ${config.i18n.enabled ? `createFarmI18nRuntime(farmI18nConfig, ${JSON.stringify(i18nCatalogs)})` : "null"};
35067
36610
  ${config.i18n.enabled ? "_setDefaultFarmI18nRuntime(farmI18nRuntime);" : ""}
@@ -35119,6 +36662,9 @@ for (const route of pageRoutes) {
35119
36662
  const layoutRoutes = [${layoutRegistrations.join(",")}
35120
36663
  ];
35121
36664
 
36665
+ const routeSlots = [${routeSlotRegistrations.join(",")}
36666
+ ];
36667
+
35122
36668
  // Route-level error boundaries bundled at build time.
35123
36669
  const errorRoutes = [${errorRegistrations.join(",")}
35124
36670
  ];
@@ -35153,18 +36699,21 @@ function serializeFarmInlineValue(value) {
35153
36699
  .replace(/\\u2029/g, "\\\\u2029");
35154
36700
  }
35155
36701
 
35156
- function renderFarmClientBootstrapScript(canonicalPath) {
36702
+ function renderFarmClientBootstrapScript(canonicalPath, selectedRouteSlots) {
35157
36703
  const integrationManifest = ${hasRuntimeIntegrationConfig ? "getRegisteredIntegrationAPIManifest()" : "{}"};
36704
+ const serializedRouteSlots = serializeFarmInlineValue(selectedRouteSlots || []);
35158
36705
  let source = 'window.__FARM_INTEGRATION_API_MANIFEST__=' +
35159
36706
  serializeFarmInlineValue(integrationManifest) +
35160
- ';';
36707
+ ';window.__FARM_ROUTE_SLOTS__=' + serializedRouteSlots + ';';
35161
36708
  if (typeof canonicalPath === "string" && canonicalPath.startsWith("/")) {
35162
36709
  const serializedPath = serializeFarmInlineValue(canonicalPath);
35163
36710
  source += 'if(location.pathname+location.search!==' + serializedPath + '){' +
35164
36711
  'history.replaceState(Object.assign({},history.state||{},{path:' + serializedPath + '}),"",' +
35165
36712
  serializedPath + ');}';
35166
36713
  }
35167
- return '<script>' + source + '</script>';
36714
+ return '<script id="__farm_route_slots_data__" type="application/json">' +
36715
+ serializedRouteSlots +
36716
+ '</script><script>' + source + '</script>';
35168
36717
  }
35169
36718
 
35170
36719
  function escapeFarmHtmlAttribute(value) {
@@ -35914,6 +37463,79 @@ function matchPageRoute(pathname) {
35914
37463
  return null;
35915
37464
  }
35916
37465
 
37466
+ function matchesRoutePrefix(pathname, pattern) {
37467
+ if (pattern === "/") return true;
37468
+ const pathSegments = normalizeRuntimePath(pathname).split("/").filter(Boolean);
37469
+ const patternSegments = normalizeRuntimePath(pattern).split("/").filter(Boolean);
37470
+ if (patternSegments.length > pathSegments.length) return false;
37471
+ const candidate = "/" + pathSegments.slice(0, patternSegments.length).join("/");
37472
+ return matchRuntimePathPattern(pattern, candidate) !== null;
37473
+ }
37474
+
37475
+ function routeSlotSpecificity(slot) {
37476
+ return slot.pattern.split("/").reduce(function(score, segment) {
37477
+ if (!segment) return score;
37478
+ if (segment.startsWith("[[...")) return score + 1;
37479
+ if (segment.startsWith("[...")) return score + 2;
37480
+ if (segment.startsWith("[")) return score + 3;
37481
+ return score + 10;
37482
+ }, 0);
37483
+ }
37484
+
37485
+ function matchRouteSlots(pathname, interceptFrom) {
37486
+ const groups = new Map();
37487
+ for (const slot of routeSlots) {
37488
+ if (!matchesRoutePrefix(pathname, slot.ownerPattern)) continue;
37489
+ const key = slot.ownerPattern + ":" + slot.name;
37490
+ const entries = groups.get(key) || [];
37491
+ entries.push(slot);
37492
+ groups.set(key, entries);
37493
+ }
37494
+
37495
+ const normalizedFrom =
37496
+ typeof interceptFrom === "string" && interceptFrom.startsWith("/")
37497
+ ? new URL(interceptFrom, "http://farm.local").pathname
37498
+ : null;
37499
+ const matches = [];
37500
+
37501
+ for (const entries of groups.values()) {
37502
+ const candidates = entries
37503
+ .filter(function(entry) { return !entry.fallback; })
37504
+ .filter(function(entry) {
37505
+ return !entry.interception ||
37506
+ (normalizedFrom && matchesRoutePrefix(normalizedFrom, entry.ownerPattern));
37507
+ })
37508
+ .map(function(entry) {
37509
+ return {
37510
+ entry: entry,
37511
+ params: matchRuntimePathPattern(entry.pattern, pathname),
37512
+ };
37513
+ })
37514
+ .filter(function(candidate) { return candidate.params !== null; })
37515
+ .sort(function(left, right) {
37516
+ if (left.entry.interception !== right.entry.interception) {
37517
+ return left.entry.interception ? -1 : 1;
37518
+ }
37519
+ return routeSlotSpecificity(right.entry) - routeSlotSpecificity(left.entry);
37520
+ });
37521
+
37522
+ if (candidates[0]) {
37523
+ matches.push({ ...candidates[0].entry, params: candidates[0].params });
37524
+ continue;
37525
+ }
37526
+
37527
+ const fallback = entries.find(function(entry) { return entry.fallback; });
37528
+ if (fallback) matches.push({ ...fallback, params: {} });
37529
+ }
37530
+
37531
+ return matches.sort(function(left, right) {
37532
+ const ownerDepth =
37533
+ left.ownerPattern.split("/").filter(Boolean).length -
37534
+ right.ownerPattern.split("/").filter(Boolean).length;
37535
+ return ownerDepth || left.name.localeCompare(right.name);
37536
+ });
37537
+ }
37538
+
35917
37539
  function hasLocalRequestRoute(request, routePathname) {
35918
37540
  const pathname = new URL(request.url).pathname;
35919
37541
  if (matchLocalAPIRequest(request) || matchLocalIntegrationRequest(request)) {
@@ -36064,6 +37686,7 @@ function getPPRShellBypassReason(request, middlewareData, middlewareContext) {
36064
37686
  if (method !== "GET" && method !== "HEAD") return "method";
36065
37687
  if (request.headers.get("cookie")) return "cookie";
36066
37688
  if (request.headers.get("authorization")) return "authorization";
37689
+ if (request.headers.get("x-farm-intercept-from")) return "route-interception";
36067
37690
  if (request.headers.get("x-farm-ppr-refresh")) return "refresh";
36068
37691
  if (hasConfiguredRouteContext) return "route-context";
36069
37692
  if (middlewareData?.size) return "middleware-data";
@@ -36117,8 +37740,8 @@ function getRouteSharedCacheControl(routeModule, pprCanCache) {
36117
37740
  return "public, s-maxage=" + revalidate + ", stale-while-revalidate=300";
36118
37741
  }
36119
37742
 
36120
- function getCachedPPRShell(cacheKey) {
36121
- const entry = pprShellCache.getEntry(cacheKey);
37743
+ async function getCachedPPRShell(cacheKey) {
37744
+ const entry = await pprShellCache.getEntryAsync(cacheKey);
36122
37745
  if (!entry) {
36123
37746
  return null;
36124
37747
  }
@@ -36333,7 +37956,7 @@ async function handleFarmRequestInContext(
36333
37956
  }
36334
37957
  }
36335
37958
  if (pprCacheKey) {
36336
- const cachedPPRShell = getCachedPPRShell(pprCacheKey);
37959
+ const cachedPPRShell = await getCachedPPRShell(pprCacheKey);
36337
37960
  if (cachedPPRShell) {
36338
37961
  emitFarmEvent({ type: "ppr.shell.hit", route: pathname, key: pprCacheKey });
36339
37962
  emitFarmEvent({
@@ -36361,6 +37984,10 @@ async function handleFarmRequestInContext(
36361
37984
 
36362
37985
  // Get applicable layouts for this page
36363
37986
  const applicableLayouts = getApplicableLayouts(routePathname);
37987
+ const selectedRouteSlots = matchRouteSlots(
37988
+ routePathname,
37989
+ request.headers.get("x-farm-intercept-from"),
37990
+ );
36364
37991
 
36365
37992
  if (PageComponent) {
36366
37993
  // Parse search params - make it a resolved Promise for async components
@@ -36448,6 +38075,82 @@ async function handleFarmRequestInContext(
36448
38075
  throw routeStateError;
36449
38076
  }
36450
38077
  }
38078
+
38079
+ const renderedRouteSlots = await Promise.all(
38080
+ selectedRouteSlots.map(async function(slot) {
38081
+ const slotContext = hasConfiguredRouteContext
38082
+ ? await resolveFarmRouteContext(farmResolvedRuntimeConfig, {
38083
+ request,
38084
+ params: slot.params,
38085
+ search: searchParamsObj,
38086
+ path: pathname,
38087
+ })
38088
+ : undefined;
38089
+ const rawSlotProps = withFarmRouteContext(
38090
+ {
38091
+ params: slot.params,
38092
+ searchParams: Promise.resolve(searchParamsObj),
38093
+ path: pathname,
38094
+ ...(middlewareData?.size ? { middleware: { data: middlewareData } } : {}),
38095
+ },
38096
+ slotContext,
38097
+ );
38098
+ if (slot.module.__farmResolveRouteProps && slotContext !== undefined) {
38099
+ Object.defineProperty(rawSlotProps, "context", {
38100
+ value: slotContext,
38101
+ enumerable: true,
38102
+ configurable: true,
38103
+ });
38104
+ }
38105
+
38106
+ const slotSchemas = slot.module.__farmRouteParsesProps
38107
+ ? {}
38108
+ : slot.module.__farmRouteSchemas || {};
38109
+ let slotProps = slot.module.__farmResolveRouteProps
38110
+ ? await slot.module.__farmResolveRouteProps(rawSlotProps)
38111
+ : {
38112
+ ...rawSlotProps,
38113
+ params: slotSchemas.params?.parse
38114
+ ? slotSchemas.params.parse(slot.params)
38115
+ : slot.params,
38116
+ search: slotSchemas.search?.parse
38117
+ ? slotSchemas.search.parse(searchParamsObj)
38118
+ : searchParamsObj,
38119
+ searchParams: Promise.resolve(
38120
+ slotSchemas.search?.parse
38121
+ ? slotSchemas.search.parse(searchParamsObj)
38122
+ : searchParamsObj,
38123
+ ),
38124
+ };
38125
+ if (
38126
+ slot.module.__farmResolveRouteProps &&
38127
+ slotContext !== undefined &&
38128
+ slotProps.context === slotContext
38129
+ ) {
38130
+ const { context: _slotContext, ...renderSlotProps } = slotProps;
38131
+ slotProps = renderSlotProps;
38132
+ }
38133
+
38134
+ return { ...slot, props: slotProps };
38135
+ }),
38136
+ );
38137
+ const routeSlotPayload = renderedRouteSlots.map(function(slot) {
38138
+ return {
38139
+ name: slot.name,
38140
+ ownerPattern: slot.ownerPattern,
38141
+ pattern: slot.pattern,
38142
+ containerId: slot.containerId,
38143
+ interception: slot.interception,
38144
+ fallback: slot.fallback,
38145
+ props: {
38146
+ params: slot.props.params,
38147
+ search: slot.props.search || searchParamsObj,
38148
+ searchParams: slot.props.search || searchParamsObj,
38149
+ ...("data" in slot.props ? { data: slot.props.data } : {}),
38150
+ path: pathname,
38151
+ },
38152
+ };
38153
+ });
36451
38154
 
36452
38155
  const renderPageElement = async () => {
36453
38156
  // First, render the page content
@@ -36475,6 +38178,14 @@ async function handleFarmRequestInContext(
36475
38178
  pageElement = React.createElement(PageComponent, pageProps);
36476
38179
  }
36477
38180
 
38181
+ if (route.shouldHydrate && renderedRouteSlots.length > 0) {
38182
+ pageElement = React.createElement(
38183
+ "div",
38184
+ { id: "__farm_page__", "data-farm-client": "true" },
38185
+ pageElement,
38186
+ );
38187
+ }
38188
+
36478
38189
  // Wrap with layouts (from innermost to outermost)
36479
38190
  // Layouts are sorted by depth (root first), so we process in reverse
36480
38191
  let wrappedElement = pageElement;
@@ -36482,9 +38193,23 @@ async function handleFarmRequestInContext(
36482
38193
  const layout = applicableLayouts[i];
36483
38194
  const LayoutComponent = layout.module.default;
36484
38195
  if (LayoutComponent) {
38196
+ const slotProps = {};
38197
+ for (const slot of renderedRouteSlots) {
38198
+ if (slot.ownerPattern !== layout.pattern) continue;
38199
+ slotProps[slot.name] = React.createElement(
38200
+ "div",
38201
+ {
38202
+ id: slot.containerId,
38203
+ "data-farm-route-slot": slot.name,
38204
+ "data-farm-slot-owner": slot.ownerPattern,
38205
+ },
38206
+ React.createElement(slot.module.default, slot.props),
38207
+ );
38208
+ }
36485
38209
  wrappedElement = React.createElement(LayoutComponent, {
36486
38210
  children: wrappedElement,
36487
38211
  params,
38212
+ ...slotProps,
36488
38213
  });
36489
38214
  }
36490
38215
  }
@@ -36536,6 +38261,7 @@ async function handleFarmRequestInContext(
36536
38261
  );
36537
38262
  const hasRequestScopedRender = Boolean(
36538
38263
  pageStatus >= 400 ||
38264
+ request.headers.get("x-farm-intercept-from") ||
36539
38265
  hasPrivateRequestHeaders ||
36540
38266
  hasConfiguredRouteContext ||
36541
38267
  middlewareData?.size ||
@@ -36575,7 +38301,10 @@ async function handleFarmRequestInContext(
36575
38301
  ' <link rel="modulepreload" href="/farm-client.js">\\n' +
36576
38302
  '</head>\\n<body>\\n <div id="root">';
36577
38303
  const streamSuffix = '</div>\\n' +
36578
- ' ' + renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath) + '\\n' +
38304
+ ' ' + renderFarmClientBootstrapScript(
38305
+ pageProps.__farmCanonicalPath,
38306
+ routeSlotPayload
38307
+ ) + '\\n' +
36579
38308
  ' <script type="module" src="/farm-client.js"></script>\\n' +
36580
38309
  '</body>\\n</html>';
36581
38310
  const streamedDocument = createFarmDocumentStream(
@@ -36632,7 +38361,10 @@ async function handleFarmRequestInContext(
36632
38361
  // Inject client script before closing body tag
36633
38362
  .replace(
36634
38363
  /<\\/body>/i,
36635
- ' ' + renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath) + '\\n' +
38364
+ ' ' + renderFarmClientBootstrapScript(
38365
+ pageProps.__farmCanonicalPath,
38366
+ routeSlotPayload
38367
+ ) + '\\n' +
36636
38368
  ' <script type="module" src="/farm-client.js"></script>\\n</body>',
36637
38369
  );
36638
38370
 
@@ -36653,7 +38385,7 @@ async function handleFarmRequestInContext(
36653
38385
  </head>
36654
38386
  <body>
36655
38387
  <div id="root">\${html}</div>
36656
- \${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath)}
38388
+ \${renderFarmClientBootstrapScript(pageProps.__farmCanonicalPath, routeSlotPayload)}
36657
38389
  <script type="module" src="/farm-client.js"></script>
36658
38390
  </body>
36659
38391
  </html>\`;
@@ -36661,7 +38393,7 @@ async function handleFarmRequestInContext(
36661
38393
  fullHtml = applyFarmI18nDocument(fullHtml, pathname, farmI18nSnapshot);
36662
38394
 
36663
38395
  if (pageStatus === 200 && pprCacheKey && request.method.toUpperCase() !== "HEAD") {
36664
- pprShellCache.set(
38396
+ await pprShellCache.setAsync(
36665
38397
  pprCacheKey,
36666
38398
  { html: fullHtml },
36667
38399
  {
@@ -37854,6 +39586,13 @@ function mergeFarmViteConfig(farmConfig, userConfig = {}) {
37854
39586
  ...farmConfig.server,
37855
39587
  ...userConfig.server
37856
39588
  },
39589
+ resolve: {
39590
+ ...farmConfig.resolve,
39591
+ ...userConfig.resolve,
39592
+ dedupe: Array.from(
39593
+ /* @__PURE__ */ new Set([...farmConfig.resolve?.dedupe || [], ...userConfig.resolve?.dedupe || []])
39594
+ )
39595
+ },
37857
39596
  optimizeDeps: {
37858
39597
  ...farmConfig.optimizeDeps,
37859
39598
  ...userConfig.optimizeDeps,
@@ -38400,11 +40139,174 @@ function normalizeMutationError(error) {
38400
40139
  }
38401
40140
  __name(normalizeMutationError, "normalizeMutationError");
38402
40141
 
40142
+ // src/fetcher-client.tsx
40143
+ var import_react10 = require("react");
40144
+ var formDataContexts = /* @__PURE__ */ new WeakMap();
40145
+ function useFetcher(target, options = {}) {
40146
+ const targetRef = (0, import_react10.useRef)(target);
40147
+ const optionsRef = (0, import_react10.useRef)(options);
40148
+ const submissionIdRef = (0, import_react10.useRef)(0);
40149
+ const [formData, setFormData] = (0, import_react10.useState)(null);
40150
+ const mutation = useMutation(target, options);
40151
+ targetRef.current = target;
40152
+ optionsRef.current = options;
40153
+ const submitAsync = (0, import_react10.useCallback)(
40154
+ async (input) => {
40155
+ const submissionId = ++submissionIdRef.current;
40156
+ const submittedFormData = isFormData4(input) ? input : null;
40157
+ setFormData(submittedFormData);
40158
+ try {
40159
+ const variables = submittedFormData ? mapFetcherFormData(targetRef.current, submittedFormData, optionsRef.current) : input;
40160
+ return await mutation.mutateAsync(variables);
40161
+ } finally {
40162
+ if (submissionId === submissionIdRef.current) {
40163
+ setFormData(null);
40164
+ }
40165
+ }
40166
+ },
40167
+ [mutation.mutateAsync]
40168
+ );
40169
+ const submit = (0, import_react10.useCallback)(
40170
+ (input) => {
40171
+ void submitAsync(input).catch(() => {
40172
+ });
40173
+ },
40174
+ [submitAsync]
40175
+ );
40176
+ const Form = (0, import_react10.useMemo)(() => {
40177
+ const FetcherForm = /* @__PURE__ */ __name(({ action, method, encType, onSubmit, ...props }) => {
40178
+ const targetValue = targetRef.current;
40179
+ const metadata = getAPIRouteRefMetadata(targetValue);
40180
+ const nativeAction = action ?? resolveFetcherFormAction(targetValue, metadata);
40181
+ const nativeMethod = method ?? (metadata && (metadata.method === "GET" || metadata.method === "POST") ? metadata.method.toLowerCase() : metadata ? "post" : void 0);
40182
+ const functionAction = typeof nativeAction === "function";
40183
+ const handleSubmit = /* @__PURE__ */ __name((event) => {
40184
+ onSubmit?.(event);
40185
+ if (event.defaultPrevented) return;
40186
+ event.preventDefault();
40187
+ const submitter = getSubmitter(event);
40188
+ const nextFormData = createSubmitterFormData(event.currentTarget, submitter);
40189
+ formDataContexts.set(nextFormData, {
40190
+ form: event.currentTarget,
40191
+ submitter
40192
+ });
40193
+ void submitAsync(nextFormData).catch(() => {
40194
+ });
40195
+ }, "handleSubmit");
40196
+ return (0, import_react10.createElement)("form", {
40197
+ ...props,
40198
+ action: nativeAction,
40199
+ method: functionAction ? void 0 : nativeMethod,
40200
+ encType: functionAction ? void 0 : encType,
40201
+ onSubmit: handleSubmit
40202
+ });
40203
+ }, "FetcherForm");
40204
+ FetcherForm.displayName = "FetcherForm";
40205
+ return FetcherForm;
40206
+ }, [submitAsync]);
40207
+ const reset = (0, import_react10.useCallback)(() => {
40208
+ submissionIdRef.current += 1;
40209
+ setFormData(null);
40210
+ mutation.reset();
40211
+ }, [mutation.reset]);
40212
+ return (0, import_react10.useMemo)(
40213
+ () => ({
40214
+ state: mutation.pending ? "submitting" : "idle",
40215
+ status: mutation.status,
40216
+ pending: mutation.pending,
40217
+ data: mutation.data,
40218
+ error: mutation.error,
40219
+ variables: mutation.variables,
40220
+ formData,
40221
+ submit,
40222
+ submitAsync,
40223
+ Form,
40224
+ reset
40225
+ }),
40226
+ [
40227
+ Form,
40228
+ formData,
40229
+ mutation.data,
40230
+ mutation.error,
40231
+ mutation.pending,
40232
+ mutation.status,
40233
+ mutation.variables,
40234
+ reset,
40235
+ submit,
40236
+ submitAsync
40237
+ ]
40238
+ );
40239
+ }
40240
+ __name(useFetcher, "useFetcher");
40241
+ function mapFetcherFormData(target, formData, options) {
40242
+ const context = formDataContexts.get(formData) ?? { form: null, submitter: null };
40243
+ if (options.mapFormData) {
40244
+ return options.mapFormData(formData, context);
40245
+ }
40246
+ if (!isAPIRouteRef(target)) {
40247
+ return formData;
40248
+ }
40249
+ const values = formDataToObject3(formData);
40250
+ const method = getAPIRouteRefMetadata(target)?.method;
40251
+ return method === "GET" || method === "HEAD" ? { query: values } : { body: values };
40252
+ }
40253
+ __name(mapFetcherFormData, "mapFetcherFormData");
40254
+ function resolveFetcherFormAction(target, metadata) {
40255
+ if (!metadata) return isProgressiveFormAction(target) ? target : void 0;
40256
+ if (metadata.sameOrigin) return metadata.path;
40257
+ return new URL(metadata.path, metadata.baseURL).href;
40258
+ }
40259
+ __name(resolveFetcherFormAction, "resolveFetcherFormAction");
40260
+ function formDataToObject3(formData) {
40261
+ const output = /* @__PURE__ */ Object.create(null);
40262
+ for (const [key, value] of formData.entries()) {
40263
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
40264
+ const current = output[key];
40265
+ if (current === void 0) {
40266
+ output[key] = value;
40267
+ } else if (Array.isArray(current)) {
40268
+ current.push(value);
40269
+ } else {
40270
+ output[key] = [current, value];
40271
+ }
40272
+ }
40273
+ return output;
40274
+ }
40275
+ __name(formDataToObject3, "formDataToObject");
40276
+ function createSubmitterFormData(form, submitter) {
40277
+ try {
40278
+ return new FormData(form, submitter);
40279
+ } catch {
40280
+ const formData = new FormData(form);
40281
+ const candidate = submitter;
40282
+ if (candidate && !candidate.disabled && candidate.name) {
40283
+ formData.append(candidate.name, candidate.value ?? "");
40284
+ }
40285
+ return formData;
40286
+ }
40287
+ }
40288
+ __name(createSubmitterFormData, "createSubmitterFormData");
40289
+ function getSubmitter(event) {
40290
+ const nativeEvent = event.nativeEvent;
40291
+ return nativeEvent.submitter instanceof HTMLElement ? nativeEvent.submitter : null;
40292
+ }
40293
+ __name(getSubmitter, "getSubmitter");
40294
+ function isProgressiveFormAction(target) {
40295
+ const candidate = target;
40296
+ return candidate.__farmServerFn === true || typeof candidate.$$FORM_ACTION === "function" || candidate.$$typeof === /* @__PURE__ */ Symbol.for("react.server.reference");
40297
+ }
40298
+ __name(isProgressiveFormAction, "isProgressiveFormAction");
40299
+ function isFormData4(value) {
40300
+ if (!value || typeof value !== "object") return false;
40301
+ return typeof FormData !== "undefined" && value instanceof FormData || Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function";
40302
+ }
40303
+ __name(isFormData4, "isFormData");
40304
+
38403
40305
  // src/client.ts
38404
40306
  init_integration_api();
38405
40307
 
38406
40308
  // src/store.ts
38407
- var import_react10 = require("react");
40309
+ var import_react11 = require("react");
38408
40310
  var RESERVED_STORE_KEYS = /* @__PURE__ */ new Set([
38409
40311
  "use",
38410
40312
  "get",
@@ -38536,20 +40438,20 @@ function createStore(initialState, extend) {
38536
40438
  }
38537
40439
  return lastSlice;
38538
40440
  }, "getSnapshot");
38539
- return (0, import_react10.useSyncExternalStore)(
40441
+ return (0, import_react11.useSyncExternalStore)(
38540
40442
  (notify) => addSubscription(keys, () => notify()),
38541
40443
  getSnapshot,
38542
40444
  getSnapshot
38543
40445
  );
38544
40446
  }
38545
40447
  if (typeof keyOrKeys === "string") {
38546
- return (0, import_react10.useSyncExternalStore)(
40448
+ return (0, import_react11.useSyncExternalStore)(
38547
40449
  (notify) => addSubscription([keyOrKeys], () => notify()),
38548
40450
  () => state[keyOrKeys],
38549
40451
  () => state[keyOrKeys]
38550
40452
  );
38551
40453
  }
38552
- return (0, import_react10.useSyncExternalStore)(
40454
+ return (0, import_react11.useSyncExternalStore)(
38553
40455
  (notify) => addSubscription(null, () => notify()),
38554
40456
  () => state,
38555
40457
  () => state
@@ -38601,7 +40503,7 @@ function createStore(initialState, extend) {
38601
40503
  __name(createStore, "createStore");
38602
40504
 
38603
40505
  // src/client/link.tsx
38604
- var import_react11 = require("react");
40506
+ var import_react12 = require("react");
38605
40507
  init_router();
38606
40508
  init_client_runtime();
38607
40509
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -38663,9 +40565,9 @@ function LinkInner({
38663
40565
  onTouchStart,
38664
40566
  ...props
38665
40567
  }, ref) {
38666
- const elementRef = (0, import_react11.useRef)(null);
38667
- const intentTimeoutRef = (0, import_react11.useRef)(null);
38668
- const hasPrefetched = (0, import_react11.useRef)(false);
40568
+ const elementRef = (0, import_react12.useRef)(null);
40569
+ const intentTimeoutRef = (0, import_react12.useRef)(null);
40570
+ const hasPrefetched = (0, import_react12.useRef)(false);
38669
40571
  const { intent, viewport, render } = normalizePrefetch(prefetch2);
38670
40572
  const baseHref = resolveLinkHref(href, params, {
38671
40573
  query,
@@ -38674,17 +40576,17 @@ function LinkInner({
38674
40576
  });
38675
40577
  const resolvedHref = localizeActiveFarmHref(baseHref, locale);
38676
40578
  const isExternal = isExternalUrl(resolvedHref);
38677
- const doPrefetch = (0, import_react11.useCallback)(() => {
40579
+ const doPrefetch = (0, import_react12.useCallback)(() => {
38678
40580
  if (isExternal || hasPrefetched.current) return;
38679
40581
  const router = getRouter2();
38680
40582
  if (!router) return;
38681
40583
  hasPrefetched.current = true;
38682
40584
  router.prefetch(resolvedHref);
38683
40585
  }, [resolvedHref, isExternal]);
38684
- (0, import_react11.useEffect)(() => {
40586
+ (0, import_react12.useEffect)(() => {
38685
40587
  hasPrefetched.current = false;
38686
40588
  }, [resolvedHref]);
38687
- (0, import_react11.useEffect)(() => {
40589
+ (0, import_react12.useEffect)(() => {
38688
40590
  const element = elementRef.current;
38689
40591
  if (!element || isExternal) return;
38690
40592
  const router = getRouter2();
@@ -38694,7 +40596,7 @@ function LinkInner({
38694
40596
  return () => router.unobserveForPrefetch(element);
38695
40597
  }
38696
40598
  }, [resolvedHref, viewport, isExternal]);
38697
- (0, import_react11.useEffect)(() => {
40599
+ (0, import_react12.useEffect)(() => {
38698
40600
  if (!render || isExternal) return;
38699
40601
  let cancelled = false;
38700
40602
  let timeoutId = null;
@@ -38716,7 +40618,7 @@ function LinkInner({
38716
40618
  }
38717
40619
  };
38718
40620
  }, [render, isExternal, resolvedHref]);
38719
- (0, import_react11.useEffect)(() => {
40621
+ (0, import_react12.useEffect)(() => {
38720
40622
  return () => {
38721
40623
  if (intentTimeoutRef.current) {
38722
40624
  clearTimeout(intentTimeoutRef.current);
@@ -38724,13 +40626,13 @@ function LinkInner({
38724
40626
  }
38725
40627
  };
38726
40628
  }, []);
38727
- const cancelIntent = (0, import_react11.useCallback)(() => {
40629
+ const cancelIntent = (0, import_react12.useCallback)(() => {
38728
40630
  if (intentTimeoutRef.current) {
38729
40631
  clearTimeout(intentTimeoutRef.current);
38730
40632
  intentTimeoutRef.current = null;
38731
40633
  }
38732
40634
  }, []);
38733
- const scheduleIntentPrefetch = (0, import_react11.useCallback)(() => {
40635
+ const scheduleIntentPrefetch = (0, import_react12.useCallback)(() => {
38734
40636
  if (isExternal || !intent || hasPrefetched.current) return;
38735
40637
  cancelIntent();
38736
40638
  intentTimeoutRef.current = setTimeout(() => {
@@ -38738,42 +40640,42 @@ function LinkInner({
38738
40640
  doPrefetch();
38739
40641
  }, prefetchDelay);
38740
40642
  }, [intent, isExternal, prefetchDelay, doPrefetch, cancelIntent]);
38741
- const handleMouseEnter = (0, import_react11.useCallback)(
40643
+ const handleMouseEnter = (0, import_react12.useCallback)(
38742
40644
  (event) => {
38743
40645
  onMouseEnter?.(event);
38744
40646
  scheduleIntentPrefetch();
38745
40647
  },
38746
40648
  [onMouseEnter, scheduleIntentPrefetch]
38747
40649
  );
38748
- const handleMouseLeave = (0, import_react11.useCallback)(
40650
+ const handleMouseLeave = (0, import_react12.useCallback)(
38749
40651
  (event) => {
38750
40652
  onMouseLeave?.(event);
38751
40653
  cancelIntent();
38752
40654
  },
38753
40655
  [onMouseLeave, cancelIntent]
38754
40656
  );
38755
- const handleTouchStart = (0, import_react11.useCallback)(
40657
+ const handleTouchStart = (0, import_react12.useCallback)(
38756
40658
  (event) => {
38757
40659
  onTouchStart?.(event);
38758
40660
  scheduleIntentPrefetch();
38759
40661
  },
38760
40662
  [onTouchStart, scheduleIntentPrefetch]
38761
40663
  );
38762
- const handleFocus = (0, import_react11.useCallback)(
40664
+ const handleFocus = (0, import_react12.useCallback)(
38763
40665
  (event) => {
38764
40666
  onFocus?.(event);
38765
40667
  scheduleIntentPrefetch();
38766
40668
  },
38767
40669
  [onFocus, scheduleIntentPrefetch]
38768
40670
  );
38769
- const handleBlur = (0, import_react11.useCallback)(
40671
+ const handleBlur = (0, import_react12.useCallback)(
38770
40672
  (event) => {
38771
40673
  onBlur?.(event);
38772
40674
  cancelIntent();
38773
40675
  },
38774
40676
  [onBlur, cancelIntent]
38775
40677
  );
38776
- const handleClick = (0, import_react11.useCallback)(
40678
+ const handleClick = (0, import_react12.useCallback)(
38777
40679
  (event) => {
38778
40680
  onClick?.(event);
38779
40681
  if (event.defaultPrevented) return;
@@ -38798,7 +40700,7 @@ function LinkInner({
38798
40700
  },
38799
40701
  [resolvedHref, replace, scroll, viewTransition, target, isExternal, onClick]
38800
40702
  );
38801
- const setRefs = (0, import_react11.useCallback)(
40703
+ const setRefs = (0, import_react12.useCallback)(
38802
40704
  (node) => {
38803
40705
  elementRef.current = node;
38804
40706
  if (typeof ref === "function") ref(node);
@@ -38827,7 +40729,7 @@ function LinkInner({
38827
40729
  );
38828
40730
  }
38829
40731
  __name(LinkInner, "LinkInner");
38830
- var LinkWithRef = (0, import_react11.forwardRef)(LinkInner);
40732
+ var LinkWithRef = (0, import_react12.forwardRef)(LinkInner);
38831
40733
  LinkWithRef.displayName = "Link";
38832
40734
  var Link = LinkWithRef;
38833
40735
  function resolveLinkHref(href, params, options) {
@@ -39553,6 +41455,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39553
41455
  DeferredDataError,
39554
41456
  DocsRoute,
39555
41457
  EndpointFailure,
41458
+ FARM_API_ROUTE_META_SYMBOL,
39556
41459
  FARM_API_ROUTE_REF_SYMBOL,
39557
41460
  FARM_CRON_MANIFEST,
39558
41461
  FARM_DEFERRED_BRAND,
@@ -39597,6 +41500,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39597
41500
  _withAfterNodeMiddleware,
39598
41501
  after,
39599
41502
  api,
41503
+ applyFarmCacheInvalidationTargets,
39600
41504
  applyFarmCacheInvalidations,
39601
41505
  applyFarmCronVercelCrons,
39602
41506
  applyFarmWorkflowVercelCrons,
@@ -39614,6 +41518,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39614
41518
  buildFarmRoutePath,
39615
41519
  collectSSGPages,
39616
41520
  completeFarmServerQueryAction,
41521
+ configureFarmCache,
39617
41522
  configureFarmObservability,
39618
41523
  cookies,
39619
41524
  createAPIClient,
@@ -39713,6 +41618,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39713
41618
  generateFarmTypeArtifacts,
39714
41619
  generateRouteTypes,
39715
41620
  generateSSGManifest,
41621
+ getAPIRouteRefMetadata,
39716
41622
  getCurrentRequest,
39717
41623
  getDeployTargetForPreset,
39718
41624
  getEnv,
@@ -39772,6 +41678,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39772
41678
  isCronRequestAuthorized,
39773
41679
  isDeferred,
39774
41680
  isEndpointFailure,
41681
+ isFarmAPIStream,
39775
41682
  isFarmDeploymentMismatchResponse,
39776
41683
  isFarmDocsAPIRequest,
39777
41684
  isFarmDocsRequest,
@@ -39780,10 +41687,13 @@ __name(decodeCookiePart, "decodeCookiePart");
39780
41687
  isFarmNotFoundError,
39781
41688
  isFarmRedirectError,
39782
41689
  isFarmRouteActive,
41690
+ isJSONStreamResponse,
41691
+ isMultipartSchema,
39783
41692
  isProgrammaticRouteManifest,
39784
41693
  isProgrammaticRoutesFileName,
39785
41694
  isSSGModule,
39786
41695
  isWebResponse,
41696
+ jsonStream,
39787
41697
  layout,
39788
41698
  libsqlStorage,
39789
41699
  loadConfig,
@@ -39803,6 +41713,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39803
41713
  mergeScheduledTasks,
39804
41714
  middleware,
39805
41715
  mongodbStorage,
41716
+ multipart,
39806
41717
  mysql2Storage,
39807
41718
  mysqlStorage,
39808
41719
  navigateTo,
@@ -39839,6 +41750,7 @@ __name(decodeCookiePart, "decodeCookiePart");
39839
41750
  publicEnv,
39840
41751
  pushState,
39841
41752
  readDeferredDataResponse,
41753
+ readJSONStream,
39842
41754
  readPageState,
39843
41755
  redirect,
39844
41756
  redisStorage,
@@ -39883,13 +41795,16 @@ __name(decodeCookiePart, "decodeCookiePart");
39883
41795
  setEnv,
39884
41796
  snapshotDeferredData,
39885
41797
  sqliteStorage,
41798
+ storageCacheAdapter,
39886
41799
  titleFromMarkdown,
41800
+ toFormData,
39887
41801
  toViteModuleId,
39888
41802
  unstable_cache,
39889
41803
  unwrapMiddleware,
39890
41804
  updateTag,
39891
41805
  upstashStorage,
39892
41806
  useBlocker,
41807
+ useFetcher,
39893
41808
  useMutation,
39894
41809
  useNavigation,
39895
41810
  usePageState,