@farm.js/core 0.1.0-beta.95 → 0.1.0-beta.97

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 (317) hide show
  1. package/dist/after.cjs +1 -1
  2. package/dist/after.mjs +1 -1
  3. package/dist/agent-runtime.d.mts +3 -2
  4. package/dist/agent-runtime.d.ts +3 -2
  5. package/dist/api/route-manager.cjs +43 -4
  6. package/dist/api/route-manager.d.mts +4 -3
  7. package/dist/api/route-manager.d.ts +4 -3
  8. package/dist/api/route-manager.mjs +7 -7
  9. package/dist/api/runtime.cjs +43 -4
  10. package/dist/api/runtime.d.mts +1 -1
  11. package/dist/api/runtime.d.ts +1 -1
  12. package/dist/api/runtime.mjs +5 -5
  13. package/dist/api.cjs +352 -109
  14. package/dist/api.d.mts +7 -6
  15. package/dist/api.d.ts +7 -6
  16. package/dist/api.mjs +19 -12
  17. package/dist/{app-CIIEvA4r.d.ts → app-CIOx3LvY.d.ts} +4 -4
  18. package/dist/{app-O4AEC1OH.d.mts → app-DBd6437H.d.mts} +4 -4
  19. package/dist/app-markdown.d.mts +4 -3
  20. package/dist/app-markdown.d.ts +4 -3
  21. package/dist/cache.cjs +42 -4
  22. package/dist/cache.d.mts +68 -1
  23. package/dist/cache.d.ts +68 -1
  24. package/dist/cache.mjs +3 -3
  25. package/dist/{chunk-AXVJCMVF.mjs → chunk-2HDOV47R.mjs} +3 -3
  26. package/dist/chunk-2HDOV47R.mjs.map +1 -0
  27. package/dist/{chunk-RBRLLZL5.mjs → chunk-34IAPZBG.mjs} +16 -3
  28. package/dist/chunk-34IAPZBG.mjs.map +1 -0
  29. package/dist/{chunk-VV24CC42.mjs → chunk-35NPLKQJ.mjs} +2 -2
  30. package/dist/{chunk-D7QH7MDU.mjs → chunk-3TWQERDE.mjs} +5 -4
  31. package/dist/chunk-3TWQERDE.mjs.map +1 -0
  32. package/dist/{chunk-RWYRFCLG.mjs → chunk-4X57GXQA.mjs} +2 -2
  33. package/dist/{chunk-KOTSX5JH.mjs → chunk-52BR7LTX.mjs} +30 -21
  34. package/dist/chunk-52BR7LTX.mjs.map +1 -0
  35. package/dist/{chunk-SALMKQXH.mjs → chunk-6EJHNHH4.mjs} +80 -27
  36. package/dist/chunk-6EJHNHH4.mjs.map +1 -0
  37. package/dist/{chunk-ZFNK77WN.mjs → chunk-6JNGOC37.mjs} +2 -2
  38. package/dist/{after.cjs.map → chunk-6JNGOC37.mjs.map} +1 -1
  39. package/dist/{chunk-MOW47IF5.mjs → chunk-6UYVU46O.mjs} +2 -2
  40. package/dist/{chunk-7MABZJIM.mjs → chunk-7PYVLJ4J.mjs} +1 -1
  41. package/dist/chunk-7PYVLJ4J.mjs.map +1 -0
  42. package/dist/{chunk-FLHLPB57.mjs → chunk-D7F7YZ7L.mjs} +93 -67
  43. package/dist/chunk-D7F7YZ7L.mjs.map +1 -0
  44. package/dist/chunk-DU3PKDVQ.mjs +35 -0
  45. package/dist/chunk-DU3PKDVQ.mjs.map +1 -0
  46. package/dist/{chunk-SCFX4UTD.mjs → chunk-EHTUKVSW.mjs} +1 -1
  47. package/dist/chunk-EHTUKVSW.mjs.map +1 -0
  48. package/dist/{chunk-KWCNQUH5.mjs → chunk-EPDIF432.mjs} +526 -50
  49. package/dist/chunk-EPDIF432.mjs.map +1 -0
  50. package/dist/{chunk-A3636IHN.mjs → chunk-FP5Q67FO.mjs} +167 -96
  51. package/dist/chunk-FP5Q67FO.mjs.map +1 -0
  52. package/dist/{chunk-HHZAOTQD.mjs → chunk-GJ7W6LNK.mjs} +7 -6
  53. package/dist/chunk-GJ7W6LNK.mjs.map +1 -0
  54. package/dist/{chunk-RLGUZ3HS.mjs → chunk-I3OOUWO5.mjs} +3 -3
  55. package/dist/{chunk-75CGAL6E.mjs → chunk-IZBX2TEU.mjs} +217 -105
  56. package/dist/chunk-IZBX2TEU.mjs.map +1 -0
  57. package/dist/{chunk-22VG4DFJ.mjs → chunk-J3MPQ4MQ.mjs} +2 -2
  58. package/dist/{chunk-22VG4DFJ.mjs.map → chunk-J3MPQ4MQ.mjs.map} +1 -1
  59. package/dist/{chunk-2LS3KKE7.mjs → chunk-JV7JUD7Q.mjs} +4 -4
  60. package/dist/{chunk-Q3OX763A.mjs → chunk-LXDASSTE.mjs} +2 -2
  61. package/dist/{chunk-ZRBCBOEX.mjs → chunk-N2FY2QZ7.mjs} +28 -3
  62. package/dist/chunk-N2FY2QZ7.mjs.map +1 -0
  63. package/dist/{chunk-MRVJCLYQ.mjs → chunk-PSQ7N4XP.mjs} +4 -2
  64. package/dist/chunk-PSQ7N4XP.mjs.map +1 -0
  65. package/dist/{chunk-HVG3HLQZ.mjs → chunk-Q7WGOOAI.mjs} +3 -3
  66. package/dist/{chunk-WTYAPO5I.mjs → chunk-RCNWMEBT.mjs} +3 -2
  67. package/dist/{chunk-WTYAPO5I.mjs.map → chunk-RCNWMEBT.mjs.map} +1 -1
  68. package/dist/{chunk-3INDBMUU.mjs → chunk-TGDIACZT.mjs} +2 -2
  69. package/dist/{chunk-WB75GIX2.mjs → chunk-TQTB33JS.mjs} +14 -3
  70. package/dist/chunk-TQTB33JS.mjs.map +1 -0
  71. package/dist/{chunk-MH27UH72.mjs → chunk-TT3E2JOF.mjs} +3 -3
  72. package/dist/{chunk-UWRGX3J3.mjs → chunk-UMUWR5XA.mjs} +2 -2
  73. package/dist/{chunk-XTLLHCWU.mjs → chunk-V4VRLVLW.mjs} +52 -31
  74. package/dist/chunk-V4VRLVLW.mjs.map +1 -0
  75. package/dist/{chunk-EXCGBERG.mjs → chunk-WD2EBM3I.mjs} +79 -17
  76. package/dist/chunk-WD2EBM3I.mjs.map +1 -0
  77. package/dist/{chunk-DLBUAJTK.mjs → chunk-WMJGA32P.mjs} +74 -5
  78. package/dist/chunk-WMJGA32P.mjs.map +1 -0
  79. package/dist/{chunk-TKQCJMY7.mjs → chunk-X4SFHKFH.mjs} +7 -4
  80. package/dist/{chunk-TKQCJMY7.mjs.map → chunk-X4SFHKFH.mjs.map} +1 -1
  81. package/dist/{chunk-Q7GPJZCO.mjs → chunk-YIBV77KZ.mjs} +26 -7
  82. package/dist/chunk-YIBV77KZ.mjs.map +1 -0
  83. package/dist/client/lifecycle.mjs +2 -2
  84. package/dist/{client-mcMC334J.d.mts → client-DWoLZ3QU.d.mts} +52 -5
  85. package/dist/{client-d5ONQ-Pd.d.ts → client-DuQuQC1h.d.ts} +52 -5
  86. package/dist/client-cache-BMxuFqwH.d.ts +18 -0
  87. package/dist/client-cache-CCK-fCe0.d.mts +18 -0
  88. package/dist/{client-plugins-BvClItiL.d.mts → client-plugins-B6-07YmP.d.mts} +52 -99
  89. package/dist/{client-plugins-B9Sq-iMg.d.ts → client-plugins-By6MVUX-.d.ts} +52 -99
  90. package/dist/client-plugins.cjs +1 -1
  91. package/dist/client-plugins.d.mts +3 -2
  92. package/dist/client-plugins.d.ts +3 -2
  93. package/dist/client-plugins.mjs +2 -2
  94. package/dist/client.cjs +1046 -211
  95. package/dist/client.d.mts +136 -18
  96. package/dist/client.d.ts +136 -18
  97. package/dist/client.mjs +32 -15
  98. package/dist/config.d.mts +3 -2
  99. package/dist/config.d.ts +3 -2
  100. package/dist/{devtools-S52RRRMN.mjs → devtools-XWZX6CCL.mjs} +5 -5
  101. package/dist/{devtools-client-3XRTBND5.mjs → devtools-client-Z7QQA3Q2.mjs} +56 -17
  102. package/dist/devtools-client-Z7QQA3Q2.mjs.map +1 -0
  103. package/dist/{devtools-ui-NJKFORTG.mjs → devtools-ui-2HG5M4EL.mjs} +3 -1
  104. package/dist/devtools-ui-2HG5M4EL.mjs.map +1 -0
  105. package/dist/docs.cjs +24 -5
  106. package/dist/docs.mjs +5 -5
  107. package/dist/i18n/server.cjs +13 -2
  108. package/dist/i18n/server.d.mts +2 -2
  109. package/dist/i18n/server.d.ts +2 -2
  110. package/dist/i18n/server.mjs +1 -1
  111. package/dist/index.cjs +1928 -894
  112. package/dist/index.d.mts +139 -21
  113. package/dist/index.d.ts +139 -21
  114. package/dist/index.mjs +57 -34
  115. package/dist/index.mjs.map +1 -1
  116. package/dist/integration-api-BT024nuJ.d.mts +97 -0
  117. package/dist/integration-api-BT024nuJ.d.ts +97 -0
  118. package/dist/integrations.d.mts +3 -2
  119. package/dist/integrations.d.ts +3 -2
  120. package/dist/internal/build-runtime.cjs +764 -547
  121. package/dist/internal/build-runtime.d.mts +5 -4
  122. package/dist/internal/build-runtime.d.ts +5 -4
  123. package/dist/internal/build-runtime.mjs +16 -16
  124. package/dist/internal/client-runtime.cjs +1 -1
  125. package/dist/internal/client-runtime.mjs +2 -2
  126. package/dist/internal/config-runtime.cjs +4 -1
  127. package/dist/internal/config-runtime.d.mts +4 -3
  128. package/dist/internal/config-runtime.d.ts +4 -3
  129. package/dist/internal/config-runtime.mjs +4 -4
  130. package/dist/internal/product-telemetry-runtime.cjs +1 -1
  131. package/dist/internal/product-telemetry-runtime.mjs +1 -1
  132. package/dist/internal/production-runtime.cjs +29 -3
  133. package/dist/internal/production-runtime.d.mts +8 -7
  134. package/dist/internal/production-runtime.d.ts +8 -7
  135. package/dist/internal/production-runtime.mjs +5 -5
  136. package/dist/{metadata-route-yV4U6X8h.d.ts → metadata-route-8_V3UonT.d.ts} +1 -1
  137. package/dist/{metadata-route-p4K1l92V.d.mts → metadata-route-CWP_HjGU.d.mts} +1 -1
  138. package/dist/middleware.cjs +28 -2
  139. package/dist/middleware.d.mts +5 -4
  140. package/dist/middleware.d.ts +5 -4
  141. package/dist/middleware.mjs +4 -4
  142. package/dist/navigation.cjs +3 -1
  143. package/dist/navigation.mjs +3 -3
  144. package/dist/observability.cjs +27 -2
  145. package/dist/observability.mjs +1 -1
  146. package/dist/plugin.cjs +528 -349
  147. package/dist/plugin.d.mts +3 -2
  148. package/dist/plugin.d.ts +3 -2
  149. package/dist/plugin.mjs +13 -13
  150. package/dist/{production-runtime-IkB0Qj4i.d.mts → production-runtime-BGRH1dKG.d.mts} +1 -1
  151. package/dist/{production-runtime-0JTch4_d.d.ts → production-runtime-CdmzsDax.d.ts} +1 -1
  152. package/dist/query/client.cjs +68 -29
  153. package/dist/query/client.mjs +69 -30
  154. package/dist/query/client.mjs.map +1 -1
  155. package/dist/{render-plan-Dc8CjNI7.d.ts → render-plan-0GeHiGVZ.d.ts} +1 -1
  156. package/dist/{render-plan-CU31j-Jk.d.mts → render-plan-DLxJYAA5.d.mts} +1 -1
  157. package/dist/renderer-client.cjs +169 -26
  158. package/dist/renderer-client.d.mts +7 -6
  159. package/dist/renderer-client.d.ts +7 -6
  160. package/dist/renderer-client.mjs +16 -19
  161. package/dist/renderer-client.mjs.map +1 -1
  162. package/dist/{request-BXa1KY8i.d.mts → request-BCNXSXLh.d.mts} +1 -1
  163. package/dist/{request-CUUBujZt.d.ts → request-BstWbZ6O.d.ts} +1 -1
  164. package/dist/request.d.mts +4 -3
  165. package/dist/request.d.ts +4 -3
  166. package/dist/{route-Y8lfz1wF.d.ts → route-4pd-EVtw.d.ts} +45 -50
  167. package/dist/{route-Cq3aObmj.d.mts → route-CvEr4Uc9.d.mts} +45 -50
  168. package/dist/routes.cjs +27 -2
  169. package/dist/routes.d.mts +3 -2
  170. package/dist/routes.d.ts +3 -2
  171. package/dist/routes.mjs +4 -4
  172. package/dist/{runtime-j1S3sDTh.d.ts → runtime-BgDQzBiu.d.ts} +1 -0
  173. package/dist/{runtime-DDwvDtS4.d.mts → runtime-CV2UCV-5.d.mts} +1 -0
  174. package/dist/server-action-security.mjs +2 -2
  175. package/dist/server-fn-client.cjs +102 -26
  176. package/dist/server-fn-client.d.mts +6 -0
  177. package/dist/server-fn-client.d.ts +6 -0
  178. package/dist/server-fn-client.mjs +2 -1
  179. package/dist/server-fn.cjs +42 -4
  180. package/dist/server-fn.mjs +5 -5
  181. package/dist/server-plugins.d.mts +4 -3
  182. package/dist/server-plugins.d.ts +4 -3
  183. package/dist/server-query-client.cjs +195 -34
  184. package/dist/server-query-client.d.mts +3 -3
  185. package/dist/server-query-client.d.ts +3 -3
  186. package/dist/server-query-client.mjs +7 -7
  187. package/dist/{server-query-runtime-3zAj77yv.d.ts → server-query-runtime-DXRNhX_3.d.ts} +2 -0
  188. package/dist/{server-query-runtime-B50KAcj5.d.mts → server-query-runtime-aP52iuL5.d.mts} +2 -0
  189. package/dist/server-query.cjs +44 -5
  190. package/dist/server-query.d.mts +4 -0
  191. package/dist/server-query.d.ts +4 -0
  192. package/dist/server-query.mjs +7 -7
  193. package/dist/server.cjs +553 -370
  194. package/dist/server.d.mts +11 -10
  195. package/dist/server.d.ts +11 -10
  196. package/dist/server.mjs +17 -17
  197. package/dist/{spa-router-CyLkwst6.d.mts → spa-router-BeyAVSc6.d.mts} +1 -1
  198. package/dist/{spa-router-BkqGXaV_.d.ts → spa-router-COgu4txb.d.ts} +1 -1
  199. package/dist/testing.cjs +27 -2
  200. package/dist/testing.d.mts +3 -2
  201. package/dist/testing.d.ts +3 -2
  202. package/dist/testing.mjs +9 -9
  203. package/dist/{utils-NKR6SoNv.d.mts → utils-DL2VwDQl.d.mts} +1 -1
  204. package/dist/{utils-B2OHrb9F.d.ts → utils-DkU2c_1B.d.ts} +1 -1
  205. package/dist/version.cjs +1 -1
  206. package/dist/version.mjs +1 -1
  207. package/dist/vite.cjs +536 -353
  208. package/dist/vite.d.mts +3 -2
  209. package/dist/vite.d.ts +3 -2
  210. package/dist/vite.mjs +17 -13
  211. package/package.json +17 -17
  212. package/types/client.d.ts +115 -10
  213. package/dist/agent-runtime.cjs.map +0 -1
  214. package/dist/api/route-manager.cjs.map +0 -1
  215. package/dist/api/runtime.cjs.map +0 -1
  216. package/dist/api.cjs.map +0 -1
  217. package/dist/app-markdown.cjs.map +0 -1
  218. package/dist/cache.cjs.map +0 -1
  219. package/dist/chunk-75CGAL6E.mjs.map +0 -1
  220. package/dist/chunk-7MABZJIM.mjs.map +0 -1
  221. package/dist/chunk-A3636IHN.mjs.map +0 -1
  222. package/dist/chunk-AXVJCMVF.mjs.map +0 -1
  223. package/dist/chunk-D7QH7MDU.mjs.map +0 -1
  224. package/dist/chunk-DLBUAJTK.mjs.map +0 -1
  225. package/dist/chunk-EXCGBERG.mjs.map +0 -1
  226. package/dist/chunk-FLHLPB57.mjs.map +0 -1
  227. package/dist/chunk-HHZAOTQD.mjs.map +0 -1
  228. package/dist/chunk-KOTSX5JH.mjs.map +0 -1
  229. package/dist/chunk-KWCNQUH5.mjs.map +0 -1
  230. package/dist/chunk-MRVJCLYQ.mjs.map +0 -1
  231. package/dist/chunk-Q7GPJZCO.mjs.map +0 -1
  232. package/dist/chunk-RBRLLZL5.mjs.map +0 -1
  233. package/dist/chunk-SALMKQXH.mjs.map +0 -1
  234. package/dist/chunk-SCFX4UTD.mjs.map +0 -1
  235. package/dist/chunk-WB75GIX2.mjs.map +0 -1
  236. package/dist/chunk-XTLLHCWU.mjs.map +0 -1
  237. package/dist/chunk-ZFNK77WN.mjs.map +0 -1
  238. package/dist/chunk-ZRBCBOEX.mjs.map +0 -1
  239. package/dist/client/lifecycle.cjs.map +0 -1
  240. package/dist/client-cache-CopR_MaI.d.mts +0 -6
  241. package/dist/client-cache-Djy_TlE8.d.ts +0 -6
  242. package/dist/client-plugins.cjs.map +0 -1
  243. package/dist/client.cjs.map +0 -1
  244. package/dist/config.cjs.map +0 -1
  245. package/dist/cron.cjs.map +0 -1
  246. package/dist/deferred.cjs.map +0 -1
  247. package/dist/deployment.cjs.map +0 -1
  248. package/dist/devtools-client-3XRTBND5.mjs.map +0 -1
  249. package/dist/devtools-ui-NJKFORTG.mjs.map +0 -1
  250. package/dist/docs.cjs.map +0 -1
  251. package/dist/env-types.cjs.map +0 -1
  252. package/dist/env.cjs.map +0 -1
  253. package/dist/environment/vite.cjs.map +0 -1
  254. package/dist/environment.cjs.map +0 -1
  255. package/dist/font.cjs.map +0 -1
  256. package/dist/headers.cjs.map +0 -1
  257. package/dist/i18n/client.cjs.map +0 -1
  258. package/dist/i18n/index.cjs.map +0 -1
  259. package/dist/i18n/server.cjs.map +0 -1
  260. package/dist/image/server.cjs.map +0 -1
  261. package/dist/image/sharp.cjs.map +0 -1
  262. package/dist/image.cjs.map +0 -1
  263. package/dist/index.cjs.map +0 -1
  264. package/dist/instrumentation.cjs.map +0 -1
  265. package/dist/integrations.cjs.map +0 -1
  266. package/dist/internal/build-runtime.cjs.map +0 -1
  267. package/dist/internal/client-runtime.cjs.map +0 -1
  268. package/dist/internal/config-runtime.cjs.map +0 -1
  269. package/dist/internal/isolated-boundary.cjs.map +0 -1
  270. package/dist/internal/metadata-image-runtime.cjs.map +0 -1
  271. package/dist/internal/product-telemetry-runtime.cjs.map +0 -1
  272. package/dist/internal/production-node-env.cjs.map +0 -1
  273. package/dist/internal/production-runtime.cjs.map +0 -1
  274. package/dist/markdown.cjs.map +0 -1
  275. package/dist/middleware.cjs.map +0 -1
  276. package/dist/navigation.cjs.map +0 -1
  277. package/dist/observability.cjs.map +0 -1
  278. package/dist/plugin.cjs.map +0 -1
  279. package/dist/query/client.cjs.map +0 -1
  280. package/dist/query/index.cjs.map +0 -1
  281. package/dist/query/parsers.cjs.map +0 -1
  282. package/dist/query/server.cjs.map +0 -1
  283. package/dist/renderer/react/client.cjs.map +0 -1
  284. package/dist/renderer/react/server.cjs.map +0 -1
  285. package/dist/renderer/react/vite.cjs.map +0 -1
  286. package/dist/renderer-client.cjs.map +0 -1
  287. package/dist/renderer.cjs.map +0 -1
  288. package/dist/request.cjs.map +0 -1
  289. package/dist/router.cjs.map +0 -1
  290. package/dist/routes.cjs.map +0 -1
  291. package/dist/server-action-security.cjs.map +0 -1
  292. package/dist/server-fn-client.cjs.map +0 -1
  293. package/dist/server-fn.cjs.map +0 -1
  294. package/dist/server-plugins.cjs.map +0 -1
  295. package/dist/server-query-client.cjs.map +0 -1
  296. package/dist/server-query.cjs.map +0 -1
  297. package/dist/server.cjs.map +0 -1
  298. package/dist/storage.cjs.map +0 -1
  299. package/dist/testing.cjs.map +0 -1
  300. package/dist/theme/client.cjs.map +0 -1
  301. package/dist/theme/index.cjs.map +0 -1
  302. package/dist/theme/runtime.cjs.map +0 -1
  303. package/dist/theme/server.cjs.map +0 -1
  304. package/dist/version.cjs.map +0 -1
  305. package/dist/vite.cjs.map +0 -1
  306. package/dist/workflows.cjs.map +0 -1
  307. /package/dist/{chunk-VV24CC42.mjs.map → chunk-35NPLKQJ.mjs.map} +0 -0
  308. /package/dist/{chunk-RWYRFCLG.mjs.map → chunk-4X57GXQA.mjs.map} +0 -0
  309. /package/dist/{chunk-MOW47IF5.mjs.map → chunk-6UYVU46O.mjs.map} +0 -0
  310. /package/dist/{chunk-RLGUZ3HS.mjs.map → chunk-I3OOUWO5.mjs.map} +0 -0
  311. /package/dist/{chunk-2LS3KKE7.mjs.map → chunk-JV7JUD7Q.mjs.map} +0 -0
  312. /package/dist/{chunk-Q3OX763A.mjs.map → chunk-LXDASSTE.mjs.map} +0 -0
  313. /package/dist/{chunk-HVG3HLQZ.mjs.map → chunk-Q7WGOOAI.mjs.map} +0 -0
  314. /package/dist/{chunk-3INDBMUU.mjs.map → chunk-TGDIACZT.mjs.map} +0 -0
  315. /package/dist/{chunk-MH27UH72.mjs.map → chunk-TT3E2JOF.mjs.map} +0 -0
  316. /package/dist/{chunk-UWRGX3J3.mjs.map → chunk-UMUWR5XA.mjs.map} +0 -0
  317. /package/dist/{devtools-S52RRRMN.mjs.map → devtools-XWZX6CCL.mjs.map} +0 -0
