@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/client.cjs CHANGED
@@ -64,6 +64,7 @@ __export(client_exports, {
64
64
  readPageState: () => readPageState,
65
65
  replaceState: () => replaceState,
66
66
  useBlocker: () => useBlocker,
67
+ useFetcher: () => useFetcher,
67
68
  useMutation: () => useMutation,
68
69
  useNavigation: () => useNavigation,
69
70
  usePageState: () => usePageState,
@@ -988,7 +989,8 @@ var FARM_CACHE_INVALIDATION_STATE = /* @__PURE__ */ Symbol.for("farm.cacheInvali
988
989
  var globalState = globalThis;
989
990
  function getFarmCacheInvalidationState() {
990
991
  return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
991
- listeners: /* @__PURE__ */ new Set()
992
+ listeners: /* @__PURE__ */ new Set(),
993
+ taskListeners: /* @__PURE__ */ new Set()
992
994
  });
993
995
  }
994
996
  __name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
@@ -1039,11 +1041,51 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
1039
1041
 
1040
1042
  // src/cache.ts
1041
1043
  var _FarmDataCache = class _FarmDataCache {
1042
- constructor() {
1044
+ constructor(config = {}) {
1043
1045
  this.entries = /* @__PURE__ */ new Map();
1044
1046
  this.inflight = /* @__PURE__ */ new Map();
1045
1047
  this.invalidatedTagVersions = /* @__PURE__ */ new Map();
1046
1048
  this.version = 0;
1049
+ this.namespace = "farm";
1050
+ this.local = true;
1051
+ this.lease = {
1052
+ enabled: true,
1053
+ ttlMs: 1e4,
1054
+ waitTimeoutMs: 1e4,
1055
+ pollIntervalMs: 25
1056
+ };
1057
+ this.configure(config);
1058
+ }
1059
+ configure(config = {}) {
1060
+ this.adapter = config.adapter;
1061
+ this.namespace = normalizeCacheNamespace(config.namespace || "farm");
1062
+ this.local = !config.adapter;
1063
+ this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
1064
+ enabled: true,
1065
+ ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
1066
+ waitTimeoutMs: normalizePositiveDuration(
1067
+ config.lease?.waitTimeoutMs,
1068
+ 1e4,
1069
+ "cache.lease.waitTimeoutMs"
1070
+ ),
1071
+ pollIntervalMs: normalizePositiveDuration(
1072
+ config.lease?.pollIntervalMs,
1073
+ 25,
1074
+ "cache.lease.pollIntervalMs"
1075
+ )
1076
+ };
1077
+ if (!this.local) {
1078
+ this.entries.clear();
1079
+ this.inflight.clear();
1080
+ this.invalidatedTagVersions.clear();
1081
+ this.version = 0;
1082
+ }
1083
+ }
1084
+ get adapterName() {
1085
+ return this.adapter?.name || (this.adapter ? "custom" : "memory");
1086
+ }
1087
+ get hasAdapter() {
1088
+ return this.adapter !== void 0;
1047
1089
  }
1048
1090
  get size() {
1049
1091
  return this.entries.size;
@@ -1079,6 +1121,45 @@ var _FarmDataCache = class _FarmDataCache {
1079
1121
  });
1080
1122
  return this.toPublicEntry(entry);
1081
1123
  }
1124
+ async getEntryAsync(key, options = {}) {
1125
+ if (this.local) {
1126
+ const localEntry = this.getEntry(key, options);
1127
+ if (localEntry) return localEntry;
1128
+ }
1129
+ if (!this.adapter) {
1130
+ return this.local ? void 0 : this.getEntry(key, options);
1131
+ }
1132
+ const entry = await this.adapter.get(this.createAdapterKey(key));
1133
+ if (!entry) {
1134
+ emitFarmEvent({ type: "cache.miss", key });
1135
+ return void 0;
1136
+ }
1137
+ assertFarmCacheEntry(entry, key);
1138
+ const stale = await this.isAdapterEntryStale(entry, options.now);
1139
+ if (stale) {
1140
+ emitFarmEvent({
1141
+ type: "cache.stale",
1142
+ key,
1143
+ tags: [...entry.tags],
1144
+ revalidate: entry.revalidate
1145
+ });
1146
+ if (!options.allowStale) {
1147
+ emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
1148
+ return void 0;
1149
+ }
1150
+ }
1151
+ emitFarmEvent({
1152
+ type: "cache.hit",
1153
+ key,
1154
+ tags: [...entry.tags],
1155
+ revalidate: entry.revalidate,
1156
+ stale
1157
+ });
1158
+ if (this.local && !stale) {
1159
+ this.hydrateLocalEntry(entry);
1160
+ }
1161
+ return { ...entry, key };
1162
+ }
1082
1163
  set(key, value, options = {}) {
1083
1164
  const tags = /* @__PURE__ */ new Set();
1084
1165
  for (const tag of options.tags ?? []) {
@@ -1091,6 +1172,7 @@ var _FarmDataCache = class _FarmDataCache {
1091
1172
  key,
1092
1173
  value,
1093
1174
  tags,
1175
+ tagVersions: void 0,
1094
1176
  createdAt: options.createdAt ?? Date.now(),
1095
1177
  createdVersion: ++this.version,
1096
1178
  revalidate: normalizeRevalidate(options.revalidate)
@@ -1104,11 +1186,45 @@ var _FarmDataCache = class _FarmDataCache {
1104
1186
  });
1105
1187
  return this.toPublicEntry(entry);
1106
1188
  }
1189
+ async setAsync(key, value, options = {}, tagVersions) {
1190
+ const tags = normalizeCacheOptionsTags(options);
1191
+ const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
1192
+ const entry = {
1193
+ key,
1194
+ value,
1195
+ tags: Array.from(tags),
1196
+ tagVersions: capturedVersions,
1197
+ createdAt: options.createdAt ?? Date.now(),
1198
+ createdVersion: ++this.version,
1199
+ revalidate: normalizeRevalidate(options.revalidate)
1200
+ };
1201
+ if (this.local) {
1202
+ this.hydrateLocalEntry(entry);
1203
+ }
1204
+ if (this.adapter) {
1205
+ await this.adapter.set(this.createAdapterKey(key), entry);
1206
+ }
1207
+ emitFarmEvent({
1208
+ type: "cache.set",
1209
+ key,
1210
+ tags: [...entry.tags],
1211
+ revalidate: entry.revalidate
1212
+ });
1213
+ return entry;
1214
+ }
1107
1215
  delete(key) {
1108
1216
  const deleted = this.entries.delete(key);
1109
1217
  emitFarmEvent({ type: "cache.delete", key, deleted });
1110
1218
  return deleted;
1111
1219
  }
1220
+ async deleteAsync(key) {
1221
+ const deleted = this.entries.delete(key);
1222
+ if (this.adapter) {
1223
+ await this.adapter.delete(this.createAdapterKey(key));
1224
+ }
1225
+ emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
1226
+ return this.adapter ? true : deleted;
1227
+ }
1112
1228
  clear() {
1113
1229
  const count = this.entries.size;
1114
1230
  this.entries.clear();
@@ -1117,6 +1233,10 @@ var _FarmDataCache = class _FarmDataCache {
1117
1233
  this.version = 0;
1118
1234
  emitFarmEvent({ type: "cache.clear", count });
1119
1235
  }
1236
+ async clearAsync() {
1237
+ this.clear();
1238
+ await this.adapter?.clear?.();
1239
+ }
1120
1240
  isStale(entry, now2 = Date.now()) {
1121
1241
  if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now2 - entry.createdAt >= entry.revalidate * 1e3) {
1122
1242
  return true;
@@ -1129,6 +1249,12 @@ var _FarmDataCache = class _FarmDataCache {
1129
1249
  }
1130
1250
  return false;
1131
1251
  }
1252
+ async isStaleAsync(entry, now2 = Date.now()) {
1253
+ if (this.adapter) {
1254
+ return this.isAdapterEntryStale(entry, now2);
1255
+ }
1256
+ return this.isStale(entry, now2);
1257
+ }
1132
1258
  revalidateTag(tag, options = {}) {
1133
1259
  const normalized = normalizeCacheTag(tag);
1134
1260
  const count = this.invalidateTag(normalized);
@@ -1137,6 +1263,15 @@ var _FarmDataCache = class _FarmDataCache {
1137
1263
  );
1138
1264
  return count;
1139
1265
  }
1266
+ async revalidateTagAsync(tag, options = {}) {
1267
+ const normalized = normalizeCacheTag(tag);
1268
+ const count = this.invalidateTag(normalized);
1269
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
1270
+ emitFarmEvent(
1271
+ options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
1272
+ );
1273
+ return count;
1274
+ }
1140
1275
  revalidatePath(routePath) {
1141
1276
  const normalizedPath = normalizeRevalidatePath(routePath);
1142
1277
  const pathTag = createPathCacheTag(normalizedPath);
@@ -1153,8 +1288,25 @@ var _FarmDataCache = class _FarmDataCache {
1153
1288
  }
1154
1289
  return count;
1155
1290
  }
1291
+ async revalidatePathAsync(routePath) {
1292
+ const normalizedPath = normalizeRevalidatePath(routePath);
1293
+ const pathTag = createPathCacheTag(normalizedPath);
1294
+ const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
1295
+ const count = this.invalidateTag(pathTag);
1296
+ await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
1297
+ emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
1298
+ if (pprCount > 0) {
1299
+ emitFarmEvent({
1300
+ type: "ppr.shell.invalidated",
1301
+ route: normalizedPath,
1302
+ reason: "revalidatePath",
1303
+ count: pprCount
1304
+ });
1305
+ }
1306
+ return count;
1307
+ }
1156
1308
  async getOrSet(key, producer, options = {}) {
1157
- const cached = this.getEntry(key);
1309
+ const cached = await this.getEntryAsync(key);
1158
1310
  if (cached) {
1159
1311
  return cached.value;
1160
1312
  }
@@ -1163,10 +1315,8 @@ var _FarmDataCache = class _FarmDataCache {
1163
1315
  emitFarmEvent({ type: "cache.dedupe", key });
1164
1316
  return inflight;
1165
1317
  }
1166
- const promise = Promise.resolve().then(producer).then((value) => {
1167
- this.set(key, value, options);
1168
- return value;
1169
- }).catch((error) => {
1318
+ const tags = Array.from(normalizeCacheOptionsTags(options));
1319
+ const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
1170
1320
  emitFarmEvent({ type: "cache.error", key, operation: "set", error });
1171
1321
  throw error;
1172
1322
  }).finally(() => {
@@ -1175,6 +1325,40 @@ var _FarmDataCache = class _FarmDataCache {
1175
1325
  this.inflight.set(key, promise);
1176
1326
  return promise;
1177
1327
  }
1328
+ async fillCacheEntry(key, producer, options, tags) {
1329
+ const leaseKey = `${this.namespace}:lease:${key}`;
1330
+ let leaseToken;
1331
+ if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
1332
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
1333
+ if (!leaseToken) {
1334
+ const shared = await this.waitForAdapterEntry(key);
1335
+ if (shared) {
1336
+ emitFarmEvent({ type: "cache.dedupe", key });
1337
+ return shared.value;
1338
+ }
1339
+ leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
1340
+ }
1341
+ }
1342
+ try {
1343
+ const initialTagVersions = await this.getAdapterTagVersions(tags);
1344
+ const value = await producer();
1345
+ await this.setAsync(key, value, options, initialTagVersions);
1346
+ return value;
1347
+ } finally {
1348
+ if (leaseToken && this.adapter?.releaseLease) {
1349
+ await this.adapter.releaseLease(leaseKey, leaseToken);
1350
+ }
1351
+ }
1352
+ }
1353
+ async waitForAdapterEntry(key) {
1354
+ const deadline = Date.now() + this.lease.waitTimeoutMs;
1355
+ while (Date.now() < deadline) {
1356
+ await delay(this.lease.pollIntervalMs);
1357
+ const entry = await this.getEntryAsync(key);
1358
+ if (entry) return entry;
1359
+ }
1360
+ return void 0;
1361
+ }
1178
1362
  countEntriesForTag(tag) {
1179
1363
  let count = 0;
1180
1364
  for (const entry of this.entries.values()) {
@@ -1202,11 +1386,53 @@ var _FarmDataCache = class _FarmDataCache {
1202
1386
  key: entry.key,
1203
1387
  value: entry.value,
1204
1388
  tags: Array.from(entry.tags),
1389
+ tagVersions: entry.tagVersions,
1205
1390
  createdAt: entry.createdAt,
1206
1391
  createdVersion: entry.createdVersion,
1207
1392
  revalidate: entry.revalidate
1208
1393
  };
1209
1394
  }
1395
+ hydrateLocalEntry(entry) {
1396
+ this.entries.set(entry.key, {
1397
+ key: entry.key,
1398
+ value: entry.value,
1399
+ tags: new Set(entry.tags.map(normalizeCacheTag)),
1400
+ tagVersions: entry.tagVersions,
1401
+ createdAt: entry.createdAt,
1402
+ createdVersion: entry.createdVersion ?? ++this.version,
1403
+ revalidate: normalizeRevalidate(entry.revalidate)
1404
+ });
1405
+ }
1406
+ createAdapterKey(key) {
1407
+ return `${this.namespace}:entry:${key}`;
1408
+ }
1409
+ createAdapterTag(tag) {
1410
+ return `${this.namespace}:tag:${tag}`;
1411
+ }
1412
+ async getAdapterTagVersions(tags) {
1413
+ if (!this.adapter?.getTagVersions || tags.length === 0) return {};
1414
+ const normalized = tags.map(normalizeCacheTag);
1415
+ const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
1416
+ const versions = await this.adapter.getTagVersions(physicalTags);
1417
+ return Object.fromEntries(
1418
+ normalized.map((tag, index) => [
1419
+ tag,
1420
+ normalizeAdapterVersion(versions[physicalTags[index]])
1421
+ ])
1422
+ );
1423
+ }
1424
+ async isAdapterEntryStale(entry, now2 = Date.now()) {
1425
+ if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now2 - entry.createdAt >= entry.revalidate * 1e3) {
1426
+ return true;
1427
+ }
1428
+ const currentVersions = await this.getAdapterTagVersions(entry.tags);
1429
+ for (const tag of entry.tags) {
1430
+ if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
1431
+ return true;
1432
+ }
1433
+ }
1434
+ return false;
1435
+ }
1210
1436
  };
1211
1437
  __name(_FarmDataCache, "FarmDataCache");
1212
1438
  var FarmDataCache = _FarmDataCache;
@@ -1271,6 +1497,52 @@ function normalizeCacheTag(tag) {
1271
1497
  return normalized;
1272
1498
  }
1273
1499
  __name(normalizeCacheTag, "normalizeCacheTag");
1500
+ function normalizeCacheNamespace(namespace) {
1501
+ if (typeof namespace !== "string") {
1502
+ throw new TypeError("Cache namespace must be a string.");
1503
+ }
1504
+ const normalized = namespace.trim().replace(/:+$/g, "");
1505
+ if (!normalized) {
1506
+ throw new Error("Cache namespace cannot be empty.");
1507
+ }
1508
+ return normalized;
1509
+ }
1510
+ __name(normalizeCacheNamespace, "normalizeCacheNamespace");
1511
+ function normalizeAdapterVersion(value) {
1512
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
1513
+ }
1514
+ __name(normalizeAdapterVersion, "normalizeAdapterVersion");
1515
+ function normalizePositiveDuration(value, fallback, name) {
1516
+ if (value === void 0) return fallback;
1517
+ if (!Number.isFinite(value) || value <= 0) {
1518
+ throw new TypeError(`${name} must be a positive number of milliseconds.`);
1519
+ }
1520
+ return Math.floor(value);
1521
+ }
1522
+ __name(normalizePositiveDuration, "normalizePositiveDuration");
1523
+ function delay(ms) {
1524
+ return new Promise((resolve) => setTimeout(resolve, ms));
1525
+ }
1526
+ __name(delay, "delay");
1527
+ function normalizeCacheOptionsTags(options) {
1528
+ const tags = /* @__PURE__ */ new Set();
1529
+ for (const tag of options.tags ?? []) {
1530
+ tags.add(normalizeCacheTag(tag));
1531
+ }
1532
+ for (const routePath of options.paths ?? []) {
1533
+ tags.add(createPathCacheTag(routePath));
1534
+ }
1535
+ return tags;
1536
+ }
1537
+ __name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
1538
+ function assertFarmCacheEntry(entry, expectedKey) {
1539
+ if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
1540
+ throw new TypeError(
1541
+ `Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
1542
+ );
1543
+ }
1544
+ }
1545
+ __name(assertFarmCacheEntry, "assertFarmCacheEntry");
1274
1546
  function getFunctionCacheIdentity(fn) {
1275
1547
  if (fn.name) {
1276
1548
  return `name:${fn.name}`;
@@ -1467,8 +1739,74 @@ function normalizeFarmClientCacheKey(key) {
1467
1739
  }
1468
1740
  __name(normalizeFarmClientCacheKey, "normalizeFarmClientCacheKey");
1469
1741
 
1742
+ // src/api/transport.ts
1743
+ function isJSONStreamResponse(response) {
1744
+ const contentType = response.headers?.get?.("content-type")?.toLowerCase() ?? "";
1745
+ return contentType.includes("application/x-ndjson") || contentType.includes("application/ndjson");
1746
+ }
1747
+ __name(isJSONStreamResponse, "isJSONStreamResponse");
1748
+ function readJSONStream(response) {
1749
+ if (!response.body) {
1750
+ throw new TypeError("Cannot read a JSON stream response without a body");
1751
+ }
1752
+ const reader = response.body.getReader();
1753
+ const decoder = new TextDecoder();
1754
+ let buffer = "";
1755
+ let completed = false;
1756
+ let claimed = false;
1757
+ const iterator = {
1758
+ async next() {
1759
+ while (true) {
1760
+ const lineEnd = buffer.indexOf("\n");
1761
+ if (lineEnd >= 0) {
1762
+ const line = buffer.slice(0, lineEnd).trim();
1763
+ buffer = buffer.slice(lineEnd + 1);
1764
+ if (!line) continue;
1765
+ return { done: false, value: JSON.parse(line) };
1766
+ }
1767
+ if (completed) {
1768
+ const line = buffer.trim();
1769
+ buffer = "";
1770
+ if (!line) return { done: true, value: void 0 };
1771
+ return { done: false, value: JSON.parse(line) };
1772
+ }
1773
+ const chunk = await reader.read();
1774
+ completed = chunk.done;
1775
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
1776
+ }
1777
+ },
1778
+ async return() {
1779
+ completed = true;
1780
+ buffer = "";
1781
+ await reader.cancel();
1782
+ return { done: true, value: void 0 };
1783
+ }
1784
+ };
1785
+ return {
1786
+ response,
1787
+ async cancel(reason) {
1788
+ completed = true;
1789
+ buffer = "";
1790
+ await reader.cancel(reason);
1791
+ },
1792
+ [Symbol.asyncIterator]() {
1793
+ if (claimed) {
1794
+ throw new TypeError("Farm API streams can only be consumed once");
1795
+ }
1796
+ claimed = true;
1797
+ return iterator;
1798
+ }
1799
+ };
1800
+ }
1801
+ __name(readJSONStream, "readJSONStream");
1802
+ function isFarmAPIStream(value) {
1803
+ return typeof value === "object" && value !== null && "response" in value && typeof value.cancel === "function" && typeof value[Symbol.asyncIterator] === "function";
1804
+ }
1805
+ __name(isFarmAPIStream, "isFarmAPIStream");
1806
+
1470
1807
  // src/api/client.ts
1471
1808
  var FARM_API_ROUTE_REF_SYMBOL = /* @__PURE__ */ Symbol.for("farm.api.route-ref");
1809
+ var FARM_API_ROUTE_META_SYMBOL = /* @__PURE__ */ Symbol.for("farm.api.route-meta");
1472
1810
  var _APIClientError = class _APIClientError extends Error {
1473
1811
  constructor(code, data, options) {
1474
1812
  super(options.message);
@@ -1506,16 +1844,22 @@ function createAPIClient(options = {}) {
1506
1844
  }
1507
1845
  });
1508
1846
  }
1847
+ const headers = {
1848
+ "Content-Type": "application/json",
1849
+ ...options.headers,
1850
+ ...requestOptions.headers
1851
+ };
1509
1852
  const fetchOptions = {
1510
1853
  method: requestOptions.method || "GET",
1511
- headers: {
1512
- "Content-Type": "application/json",
1513
- ...options.headers,
1514
- ...requestOptions.headers
1515
- }
1854
+ headers
1516
1855
  };
1517
- if (requestOptions.body) {
1518
- fetchOptions.body = JSON.stringify(requestOptions.body);
1856
+ if (requestOptions.body !== void 0) {
1857
+ if (isFormData(requestOptions.body)) {
1858
+ deleteHeader(headers, "content-type");
1859
+ fetchOptions.body = requestOptions.body;
1860
+ } else {
1861
+ fetchOptions.body = JSON.stringify(requestOptions.body);
1862
+ }
1519
1863
  }
1520
1864
  const response = await fetch(url.toString(), fetchOptions);
1521
1865
  applyFarmCacheInvalidations(
@@ -1523,7 +1867,7 @@ function createAPIClient(options = {}) {
1523
1867
  );
1524
1868
  let data = void 0;
1525
1869
  if (response.status !== 204 && response.status !== 205) {
1526
- data = await response.json();
1870
+ data = isJSONStreamResponse(response) ? readJSONStream(response) : await response.json();
1527
1871
  }
1528
1872
  return { response, data };
1529
1873
  }, "fetchClient");
@@ -1669,16 +2013,16 @@ function createAPIClient(options = {}) {
1669
2013
  }
1670
2014
  }
1671
2015
  attempt += 1;
1672
- const delay = typeof clientOptions?.retry?.delay === "function" ? clientOptions.retry.delay(attempt) : clientOptions?.retry?.delay ?? 0;
1673
- if (delay > 0) {
1674
- await new Promise((resolve) => setTimeout(resolve, delay));
2016
+ const delay2 = typeof clientOptions?.retry?.delay === "function" ? clientOptions.retry.delay(attempt) : clientOptions?.retry?.delay ?? 0;
2017
+ if (delay2 > 0) {
2018
+ await new Promise((resolve) => setTimeout(resolve, delay2));
1675
2019
  }
1676
2020
  }
1677
2021
  })();
1678
2022
  inflightState.set(cacheKey, { promise, startedAt: now2 });
1679
2023
  try {
1680
2024
  const result2 = await promise;
1681
- if (!result2.error && isCacheEnabled) {
2025
+ if (!result2.error && isCacheEnabled && !isFarmAPIStream(result2.data)) {
1682
2026
  const updatedAt = Date.now();
1683
2027
  cacheState.set(cacheKey, {
1684
2028
  data: result2.data,
@@ -1751,10 +2095,17 @@ function createAPIClient(options = {}) {
1751
2095
  clientOptions?.onSettled?.(result.data, result.error);
1752
2096
  return result;
1753
2097
  }, "request");
1754
- return createNestedProxy([], request, routeMeta, baseURL, rootAliases);
2098
+ return createNestedProxy(
2099
+ [],
2100
+ request,
2101
+ routeMeta,
2102
+ baseURL,
2103
+ options.baseURL === void 0,
2104
+ rootAliases
2105
+ );
1755
2106
  }
1756
2107
  __name(createAPIClient, "createAPIClient");
1757
- function createNestedProxy(path, client, routeMeta, baseURL, rootAliases) {
2108
+ function createNestedProxy(path, client, routeMeta, baseURL, sameOrigin, rootAliases) {
1758
2109
  const target = /* @__PURE__ */ __name(() => {
1759
2110
  }, "target");
1760
2111
  const proxy = new Proxy(target, {
@@ -1763,13 +2114,29 @@ function createNestedProxy(path, client, routeMeta, baseURL, rootAliases) {
1763
2114
  if (prop === FARM_API_ROUTE_REF_SYMBOL) {
1764
2115
  return path.length > 0;
1765
2116
  }
2117
+ if (prop === FARM_API_ROUTE_META_SYMBOL) {
2118
+ const metadata = resolveRouteMeta({ path, baseURL });
2119
+ return Object.freeze({
2120
+ path: metadata.routePath,
2121
+ method: metadata.method,
2122
+ baseURL,
2123
+ sameOrigin
2124
+ });
2125
+ }
1766
2126
  if (path.length === 0 && typeof prop === "string" && rootAliases && prop in rootAliases) {
1767
2127
  return rootAliases[prop];
1768
2128
  }
1769
2129
  if (typeof prop !== "string") {
1770
2130
  return Reflect.get(_target, prop);
1771
2131
  }
1772
- return createNestedProxy([...path, prop], client, routeMeta, baseURL, rootAliases);
2132
+ return createNestedProxy(
2133
+ [...path, prop],
2134
+ client,
2135
+ routeMeta,
2136
+ baseURL,
2137
+ sameOrigin,
2138
+ rootAliases
2139
+ );
1773
2140
  },
1774
2141
  // When calling as a function
1775
2142
  apply(_target, _thisArg, args) {
@@ -1795,6 +2162,22 @@ function isAPIRouteRef(value) {
1795
2162
  return typeof value === "function" && value[FARM_API_ROUTE_REF_SYMBOL] === true;
1796
2163
  }
1797
2164
  __name(isAPIRouteRef, "isAPIRouteRef");
2165
+ function getAPIRouteRefMetadata(value) {
2166
+ if (!isAPIRouteRef(value)) return null;
2167
+ const metadata = value[FARM_API_ROUTE_META_SYMBOL];
2168
+ if (!metadata || typeof metadata !== "object") return null;
2169
+ const candidate = metadata;
2170
+ if (typeof candidate.path !== "string" || typeof candidate.method !== "string" || typeof candidate.baseURL !== "string" || typeof candidate.sameOrigin !== "boolean") {
2171
+ return null;
2172
+ }
2173
+ return {
2174
+ path: candidate.path,
2175
+ method: candidate.method,
2176
+ baseURL: candidate.baseURL,
2177
+ sameOrigin: candidate.sameOrigin
2178
+ };
2179
+ }
2180
+ __name(getAPIRouteRefMetadata, "getAPIRouteRefMetadata");
1798
2181
  function createServerAPIClient(endpoints, options = {}) {
1799
2182
  if (options.integrations === false || Object.prototype.hasOwnProperty.call(endpoints, "integrations")) {
1800
2183
  return endpoints;
@@ -1899,6 +2282,17 @@ function normalizeError(error) {
1899
2282
  return normalized;
1900
2283
  }
1901
2284
  __name(normalizeError, "normalizeError");
2285
+ function isFormData(value) {
2286
+ return typeof value === "object" && value !== null && (typeof FormData !== "undefined" && value instanceof FormData || Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function");
2287
+ }
2288
+ __name(isFormData, "isFormData");
2289
+ function deleteHeader(headers, name) {
2290
+ const normalized = name.toLowerCase();
2291
+ for (const key of Object.keys(headers)) {
2292
+ if (key.toLowerCase() === normalized) delete headers[key];
2293
+ }
2294
+ }
2295
+ __name(deleteHeader, "deleteHeader");
1902
2296
  function createResponseError2(response, data) {
1903
2297
  const expected = readEndpointErrorEnvelope(data);
1904
2298
  if (expected) {
@@ -2089,8 +2483,171 @@ function normalizeMutationError(error) {
2089
2483
  }
2090
2484
  __name(normalizeMutationError, "normalizeMutationError");
2091
2485
 
2092
- // src/server-query-client.ts
2486
+ // src/fetcher-client.tsx
2093
2487
  var import_react2 = require("react");
2488
+ var formDataContexts = /* @__PURE__ */ new WeakMap();
2489
+ function useFetcher(target, options = {}) {
2490
+ const targetRef = (0, import_react2.useRef)(target);
2491
+ const optionsRef = (0, import_react2.useRef)(options);
2492
+ const submissionIdRef = (0, import_react2.useRef)(0);
2493
+ const [formData, setFormData] = (0, import_react2.useState)(null);
2494
+ const mutation = useMutation(target, options);
2495
+ targetRef.current = target;
2496
+ optionsRef.current = options;
2497
+ const submitAsync = (0, import_react2.useCallback)(
2498
+ async (input) => {
2499
+ const submissionId = ++submissionIdRef.current;
2500
+ const submittedFormData = isFormData2(input) ? input : null;
2501
+ setFormData(submittedFormData);
2502
+ try {
2503
+ const variables = submittedFormData ? mapFetcherFormData(targetRef.current, submittedFormData, optionsRef.current) : input;
2504
+ return await mutation.mutateAsync(variables);
2505
+ } finally {
2506
+ if (submissionId === submissionIdRef.current) {
2507
+ setFormData(null);
2508
+ }
2509
+ }
2510
+ },
2511
+ [mutation.mutateAsync]
2512
+ );
2513
+ const submit = (0, import_react2.useCallback)(
2514
+ (input) => {
2515
+ void submitAsync(input).catch(() => {
2516
+ });
2517
+ },
2518
+ [submitAsync]
2519
+ );
2520
+ const Form = (0, import_react2.useMemo)(() => {
2521
+ const FetcherForm = /* @__PURE__ */ __name(({ action, method, encType, onSubmit, ...props }) => {
2522
+ const targetValue = targetRef.current;
2523
+ const metadata = getAPIRouteRefMetadata(targetValue);
2524
+ const nativeAction = action ?? resolveFetcherFormAction(targetValue, metadata);
2525
+ const nativeMethod = method ?? (metadata && (metadata.method === "GET" || metadata.method === "POST") ? metadata.method.toLowerCase() : metadata ? "post" : void 0);
2526
+ const functionAction = typeof nativeAction === "function";
2527
+ const handleSubmit = /* @__PURE__ */ __name((event) => {
2528
+ onSubmit?.(event);
2529
+ if (event.defaultPrevented) return;
2530
+ event.preventDefault();
2531
+ const submitter = getSubmitter(event);
2532
+ const nextFormData = createSubmitterFormData(event.currentTarget, submitter);
2533
+ formDataContexts.set(nextFormData, {
2534
+ form: event.currentTarget,
2535
+ submitter
2536
+ });
2537
+ void submitAsync(nextFormData).catch(() => {
2538
+ });
2539
+ }, "handleSubmit");
2540
+ return (0, import_react2.createElement)("form", {
2541
+ ...props,
2542
+ action: nativeAction,
2543
+ method: functionAction ? void 0 : nativeMethod,
2544
+ encType: functionAction ? void 0 : encType,
2545
+ onSubmit: handleSubmit
2546
+ });
2547
+ }, "FetcherForm");
2548
+ FetcherForm.displayName = "FetcherForm";
2549
+ return FetcherForm;
2550
+ }, [submitAsync]);
2551
+ const reset = (0, import_react2.useCallback)(() => {
2552
+ submissionIdRef.current += 1;
2553
+ setFormData(null);
2554
+ mutation.reset();
2555
+ }, [mutation.reset]);
2556
+ return (0, import_react2.useMemo)(
2557
+ () => ({
2558
+ state: mutation.pending ? "submitting" : "idle",
2559
+ status: mutation.status,
2560
+ pending: mutation.pending,
2561
+ data: mutation.data,
2562
+ error: mutation.error,
2563
+ variables: mutation.variables,
2564
+ formData,
2565
+ submit,
2566
+ submitAsync,
2567
+ Form,
2568
+ reset
2569
+ }),
2570
+ [
2571
+ Form,
2572
+ formData,
2573
+ mutation.data,
2574
+ mutation.error,
2575
+ mutation.pending,
2576
+ mutation.status,
2577
+ mutation.variables,
2578
+ reset,
2579
+ submit,
2580
+ submitAsync
2581
+ ]
2582
+ );
2583
+ }
2584
+ __name(useFetcher, "useFetcher");
2585
+ function mapFetcherFormData(target, formData, options) {
2586
+ const context = formDataContexts.get(formData) ?? { form: null, submitter: null };
2587
+ if (options.mapFormData) {
2588
+ return options.mapFormData(formData, context);
2589
+ }
2590
+ if (!isAPIRouteRef(target)) {
2591
+ return formData;
2592
+ }
2593
+ const values = formDataToObject(formData);
2594
+ const method = getAPIRouteRefMetadata(target)?.method;
2595
+ return method === "GET" || method === "HEAD" ? { query: values } : { body: values };
2596
+ }
2597
+ __name(mapFetcherFormData, "mapFetcherFormData");
2598
+ function resolveFetcherFormAction(target, metadata) {
2599
+ if (!metadata) return isProgressiveFormAction(target) ? target : void 0;
2600
+ if (metadata.sameOrigin) return metadata.path;
2601
+ return new URL(metadata.path, metadata.baseURL).href;
2602
+ }
2603
+ __name(resolveFetcherFormAction, "resolveFetcherFormAction");
2604
+ function formDataToObject(formData) {
2605
+ const output = /* @__PURE__ */ Object.create(null);
2606
+ for (const [key, value] of formData.entries()) {
2607
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
2608
+ const current = output[key];
2609
+ if (current === void 0) {
2610
+ output[key] = value;
2611
+ } else if (Array.isArray(current)) {
2612
+ current.push(value);
2613
+ } else {
2614
+ output[key] = [current, value];
2615
+ }
2616
+ }
2617
+ return output;
2618
+ }
2619
+ __name(formDataToObject, "formDataToObject");
2620
+ function createSubmitterFormData(form, submitter) {
2621
+ try {
2622
+ return new FormData(form, submitter);
2623
+ } catch {
2624
+ const formData = new FormData(form);
2625
+ const candidate = submitter;
2626
+ if (candidate && !candidate.disabled && candidate.name) {
2627
+ formData.append(candidate.name, candidate.value ?? "");
2628
+ }
2629
+ return formData;
2630
+ }
2631
+ }
2632
+ __name(createSubmitterFormData, "createSubmitterFormData");
2633
+ function getSubmitter(event) {
2634
+ const nativeEvent = event.nativeEvent;
2635
+ return nativeEvent.submitter instanceof HTMLElement ? nativeEvent.submitter : null;
2636
+ }
2637
+ __name(getSubmitter, "getSubmitter");
2638
+ function isProgressiveFormAction(target) {
2639
+ const candidate = target;
2640
+ return candidate.__farmServerFn === true || typeof candidate.$$FORM_ACTION === "function" || candidate.$$typeof === /* @__PURE__ */ Symbol.for("react.server.reference");
2641
+ }
2642
+ __name(isProgressiveFormAction, "isProgressiveFormAction");
2643
+ function isFormData2(value) {
2644
+ if (!value || typeof value !== "object") return false;
2645
+ return typeof FormData !== "undefined" && value instanceof FormData || Object.prototype.toString.call(value) === "[object FormData]" && typeof value.entries === "function";
2646
+ }
2647
+ __name(isFormData2, "isFormData");
2648
+
2649
+ // src/server-query-client.ts
2650
+ var import_react3 = require("react");
2094
2651
  var FARM_SERVER_QUERY_CLIENT_STATE = /* @__PURE__ */ Symbol.for("farm.serverQueryClientState");
2095
2652
  var serverQueryClientGlobal = globalThis;
2096
2653
  var serverQueryClientState = serverQueryClientGlobal[FARM_SERVER_QUERY_CLIENT_STATE] ?? (serverQueryClientGlobal[FARM_SERVER_QUERY_CLIENT_STATE] = {
@@ -2122,25 +2679,25 @@ __name(prefetchServerQuery, "prefetchServerQuery");
2122
2679
  function useServerQuery(query, input, options = {}) {
2123
2680
  const cache = getFarmClientDataCache();
2124
2681
  const key = createServerQueryCallKey(query, input);
2125
- const inputRef = (0, import_react2.useRef)(input);
2126
- const optionsRef = (0, import_react2.useRef)(options);
2127
- const mountedKeyRef = (0, import_react2.useRef)();
2682
+ const inputRef = (0, import_react3.useRef)(input);
2683
+ const optionsRef = (0, import_react3.useRef)(options);
2684
+ const mountedKeyRef = (0, import_react3.useRef)();
2128
2685
  inputRef.current = input;
2129
2686
  optionsRef.current = options;
2130
- const subscribe = (0, import_react2.useCallback)(
2687
+ const subscribe = (0, import_react3.useCallback)(
2131
2688
  (listener) => cache.subscribe(key, listener),
2132
2689
  [cache, key]
2133
2690
  );
2134
- const getSnapshot = (0, import_react2.useCallback)(() => cache.get(key), [cache, key]);
2135
- const entry = (0, import_react2.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
2136
- const run = (0, import_react2.useCallback)(
2691
+ const getSnapshot = (0, import_react3.useCallback)(() => cache.get(key), [cache, key]);
2692
+ const entry = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
2693
+ const run = (0, import_react3.useCallback)(
2137
2694
  (force = false) => fetchServerQuery(query, inputRef.current, {
2138
2695
  ...optionsRef.current,
2139
2696
  force
2140
2697
  }),
2141
2698
  [query]
2142
2699
  );
2143
- (0, import_react2.useEffect)(() => {
2700
+ (0, import_react3.useEffect)(() => {
2144
2701
  if (options.enabled === false) return;
2145
2702
  const firstReadForKey = mountedKeyRef.current !== key;
2146
2703
  if (firstReadForKey) mountedKeyRef.current = key;
@@ -2148,7 +2705,7 @@ function useServerQuery(query, input, options = {}) {
2148
2705
  void run().catch(() => void 0);
2149
2706
  }
2150
2707
  }, [cache, entry, key, options.enabled, run]);
2151
- (0, import_react2.useEffect)(() => {
2708
+ (0, import_react3.useEffect)(() => {
2152
2709
  if (options.enabled === false || typeof window === "undefined") return;
2153
2710
  const refreshIfStale = /* @__PURE__ */ __name(() => {
2154
2711
  if (cache.isStale(key)) void run().catch(() => void 0);
@@ -2461,7 +3018,7 @@ var api = {
2461
3018
  var endpoint = api;
2462
3019
 
2463
3020
  // src/store.ts
2464
- var import_react3 = require("react");
3021
+ var import_react4 = require("react");
2465
3022
  var RESERVED_STORE_KEYS = /* @__PURE__ */ new Set([
2466
3023
  "use",
2467
3024
  "get",
@@ -2593,20 +3150,20 @@ function createStore(initialState, extend) {
2593
3150
  }
2594
3151
  return lastSlice;
2595
3152
  }, "getSnapshot");
2596
- return (0, import_react3.useSyncExternalStore)(
3153
+ return (0, import_react4.useSyncExternalStore)(
2597
3154
  (notify) => addSubscription(keys, () => notify()),
2598
3155
  getSnapshot,
2599
3156
  getSnapshot
2600
3157
  );
2601
3158
  }
2602
3159
  if (typeof keyOrKeys === "string") {
2603
- return (0, import_react3.useSyncExternalStore)(
3160
+ return (0, import_react4.useSyncExternalStore)(
2604
3161
  (notify) => addSubscription([keyOrKeys], () => notify()),
2605
3162
  () => state[keyOrKeys],
2606
3163
  () => state[keyOrKeys]
2607
3164
  );
2608
3165
  }
2609
- return (0, import_react3.useSyncExternalStore)(
3166
+ return (0, import_react4.useSyncExternalStore)(
2610
3167
  (notify) => addSubscription(null, () => notify()),
2611
3168
  () => state,
2612
3169
  () => state
@@ -2658,7 +3215,7 @@ function createStore(initialState, extend) {
2658
3215
  __name(createStore, "createStore");
2659
3216
 
2660
3217
  // src/client/link.tsx
2661
- var import_react4 = require("react");
3218
+ var import_react5 = require("react");
2662
3219
 
2663
3220
  // src/router.ts
2664
3221
  function createFarmRouter(routes) {
@@ -3058,9 +3615,9 @@ function LinkInner({
3058
3615
  onTouchStart,
3059
3616
  ...props
3060
3617
  }, ref) {
3061
- const elementRef = (0, import_react4.useRef)(null);
3062
- const intentTimeoutRef = (0, import_react4.useRef)(null);
3063
- const hasPrefetched = (0, import_react4.useRef)(false);
3618
+ const elementRef = (0, import_react5.useRef)(null);
3619
+ const intentTimeoutRef = (0, import_react5.useRef)(null);
3620
+ const hasPrefetched = (0, import_react5.useRef)(false);
3064
3621
  const { intent, viewport, render } = normalizePrefetch(prefetch2);
3065
3622
  const baseHref = resolveLinkHref(href, params, {
3066
3623
  query,
@@ -3069,17 +3626,17 @@ function LinkInner({
3069
3626
  });
3070
3627
  const resolvedHref = localizeActiveFarmHref(baseHref, locale);
3071
3628
  const isExternal = isExternalUrl(resolvedHref);
3072
- const doPrefetch = (0, import_react4.useCallback)(() => {
3629
+ const doPrefetch = (0, import_react5.useCallback)(() => {
3073
3630
  if (isExternal || hasPrefetched.current) return;
3074
3631
  const router = getRouter();
3075
3632
  if (!router) return;
3076
3633
  hasPrefetched.current = true;
3077
3634
  router.prefetch(resolvedHref);
3078
3635
  }, [resolvedHref, isExternal]);
3079
- (0, import_react4.useEffect)(() => {
3636
+ (0, import_react5.useEffect)(() => {
3080
3637
  hasPrefetched.current = false;
3081
3638
  }, [resolvedHref]);
3082
- (0, import_react4.useEffect)(() => {
3639
+ (0, import_react5.useEffect)(() => {
3083
3640
  const element = elementRef.current;
3084
3641
  if (!element || isExternal) return;
3085
3642
  const router = getRouter();
@@ -3089,7 +3646,7 @@ function LinkInner({
3089
3646
  return () => router.unobserveForPrefetch(element);
3090
3647
  }
3091
3648
  }, [resolvedHref, viewport, isExternal]);
3092
- (0, import_react4.useEffect)(() => {
3649
+ (0, import_react5.useEffect)(() => {
3093
3650
  if (!render || isExternal) return;
3094
3651
  let cancelled = false;
3095
3652
  let timeoutId = null;
@@ -3111,7 +3668,7 @@ function LinkInner({
3111
3668
  }
3112
3669
  };
3113
3670
  }, [render, isExternal, resolvedHref]);
3114
- (0, import_react4.useEffect)(() => {
3671
+ (0, import_react5.useEffect)(() => {
3115
3672
  return () => {
3116
3673
  if (intentTimeoutRef.current) {
3117
3674
  clearTimeout(intentTimeoutRef.current);
@@ -3119,13 +3676,13 @@ function LinkInner({
3119
3676
  }
3120
3677
  };
3121
3678
  }, []);
3122
- const cancelIntent = (0, import_react4.useCallback)(() => {
3679
+ const cancelIntent = (0, import_react5.useCallback)(() => {
3123
3680
  if (intentTimeoutRef.current) {
3124
3681
  clearTimeout(intentTimeoutRef.current);
3125
3682
  intentTimeoutRef.current = null;
3126
3683
  }
3127
3684
  }, []);
3128
- const scheduleIntentPrefetch = (0, import_react4.useCallback)(() => {
3685
+ const scheduleIntentPrefetch = (0, import_react5.useCallback)(() => {
3129
3686
  if (isExternal || !intent || hasPrefetched.current) return;
3130
3687
  cancelIntent();
3131
3688
  intentTimeoutRef.current = setTimeout(() => {
@@ -3133,42 +3690,42 @@ function LinkInner({
3133
3690
  doPrefetch();
3134
3691
  }, prefetchDelay);
3135
3692
  }, [intent, isExternal, prefetchDelay, doPrefetch, cancelIntent]);
3136
- const handleMouseEnter = (0, import_react4.useCallback)(
3693
+ const handleMouseEnter = (0, import_react5.useCallback)(
3137
3694
  (event) => {
3138
3695
  onMouseEnter?.(event);
3139
3696
  scheduleIntentPrefetch();
3140
3697
  },
3141
3698
  [onMouseEnter, scheduleIntentPrefetch]
3142
3699
  );
3143
- const handleMouseLeave = (0, import_react4.useCallback)(
3700
+ const handleMouseLeave = (0, import_react5.useCallback)(
3144
3701
  (event) => {
3145
3702
  onMouseLeave?.(event);
3146
3703
  cancelIntent();
3147
3704
  },
3148
3705
  [onMouseLeave, cancelIntent]
3149
3706
  );
3150
- const handleTouchStart = (0, import_react4.useCallback)(
3707
+ const handleTouchStart = (0, import_react5.useCallback)(
3151
3708
  (event) => {
3152
3709
  onTouchStart?.(event);
3153
3710
  scheduleIntentPrefetch();
3154
3711
  },
3155
3712
  [onTouchStart, scheduleIntentPrefetch]
3156
3713
  );
3157
- const handleFocus = (0, import_react4.useCallback)(
3714
+ const handleFocus = (0, import_react5.useCallback)(
3158
3715
  (event) => {
3159
3716
  onFocus?.(event);
3160
3717
  scheduleIntentPrefetch();
3161
3718
  },
3162
3719
  [onFocus, scheduleIntentPrefetch]
3163
3720
  );
3164
- const handleBlur = (0, import_react4.useCallback)(
3721
+ const handleBlur = (0, import_react5.useCallback)(
3165
3722
  (event) => {
3166
3723
  onBlur?.(event);
3167
3724
  cancelIntent();
3168
3725
  },
3169
3726
  [onBlur, cancelIntent]
3170
3727
  );
3171
- const handleClick = (0, import_react4.useCallback)(
3728
+ const handleClick = (0, import_react5.useCallback)(
3172
3729
  (event) => {
3173
3730
  onClick?.(event);
3174
3731
  if (event.defaultPrevented) return;
@@ -3193,7 +3750,7 @@ function LinkInner({
3193
3750
  },
3194
3751
  [resolvedHref, replace, scroll, viewTransition, target, isExternal, onClick]
3195
3752
  );
3196
- const setRefs = (0, import_react4.useCallback)(
3753
+ const setRefs = (0, import_react5.useCallback)(
3197
3754
  (node) => {
3198
3755
  elementRef.current = node;
3199
3756
  if (typeof ref === "function") ref(node);
@@ -3222,7 +3779,7 @@ function LinkInner({
3222
3779
  );
3223
3780
  }
3224
3781
  __name(LinkInner, "LinkInner");
3225
- var LinkWithRef = (0, import_react4.forwardRef)(LinkInner);
3782
+ var LinkWithRef = (0, import_react5.forwardRef)(LinkInner);
3226
3783
  LinkWithRef.displayName = "Link";
3227
3784
  var Link = LinkWithRef;
3228
3785
  function resolveLinkHref(href, params, options) {
@@ -3323,7 +3880,7 @@ function matchManifestRoute(pathname, route2) {
3323
3880
  __name(matchManifestRoute, "matchManifestRoute");
3324
3881
 
3325
3882
  // src/client/router.ts
3326
- var import_react5 = require("react");
3883
+ var import_react6 = require("react");
3327
3884
 
3328
3885
  // src/deferred.ts
3329
3886
  var FARM_DEFERRED_CONTENT_TYPE = "application/x-farm-deferred+json";
@@ -3542,6 +4099,7 @@ __name(createFarmDeploymentMismatchError, "createFarmDeploymentMismatchError");
3542
4099
 
3543
4100
  // src/client/spa-router.ts
3544
4101
  var FARM_PAGE_STATE_KEY = "__farmPageState";
4102
+ var FARM_INTERCEPT_FROM_KEY = "__farmInterceptFrom";
3545
4103
  var IDLE_NAVIGATION_STATE = {
3546
4104
  state: "idle",
3547
4105
  pending: false,
@@ -3612,7 +4170,11 @@ var _SPARouter = class _SPARouter {
3612
4170
  return;
3613
4171
  }
3614
4172
  const from = window.location.pathname + window.location.search;
3615
- if (await this.shouldBlockNavigation({ from, to: fullPath, action: replace ? "replace" : "push" })) {
4173
+ if (await this.shouldBlockNavigation({
4174
+ from,
4175
+ to: fullPath,
4176
+ action: replace ? "replace" : "push"
4177
+ })) {
3616
4178
  return;
3617
4179
  }
3618
4180
  if (this.options.scrollRestoration) {
@@ -3630,11 +4192,11 @@ var _SPARouter = class _SPARouter {
3630
4192
  to: url,
3631
4193
  action: replace ? "replace" : "push"
3632
4194
  });
3633
- const pageData = await this.fetchPageData(fullPath);
4195
+ const pageData = await this.fetchPageData(fullPath, true, from);
3634
4196
  if (clientNavigation) {
3635
4197
  await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);
3636
4198
  }
3637
- if (pageData.isClientComponent === false) {
4199
+ if (pageData.isClientComponent === false && !pageData.interception) {
3638
4200
  this.finishNavigation();
3639
4201
  window.location.assign(pageData.canonicalPath || fullPath);
3640
4202
  return;
@@ -3672,11 +4234,12 @@ var _SPARouter = class _SPARouter {
3672
4234
  if (isFarmLocaleChangeHref(href)) return;
3673
4235
  const url = new URL(href, window.location.origin);
3674
4236
  const fullPath = url.pathname + url.search;
4237
+ const interceptFrom = window.location.pathname + window.location.search;
3675
4238
  if (this.prefetchingUrls.has(fullPath)) return;
3676
- if (this.isCached(fullPath)) return;
4239
+ if (this.isCached(fullPath, interceptFrom)) return;
3677
4240
  this.prefetchingUrls.add(fullPath);
3678
4241
  try {
3679
- await this.fetchPageData(fullPath, false);
4242
+ await this.fetchPageData(fullPath, false, interceptFrom);
3680
4243
  } catch (error) {
3681
4244
  console.warn("[Farm.js] Prefetch failed:", href, error);
3682
4245
  } finally {
@@ -3751,7 +4314,12 @@ var _SPARouter = class _SPARouter {
3751
4314
  }
3752
4315
  async commitNavigation(options) {
3753
4316
  const historyPath = options.pageData.canonicalPath || options.fullPath;
3754
- const historyState = createHistoryState(historyPath, options.state);
4317
+ const historyState = createHistoryState(
4318
+ historyPath,
4319
+ options.state,
4320
+ void 0,
4321
+ options.pageData.interception?.from ?? null
4322
+ );
3755
4323
  if (options.replace) {
3756
4324
  window.history.replaceState(historyState, "", historyPath);
3757
4325
  } else {
@@ -3806,15 +4374,17 @@ var _SPARouter = class _SPARouter {
3806
4374
  /**
3807
4375
  * Fetch page data from cache or server
3808
4376
  */
3809
- async fetchPageData(path, recover = true) {
3810
- const cached = this.cache.get(path);
4377
+ async fetchPageData(path, recover = true, interceptFrom) {
4378
+ const cacheKey = getPageDataCacheKey(path, interceptFrom);
4379
+ const cached = this.cache.get(cacheKey);
3811
4380
  if (cached && Date.now() - cached.timestamp < this.options.cacheMaxAge) {
3812
4381
  return cached.data;
3813
4382
  }
3814
4383
  const response = await fetch(`/__farm/page-data?path=${encodeURIComponent(path)}`, {
3815
4384
  headers: createFarmDeploymentRequestHeaders(this.options.deploymentId, {
3816
4385
  Accept: "application/x-farm-deferred+json, application/json",
3817
- "X-Farm-SPA": "1"
4386
+ "X-Farm-SPA": "1",
4387
+ ...interceptFrom ? { "X-Farm-Intercept-From": interceptFrom } : {}
3818
4388
  })
3819
4389
  });
3820
4390
  if (isFarmDeploymentMismatchResponse(response, this.options.deploymentId)) {
@@ -3832,7 +4402,7 @@ var _SPARouter = class _SPARouter {
3832
4402
  throw new Error(`Failed to fetch page data: ${response.status}`);
3833
4403
  }
3834
4404
  const data = await readDeferredDataResponse(response);
3835
- this.cache.set(path, {
4405
+ this.cache.set(cacheKey, {
3836
4406
  data,
3837
4407
  timestamp: Date.now()
3838
4408
  });
@@ -3863,7 +4433,8 @@ var _SPARouter = class _SPARouter {
3863
4433
  to: window.location.href,
3864
4434
  action: "pop"
3865
4435
  });
3866
- const pageData = await this.fetchPageData(path);
4436
+ const interceptFrom = typeof event.state?.[FARM_INTERCEPT_FROM_KEY] === "string" ? event.state[FARM_INTERCEPT_FROM_KEY] : void 0;
4437
+ const pageData = await this.fetchPageData(path, true, interceptFrom);
3867
4438
  if (clientNavigation) {
3868
4439
  await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);
3869
4440
  }
@@ -3894,8 +4465,8 @@ var _SPARouter = class _SPARouter {
3894
4465
  /**
3895
4466
  * Check if URL is cached
3896
4467
  */
3897
- isCached(path) {
3898
- const cached = this.cache.get(path);
4468
+ isCached(path, interceptFrom) {
4469
+ const cached = this.cache.get(getPageDataCacheKey(path, interceptFrom));
3899
4470
  return cached !== void 0 && Date.now() - cached.timestamp < this.options.cacheMaxAge;
3900
4471
  }
3901
4472
  /**
@@ -4051,15 +4622,26 @@ function readPageState() {
4051
4622
  return state[FARM_PAGE_STATE_KEY] ?? null;
4052
4623
  }
4053
4624
  __name(readPageState, "readPageState");
4054
- function createHistoryState(path, pageState, currentState) {
4625
+ function createHistoryState(path, pageState, currentState, interceptFrom) {
4055
4626
  const base = currentState && typeof currentState === "object" ? { ...currentState } : {};
4056
- return {
4627
+ const nextState = {
4057
4628
  ...base,
4058
4629
  path,
4059
4630
  [FARM_PAGE_STATE_KEY]: pageState
4060
4631
  };
4632
+ if (interceptFrom === null) {
4633
+ delete nextState[FARM_INTERCEPT_FROM_KEY];
4634
+ } else if (interceptFrom) {
4635
+ nextState[FARM_INTERCEPT_FROM_KEY] = interceptFrom;
4636
+ }
4637
+ return nextState;
4061
4638
  }
4062
4639
  __name(createHistoryState, "createHistoryState");
4640
+ function getPageDataCacheKey(path, interceptFrom) {
4641
+ return interceptFrom ? `${path}
4642
+ intercept:${interceptFrom}` : path;
4643
+ }
4644
+ __name(getPageDataCacheKey, "getPageDataCacheKey");
4063
4645
  function createNavigationLocation(url) {
4064
4646
  return {
4065
4647
  href: url.href,
@@ -4079,14 +4661,14 @@ function useRouter(options = {}) {
4079
4661
  const basePath = options.basePath || "";
4080
4662
  const routes = options.routes;
4081
4663
  const routeKey = routes?.map((route2) => typeof route2 === "string" ? route2 : route2.path).join("\n") || "";
4082
- const routeMatcher = (0, import_react5.useMemo)(
4664
+ const routeMatcher = (0, import_react6.useMemo)(
4083
4665
  () => routeKey ? createFarmRouter(routeKey.split("\n")) : null,
4084
4666
  [routeKey]
4085
4667
  );
4086
- const [state, setState] = (0, import_react5.useState)(() => {
4668
+ const [state, setState] = (0, import_react6.useState)(() => {
4087
4669
  return readRouterState(basePath, routeMatcher);
4088
4670
  });
4089
- (0, import_react5.useEffect)(() => {
4671
+ (0, import_react6.useEffect)(() => {
4090
4672
  if (typeof window === "undefined") return;
4091
4673
  const handlePopState = /* @__PURE__ */ __name(() => {
4092
4674
  setState(readRouterState(basePath, routeMatcher));
@@ -4137,8 +4719,8 @@ function useRouter(options = {}) {
4137
4719
  }
4138
4720
  __name(useRouter, "useRouter");
4139
4721
  function usePageState() {
4140
- const [state, setState] = (0, import_react5.useState)(() => readPageState());
4141
- (0, import_react5.useEffect)(() => {
4722
+ const [state, setState] = (0, import_react6.useState)(() => readPageState());
4723
+ (0, import_react6.useEffect)(() => {
4142
4724
  if (typeof window === "undefined") return;
4143
4725
  const handlePopState = /* @__PURE__ */ __name(() => {
4144
4726
  setState(readPageState());
@@ -4151,10 +4733,10 @@ function usePageState() {
4151
4733
  }
4152
4734
  __name(usePageState, "usePageState");
4153
4735
  function useNavigation() {
4154
- const [state, setState] = (0, import_react5.useState)(
4736
+ const [state, setState] = (0, import_react6.useState)(
4155
4737
  () => getRouter2().getNavigationState()
4156
4738
  );
4157
- (0, import_react5.useEffect)(() => {
4739
+ (0, import_react6.useEffect)(() => {
4158
4740
  if (typeof window === "undefined") return;
4159
4741
  return getRouter2().subscribeNavigation(setState);
4160
4742
  }, []);
@@ -4162,10 +4744,10 @@ function useNavigation() {
4162
4744
  }
4163
4745
  __name(useNavigation, "useNavigation");
4164
4746
  function useBlocker(options) {
4165
- const optionsRef = (0, import_react5.useRef)(options);
4747
+ const optionsRef = (0, import_react6.useRef)(options);
4166
4748
  optionsRef.current = options;
4167
4749
  const active = Boolean(options.when);
4168
- (0, import_react5.useEffect)(() => {
4750
+ (0, import_react6.useEffect)(() => {
4169
4751
  if (typeof window === "undefined" || !active) {
4170
4752
  return;
4171
4753
  }
@@ -4186,8 +4768,8 @@ function useBlocker(options) {
4186
4768
  }
4187
4769
  __name(useBlocker, "useBlocker");
4188
4770
  function useScrollRestoration(key) {
4189
- const ref = (0, import_react5.useRef)(null);
4190
- (0, import_react5.useEffect)(() => {
4771
+ const ref = (0, import_react6.useRef)(null);
4772
+ (0, import_react6.useEffect)(() => {
4191
4773
  const element = ref.current;
4192
4774
  if (!element) return;
4193
4775
  return getRouter2().registerScrollElement(key, element);
@@ -4809,6 +5391,7 @@ __name(isObject, "isObject");
4809
5391
  readPageState,
4810
5392
  replaceState,
4811
5393
  useBlocker,
5394
+ useFetcher,
4812
5395
  useMutation,
4813
5396
  useNavigation,
4814
5397
  usePageState,