package/dist/client.cjs CHANGED
@@ -32,11 +32,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var client_exports = {};
33
33
  __export(client_exports, {
34
34
  APIClientError: () => APIClientError,
35
+ FARM_CACHE_INVALIDATION_CHANNEL: () => FARM_CACHE_INVALIDATION_CHANNEL,
36
+ FARM_CLIENT_CACHE_PERSIST_VERSION: () => FARM_CLIENT_CACHE_PERSIST_VERSION,
35
37
  FarmClientPluginManager: () => FarmClientPluginManager,
38
+ FetcherInputError: () => FetcherInputError,
36
39
  IntegrationClientError: () => IntegrationClientError,
37
40
  Link: () => Link,
38
41
  SPARouter: () => SPARouter,
39
42
  api: () => api,
43
+ clearPersistedCache: () => clearPersistedCache,
40
44
  createAPIClient: () => createAPIClient,
41
45
  createApiClients: () => createApiClients,
42
46
  createClientPluginManager: () => createClientPluginManager,
@@ -47,13 +51,16 @@ __export(client_exports, {
47
51
  createIntegrations: () => createIntegrations,
48
52
  createServerAPIClient: () => createServerAPIClient,
49
53
  createStore: () => createStore,
54
+ defineClientCacheAdapter: () => defineClientCacheAdapter,
50
55
  defineIntegrationAPI: () => defineIntegrationAPI,
51
56
  defineIntegrationAPIOperation: () => defineIntegrationAPIOperation,
57
+ enableCrossTabCacheInvalidation: () => enableCrossTabCacheInvalidation,
52
58
  endpoint: () => endpoint,
53
59
  fetchServerQuery: () => fetchServerQuery,
54
60
  getIntegrationAPIManifest: () => getIntegrationAPIManifest,
55
61
  getRouter: () => getRouter2,
56
62
  getTheme: () => getTheme,
63
+ initPersistedClientCache: () => initPersistedClientCache,
57
64
  installChunkErrorRecovery: () => installChunkErrorRecovery,
58
65
  integrationClients: () => integrationClients,
59
66
  integrationsClient: () => integrationsClient,
@@ -66,6 +73,7 @@ __export(client_exports, {
66
73
  readPageState: () => readPageState,
67
74
  replaceState: () => replaceState,
68
75
  setTheme: () => setTheme,
76
+ storageClientCacheAdapter: () => storageClientCacheAdapter,
69
77
  toggleTheme: () => toggleTheme,
70
78
  useAction: () => useAction,
71
79
  useBlocker: () => useBlocker,
@@ -223,10 +231,10 @@ __name(createClientCancellation, "createClientCancellation");
223
231
  function notifyClientObserver(observer, args, label = "Client lifecycle") {
224
232
  if (!observer) return;
225
233
  const report = /* @__PURE__ */ __name((error) => {
226
- const reportError = globalThis.reportError;
227
- if (typeof reportError === "function") {
234
+ const reportError2 = globalThis.reportError;
235
+ if (typeof reportError2 === "function") {
228
236
  try {
229
- reportError.call(globalThis, error);
237
+ reportError2.call(globalThis, error);
230
238
  return;
231
239
  } catch {
232
240
  }
@@ -727,7 +735,8 @@ async function executeServerOperation(operation2, input, options, requestOptions
727
735
  serverRequestOptions?.baseURL ?? options.baseURL,
728
736
  request
729
737
  );
730
- const url = new URL(operation2.path, baseURL);
738
+ const origin = resolveServerBaseURL(void 0, request);
739
+ const url = new URL(operation2.path, new URL(baseURL, origin));
731
740
  appendQuery(url, input.query);
732
741
  const headers = new Headers();
733
742
  appendHeaders(
@@ -780,7 +789,9 @@ async function executeServerOperation(operation2, input, options, requestOptions
780
789
  }
781
790
  appendIntegrationClientDataHeader(headers, data);
782
791
  const body = createOperationBody(operation2, input.body, headers);
783
- const response = await (options.fetch ?? fetch)(url.toString(), {
792
+ const httpURL = resolveFarmAPIRequestURL(operation2.path, baseURL, origin);
793
+ appendQuery(httpURL, input.query);
794
+ const response = await (options.fetch ?? fetch)(httpURL.toString(), {
784
795
  method: operation2.method,
785
796
  headers,
786
797
  body,
@@ -1214,7 +1225,13 @@ function recordFarmEventTrace(event) {
1214
1225
  activeSpan.addEvent(event.type, toEventAttributes(event), event.timestamp);
1215
1226
  }
1216
1227
  const error = event.type === "request.error" ? void 0 : getEventError(event);
1217
- if (error !== void 0) recordSpanError(activeSpan, error);
1228
+ if (error !== void 0) {
1229
+ if (event.type === "render.error") {
1230
+ recordSpanException(activeSpan, error);
1231
+ } else {
1232
+ recordSpanError(activeSpan, error);
1233
+ }
1234
+ }
1218
1235
  }
1219
1236
  const completedTraceContext = recordCompletedEventSpan(event, activeContext);
1220
1237
  return traceContext ?? completedTraceContext;
@@ -1311,12 +1328,26 @@ function getCompletedSpanDescriptor(event) {
1311
1328
  }
1312
1329
  }
1313
1330
  __name(getCompletedSpanDescriptor, "getCompletedSpanDescriptor");
1331
+ function hashFarmCacheKey(value) {
1332
+ let hash = 2166136261;
1333
+ for (let index = 0; index < value.length; index++) {
1334
+ hash ^= value.charCodeAt(index);
1335
+ hash = Math.imul(hash, 16777619);
1336
+ }
1337
+ return (hash >>> 0).toString(16).padStart(8, "0");
1338
+ }
1339
+ __name(hashFarmCacheKey, "hashFarmCacheKey");
1314
1340
  function toEventAttributes(event) {
1315
1341
  const attributes = {};
1342
+ const redactKey = typeof event.type === "string" && event.type.startsWith("cache.");
1316
1343
  for (const [key, value] of Object.entries(event)) {
1317
1344
  if (key === "timestamp" || key === "level" || key === "error" || key === "traceId" || key === "spanId" || key === "traceSampled" || value === void 0) {
1318
1345
  continue;
1319
1346
  }
1347
+ if (redactKey && key === "key" && typeof value === "string") {
1348
+ attributes["farm.key_hash"] = hashFarmCacheKey(value);
1349
+ continue;
1350
+ }
1320
1351
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1321
1352
  attributes[`farm.${key}`] = value;
1322
1353
  } else if (Array.isArray(value)) {
@@ -1336,9 +1367,14 @@ function getEventError(event) {
1336
1367
  return "error" in event ? event.error : void 0;
1337
1368
  }
1338
1369
  __name(getEventError, "getEventError");
1339
- function recordSpanError(span, error) {
1370
+ function recordSpanException(span, error) {
1340
1371
  const normalized = error instanceof Error ? error : new Error(String(error));
1341
1372
  span.recordException(normalized);
1373
+ return normalized;
1374
+ }
1375
+ __name(recordSpanException, "recordSpanException");
1376
+ function recordSpanError(span, error) {
1377
+ const normalized = recordSpanException(span, error);
1342
1378
  span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: normalized.message });
1343
1379
  }
1344
1380
  __name(recordSpanError, "recordSpanError");
@@ -1498,10 +1534,19 @@ function getFarmCacheInvalidationState() {
1498
1534
  });
1499
1535
  }
1500
1536
  __name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
1537
+ function warnFarmCacheListenerError(scope, error) {
1538
+ const detail = error instanceof Error ? error.stack ?? error.message : String(error);
1539
+ console.warn(`[farm:cache] ${scope} listener failed: ${detail}`);
1540
+ }
1541
+ __name(warnFarmCacheListenerError, "warnFarmCacheListenerError");
1501
1542
  function notifyFarmCacheInvalidation(key) {
1502
1543
  if (typeof key !== "string" || key.length === 0) return;
1503
1544
  for (const listener of getFarmCacheInvalidationState().listeners) {
1504
- listener(key);
1545
+ try {
1546
+ listener(key);
1547
+ } catch (error) {
1548
+ warnFarmCacheListenerError("invalidation", error);
1549
+ }
1505
1550
  }
1506
1551
  }
1507
1552
  __name(notifyFarmCacheInvalidation, "notifyFarmCacheInvalidation");
@@ -1514,6 +1559,14 @@ function applyFarmCacheInvalidations(keys) {
1514
1559
  }
1515
1560
  }
1516
1561
  __name(applyFarmCacheInvalidations, "applyFarmCacheInvalidations");
1562
+ function encodeFarmCacheInvalidations(keys) {
1563
+ const normalized = Array.from(
1564
+ new Set(keys.filter((key) => typeof key === "string" && key.length > 0))
1565
+ );
1566
+ if (normalized.length === 0) return null;
1567
+ return encodeURIComponent(JSON.stringify(normalized));
1568
+ }
1569
+ __name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
1517
1570
  function decodeFarmCacheInvalidations(value) {
1518
1571
  if (!value) return [];
1519
1572
  try {
@@ -2193,6 +2246,31 @@ function stableSerialize(value, seen = /* @__PURE__ */ new WeakSet()) {
2193
2246
  __name(stableSerialize, "stableSerialize");
2194
2247
 
2195
2248
  // src/client-cache.ts
2249
+ var invalidationTrackers = /* @__PURE__ */ new WeakMap();
2250
+ function trackFarmClientCacheInvalidations(cache) {
2251
+ let trackers = invalidationTrackers.get(cache);
2252
+ if (!trackers) {
2253
+ trackers = /* @__PURE__ */ new Set();
2254
+ invalidationTrackers.set(cache, trackers);
2255
+ }
2256
+ const keys = /* @__PURE__ */ new Set();
2257
+ trackers.add(keys);
2258
+ return {
2259
+ has(key) {
2260
+ const resolved = cache.resolveKey(key);
2261
+ for (const invalidated of keys) {
2262
+ if (cache.resolveKey(invalidated) === resolved) return true;
2263
+ }
2264
+ return false;
2265
+ },
2266
+ dispose() {
2267
+ if (!trackers.delete(keys)) return;
2268
+ keys.clear();
2269
+ if (trackers.size === 0) invalidationTrackers.delete(cache);
2270
+ }
2271
+ };
2272
+ }
2273
+ __name(trackFarmClientCacheInvalidations, "trackFarmClientCacheInvalidations");
2196
2274
  var cacheFinalizer = typeof FinalizationRegistry === "function" ? new FinalizationRegistry((unsubscribe) => unsubscribe()) : void 0;
2197
2275
  function subscribeWeakCache(reference) {
2198
2276
  const unsubscribe = subscribeFarmCacheInvalidation((key) => {
@@ -2208,6 +2286,7 @@ function subscribeWeakCache(reference) {
2208
2286
  return dispose;
2209
2287
  }
2210
2288
  __name(subscribeWeakCache, "subscribeWeakCache");
2289
+ var DEFAULT_GC_SWEEP_INTERVAL_MS = 3e4;
2211
2290
  var _FarmClientDataCache = class _FarmClientDataCache {
2212
2291
  constructor(options = {}) {
2213
2292
  this.entries = /* @__PURE__ */ new Map();
@@ -2215,6 +2294,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2215
2294
  this.invalidatedAt = /* @__PURE__ */ new Map();
2216
2295
  this.listeners = /* @__PURE__ */ new Map();
2217
2296
  this.inflight = /* @__PURE__ */ new Map();
2297
+ this.gcSweepIntervalMs = options.gcSweepIntervalMs ?? DEFAULT_GC_SWEEP_INTERVAL_MS;
2218
2298
  if (options.subscribeToInvalidation !== false) {
2219
2299
  if (typeof WeakRef === "function") {
2220
2300
  const reference = new WeakRef(this);
@@ -2231,6 +2311,10 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2231
2311
  get size() {
2232
2312
  return this.entries.size;
2233
2313
  }
2314
+ /** @internal Attach or detach the persistence engine's observation sink. */
2315
+ attachPersistence(sink) {
2316
+ this.persistence = sink;
2317
+ }
2234
2318
  resolveKey(key) {
2235
2319
  let resolved = key;
2236
2320
  const seen = /* @__PURE__ */ new Set();
@@ -2246,6 +2330,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2246
2330
  if (!entry) return void 0;
2247
2331
  if (entry.gcAt !== void 0 && now2 >= entry.gcAt) {
2248
2332
  this.entries.delete(resolved);
2333
+ this.persistence?.onDelete(resolved);
2249
2334
  this.emit(resolved);
2250
2335
  return void 0;
2251
2336
  }
@@ -2259,6 +2344,8 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2259
2344
  this.invalidatedAt.delete(resolved);
2260
2345
  }
2261
2346
  this.entries.set(resolved, nextEntry);
2347
+ if (nextEntry.gcAt !== void 0) this.scheduleGcSweep();
2348
+ this.persistence?.onSet(resolved, nextEntry);
2262
2349
  this.emit(resolved);
2263
2350
  return this;
2264
2351
  }
@@ -2266,6 +2353,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2266
2353
  const resolved = this.resolveKey(key);
2267
2354
  const deleted = this.entries.delete(resolved);
2268
2355
  this.inflight.delete(resolved);
2356
+ if (deleted) this.persistence?.onDelete(resolved);
2269
2357
  this.emit(resolved);
2270
2358
  return deleted;
2271
2359
  }
@@ -2275,11 +2363,16 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2275
2363
  this.aliases.clear();
2276
2364
  this.invalidatedAt.clear();
2277
2365
  this.inflight.clear();
2366
+ this.persistence?.onClear();
2278
2367
  for (const key of keys) this.emit(key);
2279
2368
  }
2280
2369
  dispose() {
2281
2370
  this.unsubscribeInvalidation?.();
2282
2371
  this.unsubscribeInvalidation = void 0;
2372
+ if (this.gcTimer !== void 0) {
2373
+ clearTimeout(this.gcTimer);
2374
+ this.gcTimer = void 0;
2375
+ }
2283
2376
  this.clear();
2284
2377
  }
2285
2378
  isStale(key, now2 = Date.now()) {
@@ -2288,6 +2381,7 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2288
2381
  }
2289
2382
  invalidate(key, now2 = Date.now()) {
2290
2383
  const resolved = this.resolveKey(key);
2384
+ for (const keys of invalidationTrackers.get(this) ?? []) keys.add(resolved);
2291
2385
  this.invalidatedAt.set(resolved, now2);
2292
2386
  const entry = this.entries.get(resolved);
2293
2387
  if (entry) {
@@ -2307,8 +2401,9 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2307
2401
  const resolvedInvalidatedAt = this.invalidatedAt.get(resolved);
2308
2402
  if (aliasEntry && !this.entries.has(resolved)) {
2309
2403
  this.entries.set(resolved, aliasEntry);
2404
+ this.persistence?.onSet(resolved, aliasEntry);
2310
2405
  }
2311
- this.entries.delete(alias);
2406
+ if (this.entries.delete(alias)) this.persistence?.onDelete(alias);
2312
2407
  this.invalidatedAt.delete(alias);
2313
2408
  const invalidatedAt = [aliasInvalidatedAt, resolvedInvalidatedAt].reduce(
2314
2409
  (latest, value) => value === void 0 ? latest : latest === void 0 ? value : Math.max(latest, value),
@@ -2348,7 +2443,9 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2348
2443
  listeners2.add(listener);
2349
2444
  return () => {
2350
2445
  listeners2.delete(listener);
2351
- if (listeners2.size === 0) this.listeners.delete(key);
2446
+ if (listeners2.size === 0 && this.listeners.get(key) === listeners2) {
2447
+ this.listeners.delete(key);
2448
+ }
2352
2449
  };
2353
2450
  }
2354
2451
  getInflight(key) {
@@ -2360,6 +2457,30 @@ var _FarmClientDataCache = class _FarmClientDataCache {
2360
2457
  deleteInflight(key) {
2361
2458
  this.inflight.delete(this.resolveKey(key));
2362
2459
  }
2460
+ scheduleGcSweep() {
2461
+ if (this.gcSweepIntervalMs === false || this.gcTimer !== void 0) return;
2462
+ const timer = setTimeout(() => {
2463
+ this.gcTimer = void 0;
2464
+ this.sweepExpiredEntries();
2465
+ }, this.gcSweepIntervalMs);
2466
+ timer.unref?.();
2467
+ this.gcTimer = timer;
2468
+ }
2469
+ sweepExpiredEntries(now2 = Date.now()) {
2470
+ const watched = /* @__PURE__ */ new Set();
2471
+ for (const key of this.listeners.keys()) watched.add(this.resolveKey(key));
2472
+ let remaining = false;
2473
+ for (const [key, entry] of this.entries) {
2474
+ if (entry.gcAt === void 0) continue;
2475
+ if (now2 < entry.gcAt || entry.fetching || this.inflight.has(key) || watched.has(key)) {
2476
+ remaining = true;
2477
+ continue;
2478
+ }
2479
+ this.entries.delete(key);
2480
+ this.persistence?.onDelete(key);
2481
+ }
2482
+ if (remaining) this.scheduleGcSweep();
2483
+ }
2363
2484
  emit(key, event) {
2364
2485
  this.notifyListeners(key, event);
2365
2486
  for (const [alias, target] of this.aliases) {
@@ -2764,6 +2885,7 @@ function readJSONStream(response) {
2764
2885
  const decoder = new TextDecoder();
2765
2886
  let buffer = "";
2766
2887
  let completed = false;
2888
+ let cancelled = false;
2767
2889
  let claimed = false;
2768
2890
  let released = false;
2769
2891
  const releaseReader = /* @__PURE__ */ __name(() => {
@@ -2783,39 +2905,54 @@ function readJSONStream(response) {
2783
2905
  throw error;
2784
2906
  }
2785
2907
  }, "parseLine");
2786
- const iterator = {
2787
- async next() {
2788
- while (true) {
2789
- const lineEnd = buffer.indexOf("\n");
2790
- if (lineEnd >= 0) {
2791
- const line = buffer.slice(0, lineEnd).trim();
2792
- buffer = buffer.slice(lineEnd + 1);
2793
- if (!line) continue;
2794
- return { done: false, value: await parseLine(line) };
2795
- }
2796
- if (completed) {
2797
- const line = buffer.trim();
2798
- buffer = "";
2799
- if (!line) {
2800
- releaseReader();
2801
- return { done: true, value: void 0 };
2802
- }
2803
- return { done: false, value: await parseLine(line) };
2804
- }
2805
- let chunk;
2806
- try {
2807
- chunk = await reader.read();
2808
- } catch (error) {
2809
- completed = true;
2810
- buffer = "";
2908
+ const readNext = /* @__PURE__ */ __name(async () => {
2909
+ while (true) {
2910
+ if (cancelled) return { done: true, value: void 0 };
2911
+ const lineEnd = buffer.indexOf("\n");
2912
+ if (lineEnd >= 0) {
2913
+ const line = buffer.slice(0, lineEnd).trim();
2914
+ buffer = buffer.slice(lineEnd + 1);
2915
+ if (!line) continue;
2916
+ return { done: false, value: await parseLine(line) };
2917
+ }
2918
+ if (completed) {
2919
+ const line = buffer.trim();
2920
+ buffer = "";
2921
+ if (!line) {
2811
2922
  releaseReader();
2812
- throw error;
2923
+ return { done: true, value: void 0 };
2813
2924
  }
2814
- completed = chunk.done;
2815
- buffer += decoder.decode(chunk.value, { stream: !chunk.done });
2925
+ return { done: false, value: await parseLine(line) };
2816
2926
  }
2927
+ let chunk;
2928
+ try {
2929
+ chunk = await reader.read();
2930
+ } catch (error) {
2931
+ if (cancelled) return { done: true, value: void 0 };
2932
+ completed = true;
2933
+ buffer = "";
2934
+ releaseReader();
2935
+ throw error;
2936
+ }
2937
+ if (cancelled) return { done: true, value: void 0 };
2938
+ completed = chunk.done;
2939
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
2940
+ }
2941
+ }, "readNext");
2942
+ let readQueue = Promise.resolve();
2943
+ const iterator = {
2944
+ next() {
2945
+ const result = readQueue.then(readNext);
2946
+ readQueue = result.then(
2947
+ () => {
2948
+ },
2949
+ () => {
2950
+ }
2951
+ );
2952
+ return result;
2817
2953
  },
2818
2954
  async return() {
2955
+ cancelled = true;
2819
2956
  completed = true;
2820
2957
  buffer = "";
2821
2958
  if (!released) {
@@ -2831,6 +2968,7 @@ function readJSONStream(response) {
2831
2968
  return {
2832
2969
  response,
2833
2970
  async cancel(reason) {
2971
+ cancelled = true;
2834
2972
  completed = true;
2835
2973
  buffer = "";
2836
2974
  if (!released) {
@@ -2980,69 +3118,6 @@ function createAPIClientRuntime(options = {}, transport) {
2980
3118
  let scopedRequestState;
2981
3119
  const routeMeta = transport?.routeMeta ?? /* @__PURE__ */ new WeakMap();
2982
3120
  let requestCounter = 0;
2983
- const applyOptimisticLayer = /* @__PURE__ */ __name((entry, layer) => {
2984
- let data = entry?.data;
2985
- for (const updater of layer.updaters) data = updater(data);
2986
- return {
2987
- data,
2988
- updatedAt: layer.updatedAt,
2989
- staleAt: entry?.staleAt ?? layer.staleAt,
2990
- gcAt: entry?.gcAt ?? layer.gcAt,
2991
- invalidatedAt: entry?.invalidatedAt
2992
- };
2993
- }, "applyOptimisticLayer");
2994
- const storeOptimisticEntry = /* @__PURE__ */ __name((cacheState, key, stack, entry) => {
2995
- if (!entry) {
2996
- cacheState.delete(key);
2997
- stack.renderedEntry = void 0;
2998
- return;
2999
- }
3000
- cacheState.set(key, entry);
3001
- if (stack.invalidatedAt !== void 0) {
3002
- cacheState.invalidate(key, stack.invalidatedAt);
3003
- }
3004
- stack.renderedEntry = cacheState.get(key);
3005
- }, "storeOptimisticEntry");
3006
- const reconcileOptimisticInvalidation = /* @__PURE__ */ __name((cacheState, key, stack) => {
3007
- const current = cacheState.get(key);
3008
- const rendered = stack.renderedEntry;
3009
- if (current === rendered) return true;
3010
- if (!current || !rendered || current.data !== rendered.data || current.updatedAt !== rendered.updatedAt || current.gcAt !== rendered.gcAt || current.status !== rendered.status || current.error !== rendered.error || current.fetching !== rendered.fetching || current.staleAt !== 0 || current.invalidatedAt === void 0) {
3011
- return false;
3012
- }
3013
- stack.invalidatedAt = current.invalidatedAt;
3014
- stack.renderedEntry = current;
3015
- return true;
3016
- }, "reconcileOptimisticInvalidation");
3017
- const renderOptimisticStack = /* @__PURE__ */ __name((cacheState, key, stack) => {
3018
- let entry = stack.entry ? { ...stack.entry } : void 0;
3019
- for (const layer of stack.layers) entry = applyOptimisticLayer(entry, layer);
3020
- storeOptimisticEntry(cacheState, key, stack, entry);
3021
- }, "renderOptimisticStack");
3022
- const settleOptimisticUpdates = /* @__PURE__ */ __name((cacheState, optimisticState, snapshots, outcome) => {
3023
- const settledKeys = [];
3024
- for (const snapshot of snapshots) {
3025
- const stack = optimisticState.get(snapshot.key);
3026
- if (stack !== snapshot.stack) continue;
3027
- if (!reconcileOptimisticInvalidation(cacheState, snapshot.key, stack)) {
3028
- optimisticState.delete(snapshot.key);
3029
- continue;
3030
- }
3031
- if (outcome === "rollback") {
3032
- stack.layers = stack.layers.filter((layer) => layer !== snapshot.layer);
3033
- } else {
3034
- snapshot.layer.committed = true;
3035
- if (outcome === "invalidate") stack.invalidatedAt = Date.now();
3036
- }
3037
- while (stack.layers[0]?.committed) {
3038
- stack.entry = applyOptimisticLayer(stack.entry, stack.layers.shift());
3039
- }
3040
- renderOptimisticStack(cacheState, snapshot.key, stack);
3041
- if (stack.layers.length === 0) optimisticState.delete(snapshot.key);
3042
- settledKeys.push(snapshot.key);
3043
- }
3044
- return settledKeys;
3045
- }, "settleOptimisticUpdates");
3046
3121
  const fetchClient = /* @__PURE__ */ __name(async (path, requestOptions, defaultHeaders, cancellation) => {
3047
3122
  const url = resolveFarmAPIRequestURL(path, baseURL);
3048
3123
  const method = String(requestOptions.method || "GET").toUpperCase();
@@ -3275,6 +3350,9 @@ function createAPIClientRuntime(options = {}, transport) {
3275
3350
  const executeNetwork = /* @__PURE__ */ __name(async (opts) => {
3276
3351
  const release = cancellation.hold();
3277
3352
  let unsubscribeInvalidation;
3353
+ let readOwners;
3354
+ let readOwner;
3355
+ const resolvedCacheKey = cacheState.resolveKey(cacheKey);
3278
3356
  try {
3279
3357
  const dedupeMs = cacheOptions?.dedupeMs ?? 0;
3280
3358
  const inflight = inflightState.get(cacheKey);
@@ -3298,6 +3376,9 @@ function createAPIClientRuntime(options = {}, transport) {
3298
3376
  }
3299
3377
  let invalidatedDuringRequest = false;
3300
3378
  if (isCacheEnabled) {
3379
+ readOwners = getCacheReadOwners(cacheState);
3380
+ readOwner = {};
3381
+ readOwners.set(resolvedCacheKey, readOwner);
3301
3382
  unsubscribeInvalidation = cacheState.subscribe(cacheKey, (event) => {
3302
3383
  if (event === "invalidate") invalidatedDuringRequest = true;
3303
3384
  });
@@ -3405,15 +3486,27 @@ function createAPIClientRuntime(options = {}, transport) {
3405
3486
  inflightState.set(cacheKey, inflightEntry);
3406
3487
  try {
3407
3488
  const result2 = await promise;
3408
- if (inflightState.get(cacheKey) === inflightEntry && !invalidatedDuringRequest && !result2.error && isCacheEnabled && !isFarmAPIStream(result2.data)) {
3489
+ if (inflightState.get(cacheKey) === inflightEntry && readOwners?.get(resolvedCacheKey) === readOwner && !invalidatedDuringRequest && !result2.error && isCacheEnabled && !isFarmAPIStream(result2.data)) {
3409
3490
  const updatedAt = Date.now();
3410
- cacheState.set(cacheKey, {
3491
+ const cached = {
3411
3492
  data: result2.data,
3412
3493
  updatedAt,
3413
3494
  staleAt: updatedAt + staleTime,
3414
3495
  gcAt: getGcAt(updatedAt, cacheOptions?.gcTime),
3415
- invalidatedAt: void 0
3416
- });
3496
+ invalidatedAt: void 0,
3497
+ persist: cacheOptions?.persist === true ? true : void 0,
3498
+ [API_CACHE_REFETCH]: createCacheRefetch(
3499
+ request,
3500
+ path,
3501
+ method,
3502
+ input,
3503
+ cacheKey,
3504
+ cacheOptions,
3505
+ clientOptions,
3506
+ options.onError
3507
+ )
3508
+ };
3509
+ cacheState.set(cacheKey, cached);
3417
3510
  }
3418
3511
  if (result2.error) {
3419
3512
  emitStatus("error", { error: result2.error, isBackground: opts?.isBackground });
@@ -3441,6 +3534,9 @@ function createAPIClientRuntime(options = {}, transport) {
3441
3534
  }
3442
3535
  }
3443
3536
  } finally {
3537
+ if (readOwner && readOwners?.get(resolvedCacheKey) === readOwner) {
3538
+ readOwners.delete(resolvedCacheKey);
3539
+ }
3444
3540
  unsubscribeInvalidation?.();
3445
3541
  release();
3446
3542
  }
@@ -3451,6 +3547,7 @@ function createAPIClientRuntime(options = {}, transport) {
3451
3547
  targets: clientOptions.invalidate.targets,
3452
3548
  refetch: clientOptions.invalidate.refetch ?? false
3453
3549
  };
3550
+ const refetches = /* @__PURE__ */ new Set();
3454
3551
  for (const target of invalidateOptions.targets) {
3455
3552
  const targetKey = resolveTargetKey(
3456
3553
  routeMeta,
@@ -3462,20 +3559,22 @@ function createAPIClientRuntime(options = {}, transport) {
3462
3559
  );
3463
3560
  if (!targetKey) continue;
3464
3561
  const existing = cacheState.get(targetKey);
3562
+ const invalidatedAt = Date.now();
3563
+ cacheState.invalidate(targetKey, invalidatedAt);
3465
3564
  if (existing) {
3466
- const invalidatedAt = Date.now();
3467
3565
  const stack = optimisticState.get(targetKey);
3468
- cacheState.invalidate(targetKey, invalidatedAt);
3469
3566
  if (stack?.renderedEntry === existing) {
3470
3567
  stack.invalidatedAt = invalidatedAt;
3471
3568
  stack.renderedEntry = cacheState.get(targetKey);
3472
3569
  }
3473
3570
  }
3474
3571
  emitStatus("invalidated", { key: targetKey });
3475
- if (invalidateOptions.refetch && existing && targetKey === cacheKey) {
3476
- void executeNetwork({ isBackground: true, callCallbacks: false });
3572
+ const refetch = existing?.[API_CACHE_REFETCH];
3573
+ if (invalidateOptions.refetch && refetch) {
3574
+ refetches.add(refetch);
3477
3575
  }
3478
3576
  }
3577
+ for (const refetch of refetches) refetch();
3479
3578
  }, "invalidateTargets");
3480
3579
  const optimisticSnapshots = requestContextError ? [] : applyOptimisticUpdates();
3481
3580
  if (isCacheEnabled && !requestContextError && !cancellation.signal?.aborted) {
@@ -3709,7 +3808,31 @@ function createServerAPIClient(endpoints, options = {}) {
3709
3808
  return endpoints;
3710
3809
  }
3711
3810
  __name(createServerAPIClient, "createServerAPIClient");
3811
+ var API_CACHE_REFETCH = /* @__PURE__ */ Symbol.for("farm.api.cache-refetch");
3812
+ function createCacheRefetch(request, path, method, input, key, cache, options, onError) {
3813
+ const readOptions = {
3814
+ cache: { ...cache, key, policy: "network-only", dedupeMs: 0 },
3815
+ retry: options?.retry,
3816
+ timeoutMs: options?.timeoutMs
3817
+ };
3818
+ return () => {
3819
+ void request(path, method, input, readOptions).catch((error) => {
3820
+ notifyClientObserver(onError, [normalizeError(error)]);
3821
+ });
3822
+ };
3823
+ }
3824
+ __name(createCacheRefetch, "createCacheRefetch");
3712
3825
  var optimisticStates = /* @__PURE__ */ new WeakMap();
3826
+ var cacheReadOwners = /* @__PURE__ */ new WeakMap();
3827
+ function getCacheReadOwners(cache) {
3828
+ let owners = cacheReadOwners.get(cache);
3829
+ if (!owners) {
3830
+ owners = /* @__PURE__ */ new Map();
3831
+ cacheReadOwners.set(cache, owners);
3832
+ }
3833
+ return owners;
3834
+ }
3835
+ __name(getCacheReadOwners, "getCacheReadOwners");
3713
3836
  function getOptimisticState(cache) {
3714
3837
  let state = optimisticStates.get(cache);
3715
3838
  if (!state) {
@@ -3719,6 +3842,151 @@ function getOptimisticState(cache) {
3719
3842
  return state;
3720
3843
  }
3721
3844
  __name(getOptimisticState, "getOptimisticState");
3845
+ function applyOptimisticLayer(entry, layer) {
3846
+ let data = entry?.data;
3847
+ for (const updater of layer.updaters) data = updater(data);
3848
+ return {
3849
+ data,
3850
+ updatedAt: layer.updatedAt,
3851
+ staleAt: entry?.staleAt ?? layer.staleAt,
3852
+ gcAt: entry?.gcAt ?? layer.gcAt,
3853
+ invalidatedAt: entry?.invalidatedAt,
3854
+ [API_CACHE_REFETCH]: entry?.[API_CACHE_REFETCH]
3855
+ };
3856
+ }
3857
+ __name(applyOptimisticLayer, "applyOptimisticLayer");
3858
+ function storeOptimisticEntry(cacheState, key, stack, entry) {
3859
+ if (!entry) {
3860
+ cacheState.delete(key);
3861
+ stack.renderedEntry = void 0;
3862
+ return;
3863
+ }
3864
+ cacheState.set(key, entry);
3865
+ if (stack.invalidatedAt !== void 0) {
3866
+ cacheState.invalidate(key, stack.invalidatedAt);
3867
+ }
3868
+ stack.renderedEntry = cacheState.get(key);
3869
+ }
3870
+ __name(storeOptimisticEntry, "storeOptimisticEntry");
3871
+ function reconcileOptimisticInvalidation(cacheState, key, stack) {
3872
+ const current = cacheState.get(key);
3873
+ const rendered = stack.renderedEntry;
3874
+ if (current === rendered) return true;
3875
+ if (!current || !rendered || current.data !== rendered.data || current.updatedAt !== rendered.updatedAt || current.gcAt !== rendered.gcAt || current.status !== rendered.status || current.error !== rendered.error || current.fetching !== rendered.fetching || current.staleAt !== 0 || current.invalidatedAt === void 0) {
3876
+ return false;
3877
+ }
3878
+ stack.invalidatedAt = current.invalidatedAt;
3879
+ stack.renderedEntry = current;
3880
+ return true;
3881
+ }
3882
+ __name(reconcileOptimisticInvalidation, "reconcileOptimisticInvalidation");
3883
+ function renderOptimisticStack(cacheState, key, stack) {
3884
+ let entry = stack.entry ? { ...stack.entry } : void 0;
3885
+ for (const layer of stack.layers) entry = applyOptimisticLayer(entry, layer);
3886
+ storeOptimisticEntry(cacheState, key, stack, entry);
3887
+ }
3888
+ __name(renderOptimisticStack, "renderOptimisticStack");
3889
+ function settleOptimisticUpdates(cacheState, optimisticState, snapshots, outcome) {
3890
+ const settledKeys = [];
3891
+ for (const snapshot of snapshots) {
3892
+ const stack = optimisticState.get(snapshot.key);
3893
+ if (stack !== snapshot.stack) continue;
3894
+ if (!reconcileOptimisticInvalidation(cacheState, snapshot.key, stack)) {
3895
+ optimisticState.delete(snapshot.key);
3896
+ continue;
3897
+ }
3898
+ if (outcome === "rollback") {
3899
+ stack.layers = stack.layers.filter((layer) => layer !== snapshot.layer);
3900
+ } else {
3901
+ snapshot.layer.committed = true;
3902
+ if (outcome === "invalidate") stack.invalidatedAt = Date.now();
3903
+ }
3904
+ while (stack.layers[0]?.committed) {
3905
+ stack.entry = applyOptimisticLayer(stack.entry, stack.layers.shift());
3906
+ }
3907
+ renderOptimisticStack(cacheState, snapshot.key, stack);
3908
+ if (stack.layers.length === 0) optimisticState.delete(snapshot.key);
3909
+ settledKeys.push(snapshot.key);
3910
+ }
3911
+ return settledKeys;
3912
+ }
3913
+ __name(settleOptimisticUpdates, "settleOptimisticUpdates");
3914
+ function applyServerFnOptimisticUpdates(updates, now2 = Date.now()) {
3915
+ const cacheState = getFarmClientDataCache();
3916
+ const optimisticState = getOptimisticState(cacheState);
3917
+ const snapshots = /* @__PURE__ */ new Map();
3918
+ for (const update of updates) {
3919
+ if (update.length !== 2) continue;
3920
+ const [target, updater] = update;
3921
+ if (typeof updater !== "function") continue;
3922
+ const targetKey = typeof target === "string" || Array.isArray(target) ? normalizeFarmClientCacheKey(target) : null;
3923
+ if (!targetKey) continue;
3924
+ const targetEntry = getValidCacheEntry(cacheState, targetKey, now2);
3925
+ const currentEntry = cacheState.get(targetKey);
3926
+ let stack = optimisticState.get(targetKey);
3927
+ if (stack && !reconcileOptimisticInvalidation(cacheState, targetKey, stack)) {
3928
+ stack = void 0;
3929
+ }
3930
+ if (!stack) {
3931
+ stack = {
3932
+ entry: targetEntry ? { ...targetEntry } : void 0,
3933
+ layers: [],
3934
+ renderedEntry: currentEntry
3935
+ };
3936
+ optimisticState.set(targetKey, stack);
3937
+ }
3938
+ let snapshot = snapshots.get(targetKey);
3939
+ if (!snapshot) {
3940
+ const previousEntry = stack.layers.length === 0 ? stack.entry : stack.renderedEntry;
3941
+ const layer = {
3942
+ updaters: [],
3943
+ updatedAt: now2,
3944
+ // A server function has no cache policy of its own; preserve the
3945
+ // target read's freshness metadata when it exists.
3946
+ staleAt: targetEntry?.staleAt ?? now2,
3947
+ gcAt: targetEntry?.gcAt
3948
+ };
3949
+ stack.layers.push(layer);
3950
+ snapshot = { key: targetKey, stack, layer };
3951
+ snapshots.set(targetKey, snapshot);
3952
+ snapshot.layer.updaters.push(updater);
3953
+ const nextEntry2 = applyOptimisticLayer(previousEntry, {
3954
+ ...snapshot.layer,
3955
+ updaters: [updater]
3956
+ });
3957
+ storeOptimisticEntry(cacheState, targetKey, stack, nextEntry2);
3958
+ continue;
3959
+ }
3960
+ snapshot.layer.updaters.push(updater);
3961
+ const nextEntry = applyOptimisticLayer(stack.renderedEntry, {
3962
+ ...snapshot.layer,
3963
+ updaters: [updater]
3964
+ });
3965
+ storeOptimisticEntry(cacheState, targetKey, stack, nextEntry);
3966
+ }
3967
+ return Array.from(snapshots.values());
3968
+ }
3969
+ __name(applyServerFnOptimisticUpdates, "applyServerFnOptimisticUpdates");
3970
+ function settleServerFnOptimisticUpdates(snapshots, outcome) {
3971
+ if (snapshots.length === 0) return;
3972
+ const cacheState = getFarmClientDataCache();
3973
+ settleOptimisticUpdates(cacheState, getOptimisticState(cacheState), snapshots, outcome);
3974
+ }
3975
+ __name(settleServerFnOptimisticUpdates, "settleServerFnOptimisticUpdates");
3976
+ function resolveServerFnInvalidateTargets(invalidate) {
3977
+ const targets = Array.isArray(invalidate) ? invalidate : invalidate.targets;
3978
+ const keys = [];
3979
+ for (const target of targets) {
3980
+ if (typeof target === "string" || Array.isArray(target)) {
3981
+ if (Array.isArray(target) && typeof target[0] === "function") continue;
3982
+ keys.push(normalizeFarmClientCacheKey(target));
3983
+ } else if (target && typeof target === "object" && "key" in target) {
3984
+ keys.push(normalizeFarmClientCacheKey(target.key));
3985
+ }
3986
+ }
3987
+ return keys;
3988
+ }
3989
+ __name(resolveServerFnInvalidateTargets, "resolveServerFnInvalidateTargets");
3722
3990
  function buildCacheKey(method, path, input, baseURL, defaultHeaders) {
3723
3991
  const keyInput = input && typeof input === "object" ? {
3724
3992
  query: input.query,
@@ -3897,65 +4165,176 @@ __name(readEndpointErrorEnvelope, "readEndpointErrorEnvelope");
3897
4165
 
3898
4166
  // src/mutation-client.ts
3899
4167
  var import_react = require("react");
4168
+
4169
+ // src/client-network-status.ts
4170
+ function isNavigatorOnline() {
4171
+ if (typeof navigator === "undefined" || typeof navigator.onLine !== "boolean") return true;
4172
+ return navigator.onLine;
4173
+ }
4174
+ __name(isNavigatorOnline, "isNavigatorOnline");
4175
+ function subscribeOnline(listener) {
4176
+ if (typeof window === "undefined") return () => {
4177
+ };
4178
+ window.addEventListener("online", listener);
4179
+ return () => window.removeEventListener("online", listener);
4180
+ }
4181
+ __name(subscribeOnline, "subscribeOnline");
4182
+
4183
+ // src/mutation-retry.ts
4184
+ async function invokeMutationWithRetry(invoke, retry, shouldContinue) {
4185
+ const maxRetries = Math.max(0, retry?.count ?? 0);
4186
+ let attempt = 0;
4187
+ while (true) {
4188
+ try {
4189
+ return await invoke();
4190
+ } catch (error) {
4191
+ if (attempt >= maxRetries || !shouldContinue()) throw error;
4192
+ attempt += 1;
4193
+ const delay2 = typeof retry?.delay === "function" ? retry.delay(attempt) : retry?.delay ?? 0;
4194
+ if (delay2 > 0) {
4195
+ await new Promise((resolve) => setTimeout(resolve, delay2));
4196
+ if (!shouldContinue()) throw error;
4197
+ }
4198
+ }
4199
+ }
4200
+ }
4201
+ __name(invokeMutationWithRetry, "invokeMutationWithRetry");
4202
+
4203
+ // src/mutation-client.ts
3900
4204
  function useMutation(target, options = {}) {
4205
+ return useMutationLifecycle(target, options).mutation;
4206
+ }
4207
+ __name(useMutation, "useMutation");
4208
+ function useMutationLifecycle(target, options = {}) {
3901
4209
  const initialData = options.initialData ?? null;
3902
4210
  const optionsRef = (0, import_react.useRef)(options);
3903
4211
  const targetRef = (0, import_react.useRef)(target);
3904
4212
  const requestIdRef = (0, import_react.useRef)(0);
4213
+ const lastResetIdRef = (0, import_react.useRef)(0);
3905
4214
  const initialState = {
3906
4215
  pendingCount: 0,
4216
+ pausedCount: 0,
3907
4217
  status: "idle",
3908
4218
  data: initialData,
3909
4219
  error: null,
3910
4220
  variables: void 0
3911
4221
  };
3912
4222
  const stateRef = (0, import_react.useRef)(initialState);
4223
+ const resetWakersRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
3913
4224
  const [state, setState] = (0, import_react.useState)(initialState);
3914
4225
  optionsRef.current = options;
3915
4226
  targetRef.current = target;
3916
4227
  const setMutationState = (0, import_react.useCallback)(
3917
4228
  (value) => {
3918
- setState((current) => {
3919
- const next = typeof value === "function" ? value(current) : value;
3920
- stateRef.current = next;
3921
- return next;
3922
- });
4229
+ const next = typeof value === "function" ? value(stateRef.current) : value;
4230
+ stateRef.current = next;
4231
+ setState(next);
3923
4232
  },
3924
4233
  []
3925
4234
  );
3926
- const mutateAsync = (0, import_react.useCallback)(
3927
- async (variables) => {
4235
+ const waitForReconnect = (0, import_react.useCallback)(
4236
+ async (requestId) => {
4237
+ while (!isNavigatorOnline()) {
4238
+ if (requestId < lastResetIdRef.current) return;
4239
+ setMutationState((current) => ({ ...current, pausedCount: current.pausedCount + 1 }));
4240
+ try {
4241
+ await new Promise((resolve) => {
4242
+ const wake = /* @__PURE__ */ __name(() => {
4243
+ unsubscribe();
4244
+ resetWakersRef.current.delete(wake);
4245
+ resolve();
4246
+ }, "wake");
4247
+ const unsubscribe = subscribeOnline(wake);
4248
+ resetWakersRef.current.add(wake);
4249
+ });
4250
+ } finally {
4251
+ setMutationState((current) => ({
4252
+ ...current,
4253
+ pausedCount: Math.max(0, current.pausedCount - 1)
4254
+ }));
4255
+ }
4256
+ }
4257
+ },
4258
+ [setMutationState]
4259
+ );
4260
+ const mutatePreparedAsync = (0, import_react.useCallback)(
4261
+ async (prepare) => {
3928
4262
  const requestId = ++requestIdRef.current;
3929
4263
  const currentOptions = optionsRef.current;
3930
4264
  const previousData = stateRef.current.data;
3931
- const optimisticData = currentOptions.optimistic?.({
3932
- variables,
3933
- current: previousData
3934
- });
4265
+ let variables;
4266
+ let preparationFailed = false;
4267
+ let preparationError;
4268
+ try {
4269
+ variables = prepare();
4270
+ } catch (error) {
4271
+ preparationFailed = true;
4272
+ preparationError = error;
4273
+ }
4274
+ const optimisticData = preparationFailed ? void 0 : currentOptions.optimistic?.({ variables, current: previousData });
3935
4275
  const hasOptimisticData = optimisticData !== void 0;
3936
- setMutationState((current) => ({
3937
- pendingCount: current.pendingCount + 1,
3938
- status: "pending",
3939
- data: hasOptimisticData ? optimisticData : currentOptions.resetOnMutate === false ? current.data : null,
3940
- error: null,
3941
- variables
3942
- }));
4276
+ setMutationState((current) => {
4277
+ if (requestId < lastResetIdRef.current) return current;
4278
+ const pendingCount = current.pendingCount + 1;
4279
+ if (requestId !== requestIdRef.current) return { ...current, pendingCount };
4280
+ return {
4281
+ pendingCount,
4282
+ pausedCount: current.pausedCount,
4283
+ status: "pending",
4284
+ data: hasOptimisticData ? optimisticData : currentOptions.resetOnMutate === false ? current.data : null,
4285
+ error: null,
4286
+ variables
4287
+ };
4288
+ });
4289
+ const mutationTarget = targetRef.current;
4290
+ const isAPITarget = isAPIRouteRef(mutationTarget);
4291
+ const sharedOptimistic = !preparationFailed && !isAPITarget ? currentOptions.request?.optimistic : void 0;
4292
+ const sharedSnapshots = sharedOptimistic?.update?.length ? applyServerFnOptimisticUpdates(sharedOptimistic.update) : [];
3943
4293
  try {
3944
- const mutationTarget = targetRef.current;
3945
- const rawResult = isAPIRouteRef(mutationTarget) ? await mutationTarget(variables, currentOptions.request) : await mutationTarget(variables);
3946
- const data = unwrapMutationResult(rawResult, isAPIRouteRef(mutationTarget));
4294
+ if (preparationFailed) throw preparationError;
4295
+ let data;
4296
+ while (true) {
4297
+ if (currentOptions.networkMode === "online") {
4298
+ await waitForReconnect(requestId);
4299
+ if (requestId < lastResetIdRef.current) {
4300
+ throw new Error("Mutation reset while waiting for reconnection");
4301
+ }
4302
+ }
4303
+ try {
4304
+ const rawResult = isAPITarget ? await mutationTarget(variables, currentOptions.request) : await invokeMutationWithRetry(
4305
+ () => targetRef.current(variables),
4306
+ currentOptions.request?.retry,
4307
+ // A reset disowns this submission; stop scheduling retries then.
4308
+ () => requestId >= lastResetIdRef.current
4309
+ );
4310
+ data = unwrapMutationResult(rawResult, isAPITarget);
4311
+ break;
4312
+ } catch (cause) {
4313
+ if (currentOptions.networkMode === "online" && !isNavigatorOnline() && requestId >= lastResetIdRef.current) {
4314
+ continue;
4315
+ }
4316
+ throw cause;
4317
+ }
4318
+ }
4319
+ settleServerFnOptimisticUpdates(sharedSnapshots, "commit");
4320
+ if (!isAPITarget && currentOptions.request?.invalidate) {
4321
+ for (const key of resolveServerFnInvalidateTargets(currentOptions.request.invalidate)) {
4322
+ notifyFarmCacheInvalidation(key);
4323
+ }
4324
+ }
3947
4325
  const isLatestRequest = requestId === requestIdRef.current;
3948
4326
  setMutationState((current) => {
4327
+ if (requestId < lastResetIdRef.current) return current;
3949
4328
  const pendingCount = Math.max(0, current.pendingCount - 1);
3950
4329
  if (!isLatestRequest) {
3951
4330
  return {
3952
4331
  ...current,
3953
- pendingCount,
3954
- status: pendingCount > 0 ? "pending" : current.status
4332
+ pendingCount
3955
4333
  };
3956
4334
  }
3957
4335
  return {
3958
4336
  pendingCount,
4337
+ pausedCount: current.pausedCount,
3959
4338
  status: "success",
3960
4339
  data,
3961
4340
  error: null,
@@ -3963,24 +4342,35 @@ function useMutation(target, options = {}) {
3963
4342
  };
3964
4343
  });
3965
4344
  if (isLatestRequest) {
3966
- currentOptions.onSuccess?.(data, variables);
3967
- currentOptions.onSettled?.(data, null, variables);
4345
+ notifyClientObserver(currentOptions.onSuccess, [data, variables], "Mutation onSuccess");
4346
+ if (requestId === requestIdRef.current) {
4347
+ notifyClientObserver(
4348
+ currentOptions.onSettled,
4349
+ [data, null, variables],
4350
+ "Mutation onSettled"
4351
+ );
4352
+ }
3968
4353
  }
3969
4354
  return data;
3970
4355
  } catch (cause) {
4356
+ settleServerFnOptimisticUpdates(
4357
+ sharedSnapshots,
4358
+ sharedOptimistic?.rollbackOnError ? "rollback" : "invalidate"
4359
+ );
3971
4360
  const error = normalizeMutationError(cause);
3972
4361
  const isLatestRequest = requestId === requestIdRef.current;
3973
4362
  setMutationState((current) => {
4363
+ if (requestId < lastResetIdRef.current) return current;
3974
4364
  const pendingCount = Math.max(0, current.pendingCount - 1);
3975
4365
  if (!isLatestRequest) {
3976
4366
  return {
3977
4367
  ...current,
3978
- pendingCount,
3979
- status: pendingCount > 0 ? "pending" : current.status
4368
+ pendingCount
3980
4369
  };
3981
4370
  }
3982
4371
  return {
3983
4372
  pendingCount,
4373
+ pausedCount: current.pausedCount,
3984
4374
  status: "error",
3985
4375
  data: hasOptimisticData && currentOptions.rollbackOnError ? previousData : currentOptions.resetOnMutate === false ? current.data : null,
3986
4376
  error,
@@ -3988,13 +4378,23 @@ function useMutation(target, options = {}) {
3988
4378
  };
3989
4379
  });
3990
4380
  if (isLatestRequest) {
3991
- currentOptions.onError?.(error, variables);
3992
- currentOptions.onSettled?.(null, error, variables);
4381
+ notifyClientObserver(currentOptions.onError, [error, variables], "Mutation onError");
4382
+ if (requestId === requestIdRef.current) {
4383
+ notifyClientObserver(
4384
+ currentOptions.onSettled,
4385
+ [null, error, variables],
4386
+ "Mutation onSettled"
4387
+ );
4388
+ }
3993
4389
  }
3994
4390
  throw error;
3995
4391
  }
3996
4392
  },
3997
- [setMutationState]
4393
+ [setMutationState, waitForReconnect]
4394
+ );
4395
+ const mutateAsync = (0, import_react.useCallback)(
4396
+ (variables) => mutatePreparedAsync(() => variables),
4397
+ [mutatePreparedAsync]
3998
4398
  );
3999
4399
  const mutate = (0, import_react.useCallback)(
4000
4400
  (variables) => {
@@ -4004,18 +4404,23 @@ function useMutation(target, options = {}) {
4004
4404
  [mutateAsync]
4005
4405
  );
4006
4406
  const reset = (0, import_react.useCallback)(() => {
4007
- requestIdRef.current += 1;
4407
+ lastResetIdRef.current = ++requestIdRef.current;
4008
4408
  setMutationState({
4009
4409
  pendingCount: 0,
4410
+ pausedCount: 0,
4010
4411
  status: "idle",
4011
4412
  data: optionsRef.current.initialData ?? null,
4012
4413
  error: null,
4013
4414
  variables: void 0
4014
4415
  });
4416
+ const wakers = Array.from(resetWakersRef.current);
4417
+ resetWakersRef.current.clear();
4418
+ for (const wake of wakers) wake();
4015
4419
  }, [setMutationState]);
4016
- return (0, import_react.useMemo)(
4420
+ const mutation = (0, import_react.useMemo)(
4017
4421
  () => ({
4018
4422
  pending: state.pendingCount > 0,
4423
+ paused: state.pausedCount > 0,
4019
4424
  status: state.status,
4020
4425
  data: state.data,
4021
4426
  error: state.error,
@@ -4030,13 +4435,15 @@ function useMutation(target, options = {}) {
4030
4435
  reset,
4031
4436
  state.data,
4032
4437
  state.error,
4438
+ state.pausedCount,
4033
4439
  state.pendingCount,
4034
4440
  state.status,
4035
4441
  state.variables
4036
4442
  ]
4037
4443
  );
4444
+ return { mutation, mutatePreparedAsync };
4038
4445
  }
4039
- __name(useMutation, "useMutation");
4446
+ __name(useMutationLifecycle, "useMutationLifecycle");
4040
4447
  function unwrapMutationResult(result, apiRoute) {
4041
4448
  if (!apiRoute) return result;
4042
4449
  const apiResult = result;
@@ -4056,13 +4463,27 @@ __name(normalizeMutationError, "normalizeMutationError");
4056
4463
 
4057
4464
  // src/fetcher-client.tsx
4058
4465
  var import_react2 = require("react");
4466
+ var _FetcherInputError = class _FetcherInputError extends Error {
4467
+ constructor(cause) {
4468
+ super(
4469
+ cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "Could not prepare form input"
4470
+ );
4471
+ this.name = "FetcherInputError";
4472
+ this.code = "input_error";
4473
+ this.status = 0;
4474
+ this.data = void 0;
4475
+ this.cause = cause;
4476
+ }
4477
+ };
4478
+ __name(_FetcherInputError, "FetcherInputError");
4479
+ var FetcherInputError = _FetcherInputError;
4059
4480
  var formDataContexts = /* @__PURE__ */ new WeakMap();
4060
4481
  function useFetcher(target, options = {}) {
4061
4482
  const targetRef = (0, import_react2.useRef)(target);
4062
4483
  const optionsRef = (0, import_react2.useRef)(options);
4063
4484
  const submissionIdRef = (0, import_react2.useRef)(0);
4064
4485
  const [formData, setFormData] = (0, import_react2.useState)(null);
4065
- const mutation = useMutation(target, options);
4486
+ const { mutation, mutatePreparedAsync } = useMutationLifecycle(target, options);
4066
4487
  targetRef.current = target;
4067
4488
  optionsRef.current = options;
4068
4489
  const submitAsync = (0, import_react2.useCallback)(
@@ -4071,15 +4492,20 @@ function useFetcher(target, options = {}) {
4071
4492
  const submittedFormData = isFormData2(input) ? input : null;
4072
4493
  setFormData(submittedFormData);
4073
4494
  try {
4074
- const variables = submittedFormData ? mapFetcherFormData(targetRef.current, submittedFormData, optionsRef.current) : input;
4075
- return await mutation.mutateAsync(variables);
4495
+ return await mutatePreparedAsync(() => {
4496
+ try {
4497
+ return submittedFormData ? mapFetcherFormData(targetRef.current, submittedFormData, optionsRef.current) : input;
4498
+ } catch (error) {
4499
+ throw new FetcherInputError(error);
4500
+ }
4501
+ });
4076
4502
  } finally {
4077
4503
  if (submissionId === submissionIdRef.current) {
4078
4504
  setFormData(null);
4079
4505
  }
4080
4506
  }
4081
4507
  },
4082
- [mutation.mutateAsync]
4508
+ [mutatePreparedAsync]
4083
4509
  );
4084
4510
  const submit = (0, import_react2.useCallback)(
4085
4511
  (input) => {
@@ -4129,6 +4555,7 @@ function useFetcher(target, options = {}) {
4129
4555
  state: mutation.pending ? "submitting" : "idle",
4130
4556
  status: mutation.status,
4131
4557
  pending: mutation.pending,
4558
+ paused: mutation.paused,
4132
4559
  data: mutation.data,
4133
4560
  error: mutation.error,
4134
4561
  variables: mutation.variables,
@@ -4143,6 +4570,7 @@ function useFetcher(target, options = {}) {
4143
4570
  formData,
4144
4571
  mutation.data,
4145
4572
  mutation.error,
4573
+ mutation.paused,
4146
4574
  mutation.pending,
4147
4575
  mutation.status,
4148
4576
  mutation.variables,
@@ -4161,9 +4589,18 @@ function mapFetcherFormData(target, formData, options) {
4161
4589
  if (!isAPIRouteRef(target)) {
4162
4590
  return formData;
4163
4591
  }
4164
- const values = formDataToObject(formData);
4165
4592
  const method = getAPIRouteRefMetadata(target)?.method;
4166
- return method === "GET" || method === "HEAD" ? { query: values } : { body: values };
4593
+ const query = method === "GET" || method === "HEAD";
4594
+ const encoding = context2.submitter?.getAttribute("formenctype") ?? context2.form?.enctype;
4595
+ if (!query && (encoding?.toLowerCase() === "multipart/form-data" || Array.from(formData.values()).some((value) => typeof value !== "string"))) {
4596
+ const body = new FormData();
4597
+ for (const [key, value] of formData) {
4598
+ if (!isUnsafeFormKey(key)) body.append(key, value);
4599
+ }
4600
+ return { body };
4601
+ }
4602
+ const values = formDataToObject(formData);
4603
+ return query ? { query: values } : { body: values };
4167
4604
  }
4168
4605
  __name(mapFetcherFormData, "mapFetcherFormData");
4169
4606
  function resolveFetcherFormAction(target, metadata) {
@@ -4175,7 +4612,7 @@ __name(resolveFetcherFormAction, "resolveFetcherFormAction");
4175
4612
  function formDataToObject(formData) {
4176
4613
  const output = /* @__PURE__ */ Object.create(null);
4177
4614
  for (const [key, value] of formData.entries()) {
4178
- if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
4615
+ if (isUnsafeFormKey(key)) continue;
4179
4616
  const current = output[key];
4180
4617
  if (current === void 0) {
4181
4618
  output[key] = value;
@@ -4188,6 +4625,10 @@ function formDataToObject(formData) {
4188
4625
  return output;
4189
4626
  }
4190
4627
  __name(formDataToObject, "formDataToObject");
4628
+ function isUnsafeFormKey(key) {
4629
+ return key === "__proto__" || key === "constructor" || key === "prototype";
4630
+ }
4631
+ __name(isUnsafeFormKey, "isUnsafeFormKey");
4191
4632
  function createSubmitterFormData(form, submitter) {
4192
4633
  try {
4193
4634
  return new FormData(form, submitter);
@@ -4223,6 +4664,7 @@ function useServerFn(serverFn, options = {}) {
4223
4664
  const { initialResult = null, resetOnSubmit = true } = options;
4224
4665
  const callbacksRef = (0, import_react3.useRef)({});
4225
4666
  const requestIdRef = (0, import_react3.useRef)(0);
4667
+ const lastResetIdRef = (0, import_react3.useRef)(0);
4226
4668
  const initialState = {
4227
4669
  pendingCount: 0,
4228
4670
  status: "idle",
@@ -4233,11 +4675,9 @@ function useServerFn(serverFn, options = {}) {
4233
4675
  const [state, setState] = (0, import_react3.useState)(initialState);
4234
4676
  const setActionState = (0, import_react3.useCallback)(
4235
4677
  (value) => {
4236
- setState((current) => {
4237
- const next = typeof value === "function" ? value(current) : value;
4238
- stateRef.current = next;
4239
- return next;
4240
- });
4678
+ const next = typeof value === "function" ? value(stateRef.current) : value;
4679
+ stateRef.current = next;
4680
+ setState(next);
4241
4681
  },
4242
4682
  []
4243
4683
  );
@@ -4258,63 +4698,88 @@ function useServerFn(serverFn, options = {}) {
4258
4698
  current: previousResult
4259
4699
  });
4260
4700
  const hasOptimisticResult = optimisticResult !== void 0;
4261
- setActionState((current) => ({
4262
- pendingCount: current.pendingCount + 1,
4263
- status: "pending",
4264
- result: hasOptimisticResult ? optimisticResult : resetOnSubmit ? null : current.result,
4265
- error: null
4266
- }));
4701
+ setActionState((current) => {
4702
+ if (requestId < lastResetIdRef.current) return current;
4703
+ const pendingCount = current.pendingCount + 1;
4704
+ if (requestId !== requestIdRef.current) return { ...current, pendingCount };
4705
+ return {
4706
+ pendingCount,
4707
+ status: "pending",
4708
+ result: hasOptimisticResult ? optimisticResult : resetOnSubmit ? null : current.result,
4709
+ error: null
4710
+ };
4711
+ });
4267
4712
  try {
4268
- const result = await serverFn(input);
4713
+ const result = await invokeMutationWithRetry(
4714
+ () => serverFn(input),
4715
+ options.retry,
4716
+ // A reset disowns this submission; stop scheduling retries then.
4717
+ () => requestId >= lastResetIdRef.current
4718
+ );
4269
4719
  const isLatestRequest = requestId === requestIdRef.current;
4270
4720
  setActionState((current) => {
4721
+ if (requestId < lastResetIdRef.current) return current;
4271
4722
  const pendingCount = Math.max(0, current.pendingCount - 1);
4272
4723
  if (!isLatestRequest) {
4273
4724
  return {
4274
4725
  ...current,
4275
- pendingCount,
4276
- status: pendingCount > 0 ? "pending" : current.status
4726
+ pendingCount
4277
4727
  };
4278
4728
  }
4279
4729
  return {
4280
4730
  pendingCount,
4281
- status: pendingCount > 0 ? "pending" : "success",
4731
+ status: "success",
4282
4732
  result,
4283
4733
  error: null
4284
4734
  };
4285
4735
  });
4286
4736
  if (isLatestRequest) {
4287
- callbacksRef.current.onSuccess?.(result);
4288
- callbacksRef.current.onSettled?.(result, null);
4737
+ notifyClientObserver(callbacksRef.current.onSuccess, [result], "Action onSuccess");
4738
+ if (requestId === requestIdRef.current) {
4739
+ notifyClientObserver(
4740
+ callbacksRef.current.onSettled,
4741
+ [result, null],
4742
+ "Action onSettled"
4743
+ );
4744
+ }
4289
4745
  }
4290
4746
  return result;
4291
4747
  } catch (cause) {
4292
4748
  const error = normalizeServerFnError(cause);
4293
4749
  const isLatestRequest = requestId === requestIdRef.current;
4294
4750
  setActionState((current) => {
4751
+ if (requestId < lastResetIdRef.current) return current;
4295
4752
  const pendingCount = Math.max(0, current.pendingCount - 1);
4296
4753
  if (!isLatestRequest) {
4297
4754
  return {
4298
4755
  ...current,
4299
- pendingCount,
4300
- status: pendingCount > 0 ? "pending" : current.status
4756
+ pendingCount
4301
4757
  };
4302
4758
  }
4303
4759
  return {
4304
4760
  pendingCount,
4305
- status: pendingCount > 0 ? "pending" : "error",
4761
+ status: "error",
4306
4762
  result: hasOptimisticResult && options.rollbackOnError ? previousResult : resetOnSubmit ? null : current.result,
4307
4763
  error
4308
4764
  };
4309
4765
  });
4310
4766
  if (isLatestRequest) {
4311
- callbacksRef.current.onError?.(error);
4312
- callbacksRef.current.onSettled?.(null, error);
4767
+ notifyClientObserver(callbacksRef.current.onError, [error], "Action onError");
4768
+ if (requestId === requestIdRef.current) {
4769
+ notifyClientObserver(callbacksRef.current.onSettled, [null, error], "Action onSettled");
4770
+ }
4313
4771
  }
4314
4772
  throw error;
4315
4773
  }
4316
4774
  },
4317
- [options.optimistic, options.rollbackOnError, resetOnSubmit, serverFn, setActionState]
4775
+ [
4776
+ options.optimistic,
4777
+ options.retry,
4778
+ options.rollbackOnError,
4779
+ resetOnSubmit,
4780
+ serverFn,
4781
+ setActionState
4782
+ ]
4318
4783
  );
4319
4784
  const formAction = (0, import_react3.useCallback)(
4320
4785
  async (formData) => {
@@ -4329,7 +4794,7 @@ function useServerFn(serverFn, options = {}) {
4329
4794
  [submit]
4330
4795
  );
4331
4796
  const reset = (0, import_react3.useCallback)(() => {
4332
- requestIdRef.current += 1;
4797
+ lastResetIdRef.current = ++requestIdRef.current;
4333
4798
  setActionState({
4334
4799
  pendingCount: 0,
4335
4800
  status: "idle",
@@ -4354,14 +4819,17 @@ __name(useServerFn, "useServerFn");
4354
4819
  function useAction(target, options = {}) {
4355
4820
  const serverFn = resolveServerFnTarget(target);
4356
4821
  const action = useServerFn(serverFn, options);
4822
+ const formActionRef = (0, import_react3.useRef)(action.formAction);
4823
+ formActionRef.current = action.formAction;
4357
4824
  const Form = (0, import_react3.useMemo)(() => {
4825
+ const submitForm = /* @__PURE__ */ __name((formData) => formActionRef.current(formData), "submitForm");
4358
4826
  const ActionForm = /* @__PURE__ */ __name((props) => (0, import_react3.createElement)("form", {
4359
4827
  ...props,
4360
- action: action.formAction
4828
+ action: submitForm
4361
4829
  }), "ActionForm");
4362
4830
  ActionForm.displayName = "FarmActionForm";
4363
4831
  return ActionForm;
4364
- }, [action.formAction]);
4832
+ }, []);
4365
4833
  return (0, import_react3.useMemo)(() => {
4366
4834
  const call = /* @__PURE__ */ __name(((input) => action.submit(input)), "call");
4367
4835
  return Object.assign(call, {
@@ -4413,6 +4881,21 @@ __name(isFormData3, "isFormData");
4413
4881
  // src/server-query-client.ts
4414
4882
  var import_react4 = require("react");
4415
4883
 
4884
+ // src/client-revalidation.ts
4885
+ function attachRevalidationListeners(refresh, options = {}) {
4886
+ if (typeof window === "undefined") return () => {
4887
+ };
4888
+ const onFocus = options.refetchOnWindowFocus === false ? void 0 : refresh;
4889
+ const onOnline = options.refetchOnReconnect === false ? void 0 : refresh;
4890
+ if (onFocus) window.addEventListener("focus", onFocus);
4891
+ if (onOnline) window.addEventListener("online", onOnline);
4892
+ return () => {
4893
+ if (onFocus) window.removeEventListener("focus", onFocus);
4894
+ if (onOnline) window.removeEventListener("online", onOnline);
4895
+ };
4896
+ }
4897
+ __name(attachRevalidationListeners, "attachRevalidationListeners");
4898
+
4416
4899
  // src/server-query-runtime.ts
4417
4900
  var FARM_SERVER_QUERY_CLIENT_STATE = /* @__PURE__ */ Symbol.for("farm.serverQueryClientState");
4418
4901
  var serverQueryClientGlobal = globalThis;
@@ -4420,9 +4903,30 @@ var serverQueryClientState = serverQueryClientGlobal[FARM_SERVER_QUERY_CLIENT_ST
4420
4903
  functionIds: /* @__PURE__ */ new WeakMap(),
4421
4904
  nextFunctionId: 0,
4422
4905
  active: [],
4423
- latestOwners: /* @__PURE__ */ new Map()
4906
+ latestOwners: /* @__PURE__ */ new Map(),
4907
+ owners: /* @__PURE__ */ new Set()
4424
4908
  });
4425
4909
  serverQueryClientState.latestOwners ?? (serverQueryClientState.latestOwners = /* @__PURE__ */ new Map());
4910
+ serverQueryClientState.owners ?? (serverQueryClientState.owners = /* @__PURE__ */ new Set());
4911
+ function isServerQueryOwnerSuperseded(owner, key) {
4912
+ const cache = getFarmClientDataCache();
4913
+ const resolved = cache.resolveKey(key);
4914
+ for (const superseded of owner.supersededKeys ?? []) {
4915
+ if (cache.resolveKey(superseded) === resolved) return true;
4916
+ }
4917
+ return false;
4918
+ }
4919
+ __name(isServerQueryOwnerSuperseded, "isServerQueryOwnerSuperseded");
4920
+ function claimServerQueryKey(owner, key) {
4921
+ if (isServerQueryOwnerSuperseded(owner, key)) return false;
4922
+ const resolved = getFarmClientDataCache().resolveKey(key);
4923
+ for (const older of serverQueryClientState.owners) {
4924
+ if (older === owner) break;
4925
+ older.supersededKeys.add(resolved);
4926
+ }
4927
+ return true;
4928
+ }
4929
+ __name(claimServerQueryKey, "claimServerQueryKey");
4426
4930
  var RAW_SERVER_QUERY_SYMBOL = /* @__PURE__ */ Symbol.for("farm.server-query");
4427
4931
  function assertNotRawServerQueryInBrowser(query) {
4428
4932
  if (typeof window === "undefined" || typeof document === "undefined") return;
@@ -4436,6 +4940,10 @@ function assertNotRawServerQueryInBrowser(query) {
4436
4940
  );
4437
4941
  }
4438
4942
  __name(assertNotRawServerQueryInBrowser, "assertNotRawServerQueryInBrowser");
4943
+ function isCurrentServerQueryOwner(provisionalKey, owner) {
4944
+ return serverQueryClientState.latestOwners.get(provisionalKey) === owner && !isServerQueryOwnerSuperseded(owner, provisionalKey);
4945
+ }
4946
+ __name(isCurrentServerQueryOwner, "isCurrentServerQueryOwner");
4439
4947
  function createServerQueryCallKey(query, input) {
4440
4948
  let id = serverQueryClientState.functionIds.get(query);
4441
4949
  if (!id) {
@@ -4451,12 +4959,14 @@ async function fetchServerQuery(query, input, options = {}) {
4451
4959
  const entry = cache.get(provisionalKey);
4452
4960
  const stale = cache.isStale(provisionalKey);
4453
4961
  const inflight = cache.getInflight(provisionalKey);
4454
- if (inflight && !options.force) return inflight;
4455
- if (!options.force && entry && !stale && entry.status !== "error") return entry.data;
4456
- if (!options.force && entry && stale && entry.status !== "pending" && entry.status !== "error" && (options.swr ?? true)) {
4457
- void executeServerQuery(query, input, provisionalKey, options).catch(() => void 0);
4962
+ if (!options.force && entry && stale && (entry.status !== "pending" || entry.updatedAt !== 0) && entry.status !== "error" && (options.swr ?? true)) {
4963
+ if (!inflight) {
4964
+ void executeServerQuery(query, input, provisionalKey, options).catch(() => void 0);
4965
+ }
4458
4966
  return entry.data;
4459
4967
  }
4968
+ if (inflight && !options.force) return inflight;
4969
+ if (!options.force && entry && !stale && entry.status !== "error") return entry.data;
4460
4970
  return executeServerQuery(query, input, provisionalKey, options);
4461
4971
  }
4462
4972
  __name(fetchServerQuery, "fetchServerQuery");
@@ -4469,8 +4979,13 @@ async function executeServerQuery(query, input, provisionalKey, options) {
4469
4979
  const cache = getFarmClientDataCache();
4470
4980
  const inflight = cache.getInflight(provisionalKey);
4471
4981
  if (inflight && !options.force) return inflight;
4472
- const owner = {};
4982
+ const owner = {
4983
+ invalidations: trackFarmClientCacheInvalidations(cache),
4984
+ supersededKeys: /* @__PURE__ */ new Set()
4985
+ };
4473
4986
  serverQueryClientState.latestOwners.set(provisionalKey, owner);
4987
+ serverQueryClientState.owners.add(owner);
4988
+ claimServerQueryKey(owner, provisionalKey);
4474
4989
  const previous = cache.get(provisionalKey);
4475
4990
  cache.set(provisionalKey, {
4476
4991
  data: previous?.data,
@@ -4495,12 +5010,12 @@ async function executeServerQuery(query, input, provisionalKey, options) {
4495
5010
  }
4496
5011
  const data = await pending;
4497
5012
  const transported = cache.get(provisionalKey);
4498
- if (serverQueryClientState.latestOwners.get(provisionalKey) === owner && (!transported || transported.fetching)) {
5013
+ if (isCurrentServerQueryOwner(provisionalKey, owner) && (!transported || transported.fetching)) {
4499
5014
  const updatedAt = Date.now();
4500
5015
  cache.set(provisionalKey, {
4501
5016
  data,
4502
5017
  updatedAt,
4503
- staleAt: options.staleTime === false ? Number.POSITIVE_INFINITY : updatedAt + (options.staleTime ?? 0),
5018
+ staleAt: owner.invalidations.has(provisionalKey) ? 0 : options.staleTime === false ? Number.POSITIVE_INFINITY : updatedAt + (options.staleTime ?? 0),
4504
5019
  status: "success",
4505
5020
  error: null,
4506
5021
  fetching: false
@@ -4509,7 +5024,7 @@ async function executeServerQuery(query, input, provisionalKey, options) {
4509
5024
  return data;
4510
5025
  } catch (cause) {
4511
5026
  const error = normalizeServerQueryError(cause);
4512
- if (serverQueryClientState.latestOwners.get(provisionalKey) === owner) {
5027
+ if (isCurrentServerQueryOwner(provisionalKey, owner)) {
4513
5028
  const current = cache.get(provisionalKey);
4514
5029
  cache.set(provisionalKey, {
4515
5030
  data: current?.data,
@@ -4524,12 +5039,17 @@ async function executeServerQuery(query, input, provisionalKey, options) {
4524
5039
  }
4525
5040
  throw error;
4526
5041
  } finally {
5042
+ const invalidated = isCurrentServerQueryOwner(provisionalKey, owner) && owner.invalidations.has(provisionalKey);
5043
+ owner.invalidations.dispose();
5044
+ serverQueryClientState.owners.delete(owner);
5045
+ owner.supersededKeys.clear();
4527
5046
  if (cache.getInflight(provisionalKey) === promise) {
4528
5047
  cache.deleteInflight(provisionalKey);
4529
5048
  }
4530
5049
  if (serverQueryClientState.latestOwners.get(provisionalKey) === owner) {
4531
5050
  serverQueryClientState.latestOwners.delete(provisionalKey);
4532
5051
  }
5052
+ if (invalidated) cache.invalidate(provisionalKey);
4533
5053
  }
4534
5054
  })();
4535
5055
  cache.setInflight(provisionalKey, promise);
@@ -4551,19 +5071,29 @@ function useServerQuery(query, input, options = {}) {
4551
5071
  const inputRef = (0, import_react4.useRef)(input);
4552
5072
  const optionsRef = (0, import_react4.useRef)(options);
4553
5073
  const mountedKeyRef = (0, import_react4.useRef)(void 0);
5074
+ const pendingInvalidationRef = (0, import_react4.useRef)(false);
4554
5075
  inputRef.current = input;
4555
5076
  optionsRef.current = options;
4556
5077
  const subscribe = (0, import_react4.useCallback)(
4557
- (listener) => cache.subscribe(key, listener),
5078
+ (listener) => cache.subscribe(key, (event) => {
5079
+ if (event === "invalidate") pendingInvalidationRef.current = true;
5080
+ else if (cache.get(key)?.fetching) {
5081
+ pendingInvalidationRef.current = false;
5082
+ }
5083
+ listener();
5084
+ }),
4558
5085
  [cache, key]
4559
5086
  );
4560
5087
  const getSnapshot = (0, import_react4.useCallback)(() => cache.get(key), [cache, key]);
4561
5088
  const entry = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
4562
5089
  const run = (0, import_react4.useCallback)(
4563
- (force = false) => fetchServerQuery(query, inputRef.current, {
4564
- ...optionsRef.current,
4565
- force
4566
- }),
5090
+ (force = false) => {
5091
+ pendingInvalidationRef.current = false;
5092
+ return fetchServerQuery(query, inputRef.current, {
5093
+ ...optionsRef.current,
5094
+ force
5095
+ });
5096
+ },
4567
5097
  [query]
4568
5098
  );
4569
5099
  (0, import_react4.useEffect)(() => {
@@ -4573,23 +5103,21 @@ function useServerQuery(query, input, options = {}) {
4573
5103
  }
4574
5104
  const firstReadForKey = mountedKeyRef.current !== key;
4575
5105
  if (firstReadForKey) mountedKeyRef.current = key;
4576
- if (firstReadForKey && (!entry || cache.isStale(key)) || entry?.invalidatedAt !== void 0 && !entry.fetching) {
5106
+ if (firstReadForKey && (!entry || cache.isStale(key)) || pendingInvalidationRef.current && entry?.invalidatedAt !== void 0 && !entry.fetching) {
4577
5107
  void run().catch(() => void 0);
4578
5108
  }
4579
5109
  }, [cache, entry, key, options.enabled, run]);
4580
5110
  (0, import_react4.useEffect)(() => {
4581
- if (options.enabled === false || typeof window === "undefined") return;
4582
- const refreshIfStale = /* @__PURE__ */ __name(() => {
4583
- if (cache.isStale(key)) void run().catch(() => void 0);
4584
- }, "refreshIfStale");
4585
- const onFocus = options.refetchOnWindowFocus === false ? void 0 : refreshIfStale;
4586
- const onOnline = options.refetchOnReconnect === false ? void 0 : refreshIfStale;
4587
- if (onFocus) window.addEventListener("focus", onFocus);
4588
- if (onOnline) window.addEventListener("online", onOnline);
4589
- return () => {
4590
- if (onFocus) window.removeEventListener("focus", onFocus);
4591
- if (onOnline) window.removeEventListener("online", onOnline);
4592
- };
5111
+ if (options.enabled === false) return;
5112
+ return attachRevalidationListeners(
5113
+ () => {
5114
+ if (cache.isStale(key)) void run().catch(() => void 0);
5115
+ },
5116
+ {
5117
+ refetchOnWindowFocus: options.refetchOnWindowFocus,
5118
+ refetchOnReconnect: options.refetchOnReconnect
5119
+ }
5120
+ );
4593
5121
  }, [cache, key, options.enabled, options.refetchOnReconnect, options.refetchOnWindowFocus, run]);
4594
5122
  const status = entry?.status ?? (entry ? "success" : "idle");
4595
5123
  const fetching = entry?.fetching ?? false;
@@ -4605,6 +5133,296 @@ function useServerQuery(query, input, options = {}) {
4605
5133
  }
4606
5134
  __name(useServerQuery, "useServerQuery");
4607
5135
 
5136
+ // src/cache-invalidation-broadcast.ts
5137
+ var FARM_CACHE_INVALIDATION_CHANNEL = "farm:cache-invalidation";
5138
+ var activeBridge;
5139
+ function enableCrossTabCacheInvalidation(options = {}) {
5140
+ if (typeof BroadcastChannel !== "function") return () => {
5141
+ };
5142
+ const channelName = options.channelName ?? FARM_CACHE_INVALIDATION_CHANNEL;
5143
+ if (activeBridge) {
5144
+ if (activeBridge.channelName !== channelName) {
5145
+ throw new Error(
5146
+ `Cross-tab cache invalidation is already enabled on channel "${activeBridge.channelName}".`
5147
+ );
5148
+ }
5149
+ activeBridge.refCount += 1;
5150
+ } else {
5151
+ activeBridge = createBridge(channelName);
5152
+ }
5153
+ let disposed = false;
5154
+ return () => {
5155
+ if (disposed || !activeBridge) return;
5156
+ disposed = true;
5157
+ activeBridge.refCount -= 1;
5158
+ if (activeBridge.refCount === 0) {
5159
+ activeBridge.teardown();
5160
+ activeBridge = void 0;
5161
+ }
5162
+ };
5163
+ }
5164
+ __name(enableCrossTabCacheInvalidation, "enableCrossTabCacheInvalidation");
5165
+ function createBridge(channelName) {
5166
+ const channel = new BroadcastChannel(channelName);
5167
+ let applyingRemote = false;
5168
+ let pending = [];
5169
+ let flushScheduled = false;
5170
+ let closed = false;
5171
+ const flush = /* @__PURE__ */ __name(() => {
5172
+ flushScheduled = false;
5173
+ if (closed || pending.length === 0) return;
5174
+ const encoded = encodeFarmCacheInvalidations(pending);
5175
+ pending = [];
5176
+ if (encoded !== null) channel.postMessage(encoded);
5177
+ }, "flush");
5178
+ const unsubscribe = subscribeFarmCacheInvalidation((key) => {
5179
+ if (applyingRemote || closed) return;
5180
+ pending.push(key);
5181
+ if (!flushScheduled) {
5182
+ flushScheduled = true;
5183
+ queueMicrotask(flush);
5184
+ }
5185
+ });
5186
+ channel.onmessage = (event) => {
5187
+ const keys = decodeFarmCacheInvalidations(
5188
+ typeof event.data === "string" ? event.data : void 0
5189
+ );
5190
+ if (keys.length === 0) return;
5191
+ applyingRemote = true;
5192
+ try {
5193
+ for (const key of keys) notifyFarmCacheInvalidation(key);
5194
+ } finally {
5195
+ applyingRemote = false;
5196
+ }
5197
+ };
5198
+ return {
5199
+ channelName,
5200
+ refCount: 1,
5201
+ teardown() {
5202
+ closed = true;
5203
+ pending = [];
5204
+ unsubscribe();
5205
+ channel.onmessage = null;
5206
+ channel.close();
5207
+ }
5208
+ };
5209
+ }
5210
+ __name(createBridge, "createBridge");
5211
+
5212
+ // src/client-cache-persistence.ts
5213
+ var FARM_CLIENT_CACHE_PERSIST_VERSION = "1";
5214
+ function defineClientCacheAdapter(adapter) {
5215
+ for (const method of ["keys", "get", "set", "delete", "clear"]) {
5216
+ if (typeof adapter?.[method] !== "function") {
5217
+ throw new TypeError(
5218
+ `defineClientCacheAdapter expects a "${method}" method. Implement keys/get/set/delete/clear over your storage.`
5219
+ );
5220
+ }
5221
+ }
5222
+ return adapter;
5223
+ }
5224
+ __name(defineClientCacheAdapter, "defineClientCacheAdapter");
5225
+ function storageClientCacheAdapter(storage, options = {}) {
5226
+ if (!storage || typeof storage.getItem !== "function" || typeof storage.setItem !== "function" || typeof storage.removeItem !== "function") {
5227
+ throw new TypeError("storageClientCacheAdapter expects a compatible key-value client.");
5228
+ }
5229
+ const base = options.base ?? "farm-client-cache";
5230
+ const entryKey = /* @__PURE__ */ __name((key) => `${base}:${key}`, "entryKey");
5231
+ const enumerate = storage.getKeys?.bind(storage) ?? storage.keys?.bind(storage);
5232
+ return {
5233
+ async keys() {
5234
+ if (!enumerate) return [];
5235
+ const keys = await enumerate(base);
5236
+ const prefix = `${base}:`;
5237
+ return keys.filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length));
5238
+ },
5239
+ async get(key) {
5240
+ return await storage.getItem(entryKey(key)) ?? null;
5241
+ },
5242
+ async set(key, entry) {
5243
+ await storage.setItem(entryKey(key), entry);
5244
+ },
5245
+ async delete(key) {
5246
+ await storage.removeItem(entryKey(key));
5247
+ },
5248
+ async clear() {
5249
+ if (storage.clear) {
5250
+ await storage.clear(base);
5251
+ return;
5252
+ }
5253
+ if (!enumerate) return;
5254
+ const prefix = `${base}:`;
5255
+ for (const key of await enumerate(base)) {
5256
+ if (key.startsWith(prefix)) await storage.removeItem(key);
5257
+ }
5258
+ }
5259
+ };
5260
+ }
5261
+ __name(storageClientCacheAdapter, "storageClientCacheAdapter");
5262
+ var activeEngine;
5263
+ function reportPersistenceFailure(error) {
5264
+ const report = typeof reportError === "function" ? reportError : console.error;
5265
+ if (error instanceof Error) {
5266
+ report(error);
5267
+ return;
5268
+ }
5269
+ const normalized = new Error("Client cache persistence failed");
5270
+ normalized.cause = error;
5271
+ report(normalized);
5272
+ }
5273
+ __name(reportPersistenceFailure, "reportPersistenceFailure");
5274
+ function disableEngine(engine, error) {
5275
+ if (engine.disabled) return;
5276
+ engine.disabled = true;
5277
+ engine.pendingSets.clear();
5278
+ engine.pendingDeletes.clear();
5279
+ if (engine.flushTimer !== void 0) {
5280
+ clearTimeout(engine.flushTimer);
5281
+ engine.flushTimer = void 0;
5282
+ }
5283
+ reportPersistenceFailure(error);
5284
+ }
5285
+ __name(disableEngine, "disableEngine");
5286
+ function scheduleFlush(engine) {
5287
+ if (engine.disabled || engine.flushTimer !== void 0) return;
5288
+ const timer = setTimeout(() => {
5289
+ engine.flushTimer = void 0;
5290
+ void flushEngine(engine);
5291
+ }, engine.flushDelayMs);
5292
+ timer.unref?.();
5293
+ engine.flushTimer = timer;
5294
+ }
5295
+ __name(scheduleFlush, "scheduleFlush");
5296
+ async function flushEngine(engine) {
5297
+ if (engine.disabled) return;
5298
+ const sets = Array.from(engine.pendingSets.entries());
5299
+ const deletes = Array.from(engine.pendingDeletes);
5300
+ engine.pendingSets.clear();
5301
+ engine.pendingDeletes.clear();
5302
+ try {
5303
+ if (sets.length > 0) {
5304
+ if (engine.adapter.setMany) await engine.adapter.setMany(sets);
5305
+ else for (const [key, entry] of sets) await engine.adapter.set(key, entry);
5306
+ }
5307
+ for (const key of deletes) await engine.adapter.delete(key);
5308
+ } catch (error) {
5309
+ disableEngine(engine, error);
5310
+ }
5311
+ }
5312
+ __name(flushEngine, "flushEngine");
5313
+ async function hydrateEngine(engine) {
5314
+ const now2 = Date.now();
5315
+ const keys = await engine.adapter.keys();
5316
+ if (keys.length === 0) return;
5317
+ const persisted = engine.adapter.getMany ? await engine.adapter.getMany(keys) : await Promise.all(keys.map((key) => engine.adapter.get(key)));
5318
+ engine.hydrating = true;
5319
+ try {
5320
+ for (let index = 0; index < keys.length; index += 1) {
5321
+ const key = keys[index];
5322
+ const entry = persisted[index];
5323
+ if (engine.disabled) return;
5324
+ if (!entry || entry.version !== engine.version || entry.gcAt !== void 0 && now2 >= entry.gcAt) {
5325
+ engine.pendingDeletes.add(key);
5326
+ continue;
5327
+ }
5328
+ if (engine.cache.get(key, now2)) continue;
5329
+ engine.cache.set(key, {
5330
+ data: entry.data,
5331
+ updatedAt: entry.updatedAt,
5332
+ staleAt: 0,
5333
+ gcAt: entry.gcAt,
5334
+ status: "success",
5335
+ error: null,
5336
+ persist: true
5337
+ });
5338
+ }
5339
+ } finally {
5340
+ engine.hydrating = false;
5341
+ }
5342
+ if (engine.pendingDeletes.size > 0) scheduleFlush(engine);
5343
+ }
5344
+ __name(hydrateEngine, "hydrateEngine");
5345
+ function createSink(engine) {
5346
+ return {
5347
+ onSet(key, entry) {
5348
+ if (engine.disabled || engine.hydrating) return;
5349
+ if (!entry.persist || entry.fetching || entry.error || entry.status === "pending") return;
5350
+ if (engine.persistKey && !engine.persistKey(key)) return;
5351
+ engine.pendingDeletes.delete(key);
5352
+ engine.pendingSets.set(key, {
5353
+ data: entry.data,
5354
+ updatedAt: entry.updatedAt,
5355
+ staleAt: entry.staleAt,
5356
+ gcAt: entry.gcAt,
5357
+ version: engine.version
5358
+ });
5359
+ scheduleFlush(engine);
5360
+ },
5361
+ onDelete(key) {
5362
+ if (engine.disabled) return;
5363
+ engine.pendingSets.delete(key);
5364
+ engine.pendingDeletes.add(key);
5365
+ scheduleFlush(engine);
5366
+ },
5367
+ onClear() {
5368
+ if (engine.disabled) return;
5369
+ engine.pendingSets.clear();
5370
+ engine.pendingDeletes.clear();
5371
+ void engine.adapter.clear().catch((error) => disableEngine(engine, error));
5372
+ }
5373
+ };
5374
+ }
5375
+ __name(createSink, "createSink");
5376
+ function initPersistedClientCache(adapter, options = {}) {
5377
+ defineClientCacheAdapter(adapter);
5378
+ disposePersistedClientCache();
5379
+ const engine = {
5380
+ adapter,
5381
+ cache: getFarmClientDataCache(),
5382
+ version: options.version ? `${FARM_CLIENT_CACHE_PERSIST_VERSION}:${options.version}` : FARM_CLIENT_CACHE_PERSIST_VERSION,
5383
+ persistKey: options.persistKey,
5384
+ flushDelayMs: options.flushDelayMs ?? 300,
5385
+ pendingSets: /* @__PURE__ */ new Map(),
5386
+ pendingDeletes: /* @__PURE__ */ new Set(),
5387
+ flushTimer: void 0,
5388
+ hydrating: false,
5389
+ disabled: false
5390
+ };
5391
+ activeEngine = engine;
5392
+ engine.cache.attachPersistence(createSink(engine));
5393
+ void hydrateEngine(engine).catch((error) => disableEngine(engine, error));
5394
+ return () => {
5395
+ if (activeEngine !== engine) return;
5396
+ disposePersistedClientCache();
5397
+ };
5398
+ }
5399
+ __name(initPersistedClientCache, "initPersistedClientCache");
5400
+ function disposePersistedClientCache() {
5401
+ const engine = activeEngine;
5402
+ if (!engine) return;
5403
+ activeEngine = void 0;
5404
+ engine.cache.attachPersistence(void 0);
5405
+ if (engine.flushTimer !== void 0) {
5406
+ clearTimeout(engine.flushTimer);
5407
+ engine.flushTimer = void 0;
5408
+ }
5409
+ engine.pendingSets.clear();
5410
+ engine.pendingDeletes.clear();
5411
+ }
5412
+ __name(disposePersistedClientCache, "disposePersistedClientCache");
5413
+ async function clearPersistedCache() {
5414
+ const engine = activeEngine;
5415
+ if (!engine) return;
5416
+ engine.pendingSets.clear();
5417
+ engine.pendingDeletes.clear();
5418
+ try {
5419
+ await engine.adapter.clear();
5420
+ } catch (error) {
5421
+ disableEngine(engine, error);
5422
+ }
5423
+ }
5424
+ __name(clearPersistedCache, "clearPersistedCache");
5425
+
4608
5426
  // src/integration-api.ts
4609
5427
  function defineIntegrationAPIOperation(operation2) {
4610
5428
  return {
@@ -4847,11 +5665,14 @@ function pickState(state, keys) {
4847
5665
  return slice;
4848
5666
  }
4849
5667
  __name(pickState, "pickState");
5668
+ function getEnumerableKeys(state) {
5669
+ return Reflect.ownKeys(state).filter(
5670
+ (key) => Object.prototype.propertyIsEnumerable.call(state, key)
5671
+ );
5672
+ }
5673
+ __name(getEnumerableKeys, "getEnumerableKeys");
4850
5674
  function getChangedKeys(state, previousState) {
4851
- const keys = /* @__PURE__ */ new Set([
4852
- ...Object.keys(state),
4853
- ...Object.keys(previousState)
4854
- ]);
5675
+ const keys = /* @__PURE__ */ new Set([...getEnumerableKeys(state), ...getEnumerableKeys(previousState)]);
4855
5676
  return [...keys].filter((key) => !Object.is(state[key], previousState[key]));
4856
5677
  }
4857
5678
  __name(getChangedKeys, "getChangedKeys");
@@ -4872,7 +5693,11 @@ function createStore(initialState, extend) {
4872
5693
  let state = cloneState(initialState);
4873
5694
  const subscriptions = /* @__PURE__ */ new Set();
4874
5695
  const addSubscription = /* @__PURE__ */ __name((keys, notify) => {
4875
- const subscription = { keys, notify };
5696
+ const subscription = {
5697
+ // Object property enumeration returns numeric keys as strings.
5698
+ keys: keys?.map((key) => typeof key === "number" ? String(key) : key) ?? null,
5699
+ notify
5700
+ };
4876
5701
  subscriptions.add(subscription);
4877
5702
  return () => {
4878
5703
  subscriptions.delete(subscription);
@@ -4964,7 +5789,7 @@ function createStore(initialState, extend) {
4964
5789
  getSnapshot
4965
5790
  );
4966
5791
  }
4967
- if (typeof keyOrKeys === "string") {
5792
+ if (isStoreKey(keyOrKeys)) {
4968
5793
  return (0, import_react5.useSyncExternalStore)(
4969
5794
  (notify) => addSubscription([keyOrKeys], () => notify()),
4970
5795
  () => state[keyOrKeys],
@@ -4985,7 +5810,7 @@ function createStore(initialState, extend) {
4985
5810
  reset: /* @__PURE__ */ __name(() => replaceState2(cloneState(initialSnapshot)), "reset"),
4986
5811
  subscribe: subscribeState
4987
5812
  };
4988
- for (const key of Object.keys(initialSnapshot)) {
5813
+ for (const key of getEnumerableKeys(initialSnapshot)) {
4989
5814
  if (RESERVED_STORE_KEYS.has(key)) {
4990
5815
  throw new Error(
4991
5816
  `createStore does not allow the reserved key "${String(key)}" in the initial state.`
@@ -6679,7 +7504,9 @@ var _SPARouter = class _SPARouter {
6679
7504
  if (this.onNavigate) {
6680
7505
  await this.onNavigate(pageData);
6681
7506
  }
6682
- if (this.options.scrollRestoration) {
7507
+ if (window.location.hash) {
7508
+ getHashTargetElement(window.location.hash)?.scrollIntoView();
7509
+ } else if (this.options.scrollRestoration) {
6683
7510
  this.restoreScrollPosition(window.location.pathname + window.location.search);
6684
7511
  }
6685
7512
  if (clientNavigation) {
@@ -7768,7 +8595,7 @@ body {
7768
8595
  `;
7769
8596
 
7770
8597
  // package.json
7771
- var version = "0.1.0-beta.95";
8598
+ var version = "0.1.0-beta.97";
7772
8599
 
7773
8600
  // src/version.ts
7774
8601
  var FARM_VERSION = version;
@@ -9069,11 +9896,15 @@ __name(isObject, "isObject");
9069
9896
  // Annotate the CommonJS export names for ESM import in node:
9070
9897
  0 && (module.exports = {
9071
9898
  APIClientError,
9899
+ FARM_CACHE_INVALIDATION_CHANNEL,
9900
+ FARM_CLIENT_CACHE_PERSIST_VERSION,
9072
9901
  FarmClientPluginManager,
9902
+ FetcherInputError,
9073
9903
  IntegrationClientError,
9074
9904
  Link,
9075
9905
  SPARouter,
9076
9906
  api,
9907
+ clearPersistedCache,
9077
9908
  createAPIClient,
9078
9909
  createApiClients,
9079
9910
  createClientPluginManager,
@@ -9084,13 +9915,16 @@ __name(isObject, "isObject");
9084
9915
  createIntegrations,
9085
9916
  createServerAPIClient,
9086
9917
  createStore,
9918
+ defineClientCacheAdapter,
9087
9919
  defineIntegrationAPI,
9088
9920
  defineIntegrationAPIOperation,
9921
+ enableCrossTabCacheInvalidation,
9089
9922
  endpoint,
9090
9923
  fetchServerQuery,
9091
9924
  getIntegrationAPIManifest,
9092
9925
  getRouter,
9093
9926
  getTheme,
9927
+ initPersistedClientCache,
9094
9928
  installChunkErrorRecovery,
9095
9929
  integrationClients,
9096
9930
  integrationsClient,
@@ -9103,6 +9937,7 @@ __name(isObject, "isObject");
9103
9937
  readPageState,
9104
9938
  replaceState,
9105
9939
  setTheme,
9940
+ storageClientCacheAdapter,
9106
9941
  toggleTheme,
9107
9942
  useAction,
9108
9943
  useBlocker,