@farm.js/core 0.1.0-beta.1 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-runtime.d.mts +2 -1
- package/dist/agent-runtime.d.ts +2 -1
- package/dist/api/route-manager.cjs +410 -15
- package/dist/api/route-manager.cjs.map +1 -1
- package/dist/api/route-manager.d.mts +4 -2
- package/dist/api/route-manager.d.ts +4 -2
- package/dist/api/route-manager.mjs +9 -8
- package/dist/api/runtime.cjs +748 -9
- package/dist/api/runtime.cjs.map +1 -1
- package/dist/api/runtime.d.mts +3 -16
- package/dist/api/runtime.d.ts +3 -16
- package/dist/api/runtime.mjs +8 -1
- package/dist/api.cjs +1243 -342
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.mts +5 -147
- package/dist/api.d.ts +5 -147
- package/dist/api.mjs +51 -21
- package/dist/{app-CFRNJXP1.d.ts → app-BjN-da13.d.ts} +38 -3
- package/dist/{app-BiX4qb-d.d.mts → app-CakAr8Be.d.mts} +38 -3
- package/dist/app-markdown.cjs +1 -1
- package/dist/app-markdown.cjs.map +1 -1
- package/dist/app-markdown.d.mts +2 -1
- package/dist/app-markdown.d.ts +2 -1
- package/dist/app-markdown.mjs +1 -1
- package/dist/cache.cjs +414 -12
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.d.mts +120 -6
- package/dist/cache.d.ts +120 -6
- package/dist/cache.mjs +11 -3
- package/dist/{chunk-Y7A27276.mjs → chunk-2CUKEMVR.mjs} +349 -15
- package/dist/chunk-2CUKEMVR.mjs.map +1 -0
- package/dist/{chunk-QF4PHCMA.mjs → chunk-2ED5Q2GH.mjs} +3 -3
- package/dist/chunk-2ED5Q2GH.mjs.map +1 -0
- package/dist/{chunk-GZP5W4K3.mjs → chunk-32W4QEJP.mjs} +1 -1
- package/dist/chunk-32W4QEJP.mjs.map +1 -0
- package/dist/{chunk-TRORP7E4.mjs → chunk-3U3ZUQAQ.mjs} +2 -2
- package/dist/{chunk-25D7G34K.mjs → chunk-65A7QIKI.mjs} +5 -5
- package/dist/{chunk-25D7G34K.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
- package/dist/{chunk-G3B5BRDY.mjs → chunk-AJWRO5WE.mjs} +539 -61
- package/dist/chunk-AJWRO5WE.mjs.map +1 -0
- package/dist/chunk-ALCLXXTY.mjs +187 -0
- package/dist/chunk-ALCLXXTY.mjs.map +1 -0
- package/dist/{chunk-CHFHNEMO.mjs → chunk-AOBXKNS5.mjs} +627 -84
- package/dist/chunk-AOBXKNS5.mjs.map +1 -0
- package/dist/{chunk-B6N4ZB2H.mjs → chunk-C2ROET2V.mjs} +3 -3
- package/dist/{chunk-JN3UU635.mjs → chunk-EJ7T4TPB.mjs} +2 -2
- package/dist/chunk-EJ7T4TPB.mjs.map +1 -0
- package/dist/{chunk-ZJQNATYV.mjs → chunk-FRPWCMMG.mjs} +3 -3
- package/dist/chunk-FRPWCMMG.mjs.map +1 -0
- package/dist/{chunk-QM6VV26B.mjs → chunk-GQVGIUSN.mjs} +3 -3
- package/dist/{chunk-QM6VV26B.mjs.map → chunk-GQVGIUSN.mjs.map} +1 -1
- package/dist/{chunk-UREJA4GZ.mjs → chunk-GXASWWJU.mjs} +1 -1
- package/dist/{chunk-UREJA4GZ.mjs.map → chunk-GXASWWJU.mjs.map} +1 -1
- package/dist/{chunk-3QJO55ZF.mjs → chunk-HNIQFZKB.mjs} +5 -3
- package/dist/{chunk-3QJO55ZF.mjs.map → chunk-HNIQFZKB.mjs.map} +1 -1
- package/dist/{chunk-PRNYWD7K.mjs → chunk-JDEOUK5V.mjs} +67 -239
- package/dist/chunk-JDEOUK5V.mjs.map +1 -0
- package/dist/{chunk-O3HADRW6.mjs → chunk-MIUW47JX.mjs} +2 -2
- package/dist/{chunk-O3HADRW6.mjs.map → chunk-MIUW47JX.mjs.map} +1 -1
- package/dist/{chunk-UHE2TTLK.mjs → chunk-NM3CRAAL.mjs} +9 -8
- package/dist/chunk-NM3CRAAL.mjs.map +1 -0
- package/dist/chunk-PFE6GMNE.mjs +603 -0
- package/dist/chunk-PFE6GMNE.mjs.map +1 -0
- package/dist/{chunk-S2XHZS7W.mjs → chunk-QGQX7SFC.mjs} +2 -2
- package/dist/chunk-QGQX7SFC.mjs.map +1 -0
- package/dist/{chunk-RKI6TN3A.mjs → chunk-QM746KUO.mjs} +9 -2
- package/dist/chunk-QM746KUO.mjs.map +1 -0
- package/dist/chunk-RBRLLZL5.mjs +81 -0
- package/dist/chunk-RBRLLZL5.mjs.map +1 -0
- package/dist/{chunk-HXP3ZSPC.mjs → chunk-SADGIRS2.mjs} +3 -3
- package/dist/{chunk-6XDUHOEM.mjs → chunk-TQAEEJB4.mjs} +3 -3
- package/dist/{chunk-AGS7UJ52.mjs → chunk-UB5UOSHB.mjs} +24 -12
- package/dist/chunk-UB5UOSHB.mjs.map +1 -0
- package/dist/{chunk-SXZTEK3V.mjs → chunk-UXUAWNO5.mjs} +2 -2
- package/dist/chunk-V3XURYJO.mjs +756 -0
- package/dist/chunk-V3XURYJO.mjs.map +1 -0
- package/dist/{chunk-TU4YJICB.mjs → chunk-VVKWFZAH.mjs} +41 -16
- package/dist/chunk-VVKWFZAH.mjs.map +1 -0
- package/dist/{chunk-JLWMCADZ.mjs → chunk-VY2UYN5R.mjs} +24 -4
- package/dist/chunk-VY2UYN5R.mjs.map +1 -0
- package/dist/{chunk-QFQRHRZS.mjs → chunk-W2CRQFF6.mjs} +151 -23
- package/dist/chunk-W2CRQFF6.mjs.map +1 -0
- package/dist/chunk-W4UIVMVI.mjs +10 -0
- package/dist/chunk-W4UIVMVI.mjs.map +1 -0
- package/dist/{chunk-Y2OJJD7R.mjs → chunk-XIVV5IWN.mjs} +7 -9
- package/dist/chunk-XIVV5IWN.mjs.map +1 -0
- package/dist/{chunk-OYXO65LI.mjs → chunk-YW7OBE6Q.mjs} +4 -4
- package/dist/chunk-YW7OBE6Q.mjs.map +1 -0
- package/dist/{chunk-YHU7SS6L.mjs → chunk-Z5CQMP54.mjs} +11 -11
- package/dist/{chunk-SOU3Q3ZA.mjs → chunk-ZZ57EH5Z.mjs} +1 -1
- package/dist/chunk-ZZ57EH5Z.mjs.map +1 -0
- package/dist/{client-D_yUjVhe.d.mts → client-BT1mFQas.d.mts} +55 -10
- package/dist/{client-Dkc03WP8.d.ts → client-Nn0q4eO4.d.ts} +55 -10
- package/dist/{client-plugins-BZnpeTGA.d.ts → client-plugins-Cw4qUGsw.d.ts} +7 -0
- package/dist/{client-plugins-g4bzuCmo.d.mts → client-plugins-DQQ1adXM.d.mts} +7 -0
- package/dist/client-plugins.d.mts +2 -1
- package/dist/client-plugins.d.ts +2 -1
- package/dist/client.cjs +922 -91
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.mts +121 -3
- package/dist/client.d.ts +121 -3
- package/dist/client.mjs +23 -16
- package/dist/config.d.mts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.mjs +1 -1
- package/dist/{devtools-AE4RVXCM.mjs → devtools-LVC3VB5P.mjs} +10 -10
- package/dist/{devtools-client-6WPY2AQU.mjs → devtools-client-3XRTBND5.mjs} +2 -11
- package/dist/devtools-client-3XRTBND5.mjs.map +1 -0
- package/dist/docs.cjs +14 -2
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.mjs +10 -10
- package/dist/i18n/server.cjs +2 -2
- package/dist/i18n/server.cjs.map +1 -1
- package/dist/i18n/server.mjs +1 -1
- package/dist/index.cjs +2852 -463
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +13 -12
- package/dist/index.d.ts +13 -12
- package/dist/index.mjs +152 -109
- package/dist/index.mjs.map +1 -1
- package/dist/integrations.d.mts +2 -1
- package/dist/integrations.d.ts +2 -1
- package/dist/internal/build-runtime.cjs +1616 -149
- package/dist/internal/build-runtime.cjs.map +1 -1
- package/dist/internal/build-runtime.d.mts +4 -3
- package/dist/internal/build-runtime.d.ts +4 -3
- package/dist/internal/build-runtime.mjs +27 -25
- package/dist/internal/client-runtime.cjs.map +1 -1
- package/dist/internal/client-runtime.mjs +1 -1
- package/dist/internal/config-runtime.cjs +13 -2
- package/dist/internal/config-runtime.cjs.map +1 -1
- package/dist/internal/config-runtime.d.mts +3 -2
- package/dist/internal/config-runtime.d.ts +3 -2
- package/dist/internal/config-runtime.mjs +9 -9
- package/dist/internal/production-runtime.cjs +285 -9
- package/dist/internal/production-runtime.cjs.map +1 -1
- package/dist/internal/production-runtime.d.mts +4 -4
- package/dist/internal/production-runtime.d.ts +4 -4
- package/dist/internal/production-runtime.mjs +10 -8
- package/dist/{metadata-DAXRaOHx.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
- package/dist/{metadata-C9NZxMDW.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
- package/dist/middleware.cjs +2 -2
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.mts +4 -3
- package/dist/middleware.d.ts +4 -3
- package/dist/middleware.mjs +3 -3
- package/dist/navigation.cjs +40 -15
- package/dist/navigation.cjs.map +1 -1
- package/dist/navigation.mjs +3 -3
- package/dist/{nitro-KME62MWG.mjs → nitro-QO5LV6QK.mjs} +11 -13
- package/dist/{nitro-KME62MWG.mjs.map → nitro-QO5LV6QK.mjs.map} +1 -1
- package/dist/plugin.cjs +1032 -92
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.mts +2 -1
- package/dist/plugin.d.ts +2 -1
- package/dist/plugin.mjs +23 -21
- package/dist/{production-runtime-DRkCHUvJ.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
- package/dist/{production-runtime-flrjp_nC.d.mts → production-runtime-DPfgMV9Y.d.mts} +1 -1
- package/dist/routes.cjs +276 -6
- package/dist/routes.cjs.map +1 -1
- package/dist/routes.d.mts +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/routes.mjs +4 -4
- package/dist/runtime-9nQjVM7X.d.mts +206 -0
- package/dist/runtime-DgeS2skB.d.ts +206 -0
- package/dist/server-action-security.cjs +28 -10
- package/dist/server-action-security.cjs.map +1 -1
- package/dist/server-action-security.d.mts +2 -1
- package/dist/server-action-security.d.ts +2 -1
- package/dist/server-action-security.mjs +2 -2
- package/dist/server-fn-client.cjs.map +1 -1
- package/dist/server-fn-client.d.mts +1 -0
- package/dist/server-fn-client.d.ts +1 -0
- package/dist/server-fn-client.mjs +1 -1
- package/dist/server-fn.cjs +785 -3
- package/dist/server-fn.cjs.map +1 -1
- package/dist/server-fn.d.mts +10 -1
- package/dist/server-fn.d.ts +10 -1
- package/dist/server-fn.mjs +6 -3
- package/dist/server-plugins.d.mts +3 -2
- package/dist/server-plugins.d.ts +3 -2
- package/dist/server-query-client.cjs +278 -7
- package/dist/server-query-client.cjs.map +1 -1
- package/dist/server-query-client.mjs +4 -4
- package/dist/server-query.cjs +381 -10
- package/dist/server-query.cjs.map +1 -1
- package/dist/server-query.mjs +5 -5
- package/dist/server.cjs +1233 -118
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.mts +8 -7
- package/dist/server.d.ts +8 -7
- package/dist/server.mjs +53 -33
- package/dist/server.mjs.map +1 -1
- package/dist/testing.cjs +436 -25
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.mts +4 -3
- package/dist/testing.d.ts +4 -3
- package/dist/testing.mjs +19 -18
- package/dist/testing.mjs.map +1 -1
- package/dist/transport-BmbGTXA5.d.mts +49 -0
- package/dist/transport-BmbGTXA5.d.ts +49 -0
- package/dist/{utils-DOXXivjL.d.mts → utils-CHXlMDkg.d.mts} +1 -1
- package/dist/{utils-DA1yo54_.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
- package/dist/version.cjs +36 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.d.mts +3 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.mjs +8 -0
- package/dist/version.mjs.map +1 -0
- package/dist/vite.cjs +1039 -93
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.mts +2 -1
- package/dist/vite.d.ts +2 -1
- package/dist/vite.mjs +23 -21
- package/dist/workflows.cjs +6 -8
- package/dist/workflows.cjs.map +1 -1
- package/dist/workflows.mjs +1 -1
- package/package.json +12 -5
- package/types/api.d.ts +44 -0
- package/types/client.d.ts +220 -16
- package/dist/chunk-4PTK6KT4.mjs +0 -364
- package/dist/chunk-4PTK6KT4.mjs.map +0 -1
- package/dist/chunk-AGS7UJ52.mjs.map +0 -1
- package/dist/chunk-CHFHNEMO.mjs.map +0 -1
- package/dist/chunk-EVGBEZDF.mjs +0 -215
- package/dist/chunk-EVGBEZDF.mjs.map +0 -1
- package/dist/chunk-G3B5BRDY.mjs.map +0 -1
- package/dist/chunk-GZP5W4K3.mjs.map +0 -1
- package/dist/chunk-JLWMCADZ.mjs.map +0 -1
- package/dist/chunk-JN3UU635.mjs.map +0 -1
- package/dist/chunk-OYXO65LI.mjs.map +0 -1
- package/dist/chunk-PRNYWD7K.mjs.map +0 -1
- package/dist/chunk-QF4PHCMA.mjs.map +0 -1
- package/dist/chunk-QFQRHRZS.mjs.map +0 -1
- package/dist/chunk-RKI6TN3A.mjs.map +0 -1
- package/dist/chunk-S2XHZS7W.mjs.map +0 -1
- package/dist/chunk-SOU3Q3ZA.mjs.map +0 -1
- package/dist/chunk-TU4YJICB.mjs.map +0 -1
- package/dist/chunk-TXCFGOHW.mjs +0 -42
- package/dist/chunk-TXCFGOHW.mjs.map +0 -1
- package/dist/chunk-UHE2TTLK.mjs.map +0 -1
- package/dist/chunk-Y2OJJD7R.mjs.map +0 -1
- package/dist/chunk-Y7A27276.mjs.map +0 -1
- package/dist/chunk-ZJQNATYV.mjs.map +0 -1
- package/dist/devtools-client-6WPY2AQU.mjs.map +0 -1
- /package/dist/{chunk-TRORP7E4.mjs.map → chunk-3U3ZUQAQ.mjs.map} +0 -0
- /package/dist/{chunk-B6N4ZB2H.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
- /package/dist/{chunk-HXP3ZSPC.mjs.map → chunk-SADGIRS2.mjs.map} +0 -0
- /package/dist/{chunk-6XDUHOEM.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
- /package/dist/{chunk-SXZTEK3V.mjs.map → chunk-UXUAWNO5.mjs.map} +0 -0
- /package/dist/{chunk-YHU7SS6L.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
- /package/dist/{devtools-AE4RVXCM.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
package/dist/plugin.cjs
CHANGED
|
@@ -309,7 +309,7 @@ function createFarmMarkdownRouteModule(input) {
|
|
|
309
309
|
...props,
|
|
310
310
|
components: {
|
|
311
311
|
...components,
|
|
312
|
-
...props?.components
|
|
312
|
+
...props?.components
|
|
313
313
|
}
|
|
314
314
|
})
|
|
315
315
|
);
|
|
@@ -826,7 +826,11 @@ async function prepareFarmWorkflowsForNitro(config) {
|
|
|
826
826
|
};
|
|
827
827
|
}
|
|
828
828
|
const handlerPath = path22.join(generatedDir, "http-handler.mjs");
|
|
829
|
-
await fs8.writeFile(
|
|
829
|
+
await fs8.writeFile(
|
|
830
|
+
handlerPath,
|
|
831
|
+
createNitroWorkflowHTTPHandler(workflowConfig, workflows),
|
|
832
|
+
"utf8"
|
|
833
|
+
);
|
|
830
834
|
const manifestPath = path22.join(generatedDir, "manifest.json");
|
|
831
835
|
await fs8.writeFile(
|
|
832
836
|
manifestPath,
|
|
@@ -900,13 +904,7 @@ function normalizeSchedule(schedule) {
|
|
|
900
904
|
return (Array.isArray(schedule) ? schedule : [schedule]).map((value) => value.trim()).filter(Boolean);
|
|
901
905
|
}
|
|
902
906
|
function resolveWorkflowDefinition(module2) {
|
|
903
|
-
const candidates = [
|
|
904
|
-
module2.default,
|
|
905
|
-
module2.workflow,
|
|
906
|
-
module2.cron,
|
|
907
|
-
module2.task,
|
|
908
|
-
module2.job
|
|
909
|
-
];
|
|
907
|
+
const candidates = [module2.default, module2.workflow, module2.cron, module2.task, module2.job];
|
|
910
908
|
for (const candidate of candidates) {
|
|
911
909
|
if (candidate && typeof candidate === "object" && typeof candidate.run === "function") {
|
|
912
910
|
return candidate;
|
|
@@ -1899,8 +1897,8 @@ function compareFarmRouteRuleSpecificity(left, right) {
|
|
|
1899
1897
|
}
|
|
1900
1898
|
function getFarmRouteRuleSpecificity(pattern) {
|
|
1901
1899
|
return normalizeRoutePattern(pattern).split("/").filter(Boolean).reduce((score, segment) => {
|
|
1902
|
-
if (segment === "**" ||
|
|
1903
|
-
if (segment === "*" ||
|
|
1900
|
+
if (segment === "**" || segment.startsWith("[[...")) return score + 1;
|
|
1901
|
+
if (segment === "*" || segment.startsWith("[...")) return score + 10;
|
|
1904
1902
|
if (/^\[.+\]$/.test(segment) || /^:.+$/.test(segment)) return score + 50;
|
|
1905
1903
|
return score + 100;
|
|
1906
1904
|
}, 0);
|
|
@@ -1960,22 +1958,50 @@ var init_route_rules = __esm({
|
|
|
1960
1958
|
// src/cache-invalidation.ts
|
|
1961
1959
|
function getFarmCacheInvalidationState() {
|
|
1962
1960
|
return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
|
|
1963
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1961
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1962
|
+
taskListeners: /* @__PURE__ */ new Set()
|
|
1964
1963
|
});
|
|
1965
1964
|
}
|
|
1965
|
+
function encodeFarmCacheInvalidations(keys) {
|
|
1966
|
+
const normalized = Array.from(
|
|
1967
|
+
new Set(keys.filter((key) => typeof key === "string" && key.length > 0))
|
|
1968
|
+
);
|
|
1969
|
+
if (normalized.length === 0) return null;
|
|
1970
|
+
return encodeURIComponent(JSON.stringify(normalized));
|
|
1971
|
+
}
|
|
1972
|
+
function decodeFarmCacheInvalidations(value) {
|
|
1973
|
+
if (!value) return [];
|
|
1974
|
+
try {
|
|
1975
|
+
const parsed = JSON.parse(decodeURIComponent(value));
|
|
1976
|
+
return Array.isArray(parsed) ? Array.from(
|
|
1977
|
+
new Set(parsed.filter((key) => typeof key === "string" && key.length > 0))
|
|
1978
|
+
) : [];
|
|
1979
|
+
} catch {
|
|
1980
|
+
return [];
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1966
1983
|
function subscribeFarmCacheInvalidation(listener) {
|
|
1967
1984
|
const state = getFarmCacheInvalidationState();
|
|
1968
1985
|
state.listeners.add(listener);
|
|
1969
1986
|
return () => state.listeners.delete(listener);
|
|
1970
1987
|
}
|
|
1971
|
-
|
|
1988
|
+
function subscribeFarmCacheTask(listener) {
|
|
1989
|
+
const state = getFarmCacheInvalidationState();
|
|
1990
|
+
state.taskListeners.add(listener);
|
|
1991
|
+
return () => state.taskListeners.delete(listener);
|
|
1992
|
+
}
|
|
1993
|
+
var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
|
|
1972
1994
|
var init_cache_invalidation = __esm({
|
|
1973
1995
|
"src/cache-invalidation.ts"() {
|
|
1974
1996
|
"use strict";
|
|
1997
|
+
FARM_CACHE_INVALIDATION_HEADER = "x-farm-cache-invalidations";
|
|
1975
1998
|
FARM_CACHE_INVALIDATION_STATE = /* @__PURE__ */ Symbol.for("farm.cacheInvalidationState");
|
|
1976
1999
|
globalState = globalThis;
|
|
1977
2000
|
__name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
|
|
2001
|
+
__name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
|
|
2002
|
+
__name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
|
|
1978
2003
|
__name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
|
|
2004
|
+
__name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
|
|
1979
2005
|
}
|
|
1980
2006
|
});
|
|
1981
2007
|
|
|
@@ -2079,6 +2105,9 @@ var init_server_action_security = __esm({
|
|
|
2079
2105
|
subscribeFarmCacheInvalidation((key) => {
|
|
2080
2106
|
getServerActionExecutionContext()?.invalidations.add(key);
|
|
2081
2107
|
});
|
|
2108
|
+
subscribeFarmCacheTask((task) => {
|
|
2109
|
+
getServerActionExecutionContext()?.cacheTasks.add(task);
|
|
2110
|
+
});
|
|
2082
2111
|
__name(getServerActionStorage, "getServerActionStorage");
|
|
2083
2112
|
__name(parseBodySizeLimit, "parseBodySizeLimit");
|
|
2084
2113
|
__name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
|
|
@@ -4534,7 +4563,9 @@ function readManifest(contentDir) {
|
|
|
4534
4563
|
const manifestPath = import_node_path7.default.join(contentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
|
|
4535
4564
|
if (!(0, import_node_fs5.existsSync)(manifestPath)) return null;
|
|
4536
4565
|
try {
|
|
4537
|
-
const parsed = JSON.parse(
|
|
4566
|
+
const parsed = JSON.parse(
|
|
4567
|
+
(0, import_node_fs5.readFileSync)(manifestPath, "utf8")
|
|
4568
|
+
);
|
|
4538
4569
|
if (parsed.version !== 1 || !parsed.pages || typeof parsed.pages !== "object") return null;
|
|
4539
4570
|
const pages = Object.fromEntries(
|
|
4540
4571
|
Object.entries(parsed.pages).filter(
|
|
@@ -10706,16 +10737,7 @@ __export(devtools_client_exports, {
|
|
|
10706
10737
|
function parseShortcut(shortcut) {
|
|
10707
10738
|
const tokens = shortcut.toLowerCase().split("+").map((token) => token.trim()).filter(Boolean);
|
|
10708
10739
|
const key = tokens.find(
|
|
10709
|
-
(token) => ![
|
|
10710
|
-
"alt",
|
|
10711
|
-
"ctrl",
|
|
10712
|
-
"control",
|
|
10713
|
-
"meta",
|
|
10714
|
-
"cmd",
|
|
10715
|
-
"command",
|
|
10716
|
-
"mod",
|
|
10717
|
-
"shift"
|
|
10718
|
-
].includes(token)
|
|
10740
|
+
(token) => !["alt", "ctrl", "control", "meta", "cmd", "command", "mod", "shift"].includes(token)
|
|
10719
10741
|
);
|
|
10720
10742
|
if (!key) {
|
|
10721
10743
|
return null;
|
|
@@ -11655,11 +11677,51 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
|
|
|
11655
11677
|
// src/cache.ts
|
|
11656
11678
|
init_cache_invalidation();
|
|
11657
11679
|
var _FarmDataCache = class _FarmDataCache {
|
|
11658
|
-
constructor() {
|
|
11680
|
+
constructor(config = {}) {
|
|
11659
11681
|
this.entries = /* @__PURE__ */ new Map();
|
|
11660
11682
|
this.inflight = /* @__PURE__ */ new Map();
|
|
11661
11683
|
this.invalidatedTagVersions = /* @__PURE__ */ new Map();
|
|
11662
11684
|
this.version = 0;
|
|
11685
|
+
this.namespace = "farm";
|
|
11686
|
+
this.local = true;
|
|
11687
|
+
this.lease = {
|
|
11688
|
+
enabled: true,
|
|
11689
|
+
ttlMs: 1e4,
|
|
11690
|
+
waitTimeoutMs: 1e4,
|
|
11691
|
+
pollIntervalMs: 25
|
|
11692
|
+
};
|
|
11693
|
+
this.configure(config);
|
|
11694
|
+
}
|
|
11695
|
+
configure(config = {}) {
|
|
11696
|
+
this.adapter = config.adapter;
|
|
11697
|
+
this.namespace = normalizeCacheNamespace(config.namespace || "farm");
|
|
11698
|
+
this.local = !config.adapter;
|
|
11699
|
+
this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
|
|
11700
|
+
enabled: true,
|
|
11701
|
+
ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
|
|
11702
|
+
waitTimeoutMs: normalizePositiveDuration(
|
|
11703
|
+
config.lease?.waitTimeoutMs,
|
|
11704
|
+
1e4,
|
|
11705
|
+
"cache.lease.waitTimeoutMs"
|
|
11706
|
+
),
|
|
11707
|
+
pollIntervalMs: normalizePositiveDuration(
|
|
11708
|
+
config.lease?.pollIntervalMs,
|
|
11709
|
+
25,
|
|
11710
|
+
"cache.lease.pollIntervalMs"
|
|
11711
|
+
)
|
|
11712
|
+
};
|
|
11713
|
+
if (!this.local) {
|
|
11714
|
+
this.entries.clear();
|
|
11715
|
+
this.inflight.clear();
|
|
11716
|
+
this.invalidatedTagVersions.clear();
|
|
11717
|
+
this.version = 0;
|
|
11718
|
+
}
|
|
11719
|
+
}
|
|
11720
|
+
get adapterName() {
|
|
11721
|
+
return this.adapter?.name || (this.adapter ? "custom" : "memory");
|
|
11722
|
+
}
|
|
11723
|
+
get hasAdapter() {
|
|
11724
|
+
return this.adapter !== void 0;
|
|
11663
11725
|
}
|
|
11664
11726
|
get size() {
|
|
11665
11727
|
return this.entries.size;
|
|
@@ -11695,6 +11757,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11695
11757
|
});
|
|
11696
11758
|
return this.toPublicEntry(entry);
|
|
11697
11759
|
}
|
|
11760
|
+
async getEntryAsync(key, options = {}) {
|
|
11761
|
+
if (this.local) {
|
|
11762
|
+
const localEntry = this.getEntry(key, options);
|
|
11763
|
+
if (localEntry) return localEntry;
|
|
11764
|
+
}
|
|
11765
|
+
if (!this.adapter) {
|
|
11766
|
+
return this.local ? void 0 : this.getEntry(key, options);
|
|
11767
|
+
}
|
|
11768
|
+
const entry = await this.adapter.get(this.createAdapterKey(key));
|
|
11769
|
+
if (!entry) {
|
|
11770
|
+
emitFarmEvent({ type: "cache.miss", key });
|
|
11771
|
+
return void 0;
|
|
11772
|
+
}
|
|
11773
|
+
assertFarmCacheEntry(entry, key);
|
|
11774
|
+
const stale = await this.isAdapterEntryStale(entry, options.now);
|
|
11775
|
+
if (stale) {
|
|
11776
|
+
emitFarmEvent({
|
|
11777
|
+
type: "cache.stale",
|
|
11778
|
+
key,
|
|
11779
|
+
tags: [...entry.tags],
|
|
11780
|
+
revalidate: entry.revalidate
|
|
11781
|
+
});
|
|
11782
|
+
if (!options.allowStale) {
|
|
11783
|
+
emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
|
|
11784
|
+
return void 0;
|
|
11785
|
+
}
|
|
11786
|
+
}
|
|
11787
|
+
emitFarmEvent({
|
|
11788
|
+
type: "cache.hit",
|
|
11789
|
+
key,
|
|
11790
|
+
tags: [...entry.tags],
|
|
11791
|
+
revalidate: entry.revalidate,
|
|
11792
|
+
stale
|
|
11793
|
+
});
|
|
11794
|
+
if (this.local && !stale) {
|
|
11795
|
+
this.hydrateLocalEntry(entry);
|
|
11796
|
+
}
|
|
11797
|
+
return { ...entry, key };
|
|
11798
|
+
}
|
|
11698
11799
|
set(key, value, options = {}) {
|
|
11699
11800
|
const tags = /* @__PURE__ */ new Set();
|
|
11700
11801
|
for (const tag of options.tags ?? []) {
|
|
@@ -11707,6 +11808,7 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11707
11808
|
key,
|
|
11708
11809
|
value,
|
|
11709
11810
|
tags,
|
|
11811
|
+
tagVersions: void 0,
|
|
11710
11812
|
createdAt: options.createdAt ?? Date.now(),
|
|
11711
11813
|
createdVersion: ++this.version,
|
|
11712
11814
|
revalidate: normalizeRevalidate(options.revalidate)
|
|
@@ -11720,11 +11822,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11720
11822
|
});
|
|
11721
11823
|
return this.toPublicEntry(entry);
|
|
11722
11824
|
}
|
|
11825
|
+
async setAsync(key, value, options = {}, tagVersions) {
|
|
11826
|
+
const tags = normalizeCacheOptionsTags(options);
|
|
11827
|
+
const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
|
|
11828
|
+
const entry = {
|
|
11829
|
+
key,
|
|
11830
|
+
value,
|
|
11831
|
+
tags: Array.from(tags),
|
|
11832
|
+
tagVersions: capturedVersions,
|
|
11833
|
+
createdAt: options.createdAt ?? Date.now(),
|
|
11834
|
+
createdVersion: ++this.version,
|
|
11835
|
+
revalidate: normalizeRevalidate(options.revalidate)
|
|
11836
|
+
};
|
|
11837
|
+
if (this.local) {
|
|
11838
|
+
this.hydrateLocalEntry(entry);
|
|
11839
|
+
}
|
|
11840
|
+
if (this.adapter) {
|
|
11841
|
+
await this.adapter.set(this.createAdapterKey(key), entry);
|
|
11842
|
+
}
|
|
11843
|
+
emitFarmEvent({
|
|
11844
|
+
type: "cache.set",
|
|
11845
|
+
key,
|
|
11846
|
+
tags: [...entry.tags],
|
|
11847
|
+
revalidate: entry.revalidate
|
|
11848
|
+
});
|
|
11849
|
+
return entry;
|
|
11850
|
+
}
|
|
11723
11851
|
delete(key) {
|
|
11724
11852
|
const deleted = this.entries.delete(key);
|
|
11725
11853
|
emitFarmEvent({ type: "cache.delete", key, deleted });
|
|
11726
11854
|
return deleted;
|
|
11727
11855
|
}
|
|
11856
|
+
async deleteAsync(key) {
|
|
11857
|
+
const deleted = this.entries.delete(key);
|
|
11858
|
+
if (this.adapter) {
|
|
11859
|
+
await this.adapter.delete(this.createAdapterKey(key));
|
|
11860
|
+
}
|
|
11861
|
+
emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
|
|
11862
|
+
return this.adapter ? true : deleted;
|
|
11863
|
+
}
|
|
11728
11864
|
clear() {
|
|
11729
11865
|
const count = this.entries.size;
|
|
11730
11866
|
this.entries.clear();
|
|
@@ -11733,6 +11869,10 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11733
11869
|
this.version = 0;
|
|
11734
11870
|
emitFarmEvent({ type: "cache.clear", count });
|
|
11735
11871
|
}
|
|
11872
|
+
async clearAsync() {
|
|
11873
|
+
this.clear();
|
|
11874
|
+
await this.adapter?.clear?.();
|
|
11875
|
+
}
|
|
11736
11876
|
isStale(entry, now = Date.now()) {
|
|
11737
11877
|
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
11738
11878
|
return true;
|
|
@@ -11745,6 +11885,12 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11745
11885
|
}
|
|
11746
11886
|
return false;
|
|
11747
11887
|
}
|
|
11888
|
+
async isStaleAsync(entry, now = Date.now()) {
|
|
11889
|
+
if (this.adapter) {
|
|
11890
|
+
return this.isAdapterEntryStale(entry, now);
|
|
11891
|
+
}
|
|
11892
|
+
return this.isStale(entry, now);
|
|
11893
|
+
}
|
|
11748
11894
|
revalidateTag(tag, options = {}) {
|
|
11749
11895
|
const normalized = normalizeCacheTag(tag);
|
|
11750
11896
|
const count = this.invalidateTag(normalized);
|
|
@@ -11753,6 +11899,15 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11753
11899
|
);
|
|
11754
11900
|
return count;
|
|
11755
11901
|
}
|
|
11902
|
+
async revalidateTagAsync(tag, options = {}) {
|
|
11903
|
+
const normalized = normalizeCacheTag(tag);
|
|
11904
|
+
const count = this.invalidateTag(normalized);
|
|
11905
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
|
|
11906
|
+
emitFarmEvent(
|
|
11907
|
+
options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
|
|
11908
|
+
);
|
|
11909
|
+
return count;
|
|
11910
|
+
}
|
|
11756
11911
|
revalidatePath(routePath) {
|
|
11757
11912
|
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
11758
11913
|
const pathTag = createPathCacheTag(normalizedPath);
|
|
@@ -11769,8 +11924,25 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11769
11924
|
}
|
|
11770
11925
|
return count;
|
|
11771
11926
|
}
|
|
11927
|
+
async revalidatePathAsync(routePath) {
|
|
11928
|
+
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
11929
|
+
const pathTag = createPathCacheTag(normalizedPath);
|
|
11930
|
+
const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
|
|
11931
|
+
const count = this.invalidateTag(pathTag);
|
|
11932
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
|
|
11933
|
+
emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
|
|
11934
|
+
if (pprCount > 0) {
|
|
11935
|
+
emitFarmEvent({
|
|
11936
|
+
type: "ppr.shell.invalidated",
|
|
11937
|
+
route: normalizedPath,
|
|
11938
|
+
reason: "revalidatePath",
|
|
11939
|
+
count: pprCount
|
|
11940
|
+
});
|
|
11941
|
+
}
|
|
11942
|
+
return count;
|
|
11943
|
+
}
|
|
11772
11944
|
async getOrSet(key, producer, options = {}) {
|
|
11773
|
-
const cached = this.
|
|
11945
|
+
const cached = await this.getEntryAsync(key);
|
|
11774
11946
|
if (cached) {
|
|
11775
11947
|
return cached.value;
|
|
11776
11948
|
}
|
|
@@ -11779,10 +11951,8 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11779
11951
|
emitFarmEvent({ type: "cache.dedupe", key });
|
|
11780
11952
|
return inflight;
|
|
11781
11953
|
}
|
|
11782
|
-
const
|
|
11783
|
-
|
|
11784
|
-
return value;
|
|
11785
|
-
}).catch((error) => {
|
|
11954
|
+
const tags = Array.from(normalizeCacheOptionsTags(options));
|
|
11955
|
+
const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
|
|
11786
11956
|
emitFarmEvent({ type: "cache.error", key, operation: "set", error });
|
|
11787
11957
|
throw error;
|
|
11788
11958
|
}).finally(() => {
|
|
@@ -11791,6 +11961,40 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11791
11961
|
this.inflight.set(key, promise);
|
|
11792
11962
|
return promise;
|
|
11793
11963
|
}
|
|
11964
|
+
async fillCacheEntry(key, producer, options, tags) {
|
|
11965
|
+
const leaseKey = `${this.namespace}:lease:${key}`;
|
|
11966
|
+
let leaseToken;
|
|
11967
|
+
if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
|
|
11968
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
11969
|
+
if (!leaseToken) {
|
|
11970
|
+
const shared = await this.waitForAdapterEntry(key);
|
|
11971
|
+
if (shared) {
|
|
11972
|
+
emitFarmEvent({ type: "cache.dedupe", key });
|
|
11973
|
+
return shared.value;
|
|
11974
|
+
}
|
|
11975
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
try {
|
|
11979
|
+
const initialTagVersions = await this.getAdapterTagVersions(tags);
|
|
11980
|
+
const value = await producer();
|
|
11981
|
+
await this.setAsync(key, value, options, initialTagVersions);
|
|
11982
|
+
return value;
|
|
11983
|
+
} finally {
|
|
11984
|
+
if (leaseToken && this.adapter?.releaseLease) {
|
|
11985
|
+
await this.adapter.releaseLease(leaseKey, leaseToken);
|
|
11986
|
+
}
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
async waitForAdapterEntry(key) {
|
|
11990
|
+
const deadline = Date.now() + this.lease.waitTimeoutMs;
|
|
11991
|
+
while (Date.now() < deadline) {
|
|
11992
|
+
await delay(this.lease.pollIntervalMs);
|
|
11993
|
+
const entry = await this.getEntryAsync(key);
|
|
11994
|
+
if (entry) return entry;
|
|
11995
|
+
}
|
|
11996
|
+
return void 0;
|
|
11997
|
+
}
|
|
11794
11998
|
countEntriesForTag(tag) {
|
|
11795
11999
|
let count = 0;
|
|
11796
12000
|
for (const entry of this.entries.values()) {
|
|
@@ -11818,11 +12022,53 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11818
12022
|
key: entry.key,
|
|
11819
12023
|
value: entry.value,
|
|
11820
12024
|
tags: Array.from(entry.tags),
|
|
12025
|
+
tagVersions: entry.tagVersions,
|
|
11821
12026
|
createdAt: entry.createdAt,
|
|
11822
12027
|
createdVersion: entry.createdVersion,
|
|
11823
12028
|
revalidate: entry.revalidate
|
|
11824
12029
|
};
|
|
11825
12030
|
}
|
|
12031
|
+
hydrateLocalEntry(entry) {
|
|
12032
|
+
this.entries.set(entry.key, {
|
|
12033
|
+
key: entry.key,
|
|
12034
|
+
value: entry.value,
|
|
12035
|
+
tags: new Set(entry.tags.map(normalizeCacheTag)),
|
|
12036
|
+
tagVersions: entry.tagVersions,
|
|
12037
|
+
createdAt: entry.createdAt,
|
|
12038
|
+
createdVersion: entry.createdVersion ?? ++this.version,
|
|
12039
|
+
revalidate: normalizeRevalidate(entry.revalidate)
|
|
12040
|
+
});
|
|
12041
|
+
}
|
|
12042
|
+
createAdapterKey(key) {
|
|
12043
|
+
return `${this.namespace}:entry:${key}`;
|
|
12044
|
+
}
|
|
12045
|
+
createAdapterTag(tag) {
|
|
12046
|
+
return `${this.namespace}:tag:${tag}`;
|
|
12047
|
+
}
|
|
12048
|
+
async getAdapterTagVersions(tags) {
|
|
12049
|
+
if (!this.adapter?.getTagVersions || tags.length === 0) return {};
|
|
12050
|
+
const normalized = tags.map(normalizeCacheTag);
|
|
12051
|
+
const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
|
|
12052
|
+
const versions = await this.adapter.getTagVersions(physicalTags);
|
|
12053
|
+
return Object.fromEntries(
|
|
12054
|
+
normalized.map((tag, index) => [
|
|
12055
|
+
tag,
|
|
12056
|
+
normalizeAdapterVersion(versions[physicalTags[index]])
|
|
12057
|
+
])
|
|
12058
|
+
);
|
|
12059
|
+
}
|
|
12060
|
+
async isAdapterEntryStale(entry, now = Date.now()) {
|
|
12061
|
+
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
12062
|
+
return true;
|
|
12063
|
+
}
|
|
12064
|
+
const currentVersions = await this.getAdapterTagVersions(entry.tags);
|
|
12065
|
+
for (const tag of entry.tags) {
|
|
12066
|
+
if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
|
|
12067
|
+
return true;
|
|
12068
|
+
}
|
|
12069
|
+
}
|
|
12070
|
+
return false;
|
|
12071
|
+
}
|
|
11826
12072
|
};
|
|
11827
12073
|
__name(_FarmDataCache, "FarmDataCache");
|
|
11828
12074
|
var FarmDataCache = _FarmDataCache;
|
|
@@ -11835,6 +12081,10 @@ function getFarmDataCache() {
|
|
|
11835
12081
|
return sharedFarmDataCache;
|
|
11836
12082
|
}
|
|
11837
12083
|
__name(getFarmDataCache, "getFarmDataCache");
|
|
12084
|
+
function configureFarmCache(config) {
|
|
12085
|
+
sharedFarmDataCache.configure(config);
|
|
12086
|
+
}
|
|
12087
|
+
__name(configureFarmCache, "configureFarmCache");
|
|
11838
12088
|
function createPathCacheTag(routePath) {
|
|
11839
12089
|
return `path:${normalizeRevalidatePath(routePath)}`;
|
|
11840
12090
|
}
|
|
@@ -11895,6 +12145,52 @@ function normalizeCacheTag(tag) {
|
|
|
11895
12145
|
return normalized;
|
|
11896
12146
|
}
|
|
11897
12147
|
__name(normalizeCacheTag, "normalizeCacheTag");
|
|
12148
|
+
function normalizeCacheNamespace(namespace) {
|
|
12149
|
+
if (typeof namespace !== "string") {
|
|
12150
|
+
throw new TypeError("Cache namespace must be a string.");
|
|
12151
|
+
}
|
|
12152
|
+
const normalized = namespace.trim().replace(/:+$/g, "");
|
|
12153
|
+
if (!normalized) {
|
|
12154
|
+
throw new Error("Cache namespace cannot be empty.");
|
|
12155
|
+
}
|
|
12156
|
+
return normalized;
|
|
12157
|
+
}
|
|
12158
|
+
__name(normalizeCacheNamespace, "normalizeCacheNamespace");
|
|
12159
|
+
function normalizeAdapterVersion(value) {
|
|
12160
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
12161
|
+
}
|
|
12162
|
+
__name(normalizeAdapterVersion, "normalizeAdapterVersion");
|
|
12163
|
+
function normalizePositiveDuration(value, fallback, name) {
|
|
12164
|
+
if (value === void 0) return fallback;
|
|
12165
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
12166
|
+
throw new TypeError(`${name} must be a positive number of milliseconds.`);
|
|
12167
|
+
}
|
|
12168
|
+
return Math.floor(value);
|
|
12169
|
+
}
|
|
12170
|
+
__name(normalizePositiveDuration, "normalizePositiveDuration");
|
|
12171
|
+
function delay(ms) {
|
|
12172
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
12173
|
+
}
|
|
12174
|
+
__name(delay, "delay");
|
|
12175
|
+
function normalizeCacheOptionsTags(options) {
|
|
12176
|
+
const tags = /* @__PURE__ */ new Set();
|
|
12177
|
+
for (const tag of options.tags ?? []) {
|
|
12178
|
+
tags.add(normalizeCacheTag(tag));
|
|
12179
|
+
}
|
|
12180
|
+
for (const routePath of options.paths ?? []) {
|
|
12181
|
+
tags.add(createPathCacheTag(routePath));
|
|
12182
|
+
}
|
|
12183
|
+
return tags;
|
|
12184
|
+
}
|
|
12185
|
+
__name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
|
|
12186
|
+
function assertFarmCacheEntry(entry, expectedKey) {
|
|
12187
|
+
if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
|
|
12188
|
+
throw new TypeError(
|
|
12189
|
+
`Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
|
|
12190
|
+
);
|
|
12191
|
+
}
|
|
12192
|
+
}
|
|
12193
|
+
__name(assertFarmCacheEntry, "assertFarmCacheEntry");
|
|
11898
12194
|
function getFunctionCacheIdentity(fn) {
|
|
11899
12195
|
if (fn.name) {
|
|
11900
12196
|
return `name:${fn.name}`;
|
|
@@ -13035,6 +13331,76 @@ function normalizePathname(pathname) {
|
|
|
13035
13331
|
}
|
|
13036
13332
|
__name(normalizePathname, "normalizePathname");
|
|
13037
13333
|
|
|
13334
|
+
// src/routing/route-slots.ts
|
|
13335
|
+
var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
|
|
13336
|
+
function parseRouteSlotFile(filePath) {
|
|
13337
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
13338
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
13339
|
+
const fileName = parts.at(-1) ?? "";
|
|
13340
|
+
const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
13341
|
+
if (baseName !== "page" && baseName !== "default") return null;
|
|
13342
|
+
const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
|
|
13343
|
+
if (slotIndex < 0) return null;
|
|
13344
|
+
if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
|
|
13345
|
+
throw new Error(`Nested route slots are not supported in "${filePath}"`);
|
|
13346
|
+
}
|
|
13347
|
+
const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
|
|
13348
|
+
const name = slotMatch?.[1];
|
|
13349
|
+
if (!name) return null;
|
|
13350
|
+
const ownerParts = parts.slice(0, slotIndex);
|
|
13351
|
+
const contentParts = parts.slice(slotIndex + 1, -1);
|
|
13352
|
+
const marker = parseInterceptionMarker(contentParts[0]);
|
|
13353
|
+
let targetBase = ownerParts;
|
|
13354
|
+
let targetParts = contentParts;
|
|
13355
|
+
if (marker) {
|
|
13356
|
+
targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
|
|
13357
|
+
targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
|
|
13358
|
+
}
|
|
13359
|
+
const ownerFile = [...ownerParts, "layout.tsx"].join("/");
|
|
13360
|
+
const routeFile = [
|
|
13361
|
+
...baseName === "default" ? ownerParts : targetBase,
|
|
13362
|
+
...baseName === "default" ? [] : targetParts,
|
|
13363
|
+
"page.tsx"
|
|
13364
|
+
].join("/");
|
|
13365
|
+
return {
|
|
13366
|
+
name,
|
|
13367
|
+
ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
|
|
13368
|
+
route: parseRoutePath(routeFile || "page.tsx"),
|
|
13369
|
+
interception: marker !== null,
|
|
13370
|
+
fallback: baseName === "default"
|
|
13371
|
+
};
|
|
13372
|
+
}
|
|
13373
|
+
__name(parseRouteSlotFile, "parseRouteSlotFile");
|
|
13374
|
+
function createRouteSlotContainerId(name, ownerPattern) {
|
|
13375
|
+
const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
13376
|
+
return `__farm_slot_${name}_${owner || "root"}__`;
|
|
13377
|
+
}
|
|
13378
|
+
__name(createRouteSlotContainerId, "createRouteSlotContainerId");
|
|
13379
|
+
function parseInterceptionMarker(segment) {
|
|
13380
|
+
if (!segment) return null;
|
|
13381
|
+
if (segment.startsWith("(...)")) {
|
|
13382
|
+
return {
|
|
13383
|
+
up: 0,
|
|
13384
|
+
root: true,
|
|
13385
|
+
remainder: segment.slice(5)
|
|
13386
|
+
};
|
|
13387
|
+
}
|
|
13388
|
+
if (segment.startsWith("(.)")) {
|
|
13389
|
+
return {
|
|
13390
|
+
up: 0,
|
|
13391
|
+
remainder: segment.slice(3)
|
|
13392
|
+
};
|
|
13393
|
+
}
|
|
13394
|
+
let remainder = segment;
|
|
13395
|
+
let up = 0;
|
|
13396
|
+
while (remainder.startsWith("(..)")) {
|
|
13397
|
+
up += 1;
|
|
13398
|
+
remainder = remainder.slice(4);
|
|
13399
|
+
}
|
|
13400
|
+
return up > 0 ? { up, remainder } : null;
|
|
13401
|
+
}
|
|
13402
|
+
__name(parseInterceptionMarker, "parseInterceptionMarker");
|
|
13403
|
+
|
|
13038
13404
|
// src/routing/route-manager.ts
|
|
13039
13405
|
function routeSpecificity(entry) {
|
|
13040
13406
|
return entry.route.segments.reduce((score, segment) => {
|
|
@@ -13048,6 +13414,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13048
13414
|
constructor(config, viteServer) {
|
|
13049
13415
|
this.routes = /* @__PURE__ */ new Map();
|
|
13050
13416
|
this.layouts = /* @__PURE__ */ new Map();
|
|
13417
|
+
this.routeSlots = /* @__PURE__ */ new Map();
|
|
13051
13418
|
this.loadings = /* @__PURE__ */ new Map();
|
|
13052
13419
|
this.errors = /* @__PURE__ */ new Map();
|
|
13053
13420
|
this.metadataImages = /* @__PURE__ */ new Map();
|
|
@@ -13063,6 +13430,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13063
13430
|
async discoverRoutes() {
|
|
13064
13431
|
this.routes.clear();
|
|
13065
13432
|
this.layouts.clear();
|
|
13433
|
+
this.routeSlots.clear();
|
|
13066
13434
|
this.loadings.clear();
|
|
13067
13435
|
this.errors.clear();
|
|
13068
13436
|
this.metadataImages.clear();
|
|
@@ -13073,6 +13441,13 @@ var _RouteManager = class _RouteManager {
|
|
|
13073
13441
|
await this.discoverFileRoutes(source);
|
|
13074
13442
|
await this.discoverProgrammaticRoutes(source);
|
|
13075
13443
|
}
|
|
13444
|
+
for (const slot of this.routeSlots.values()) {
|
|
13445
|
+
if (slot.interception && !this.routes.has(slot.pattern)) {
|
|
13446
|
+
throw new Error(
|
|
13447
|
+
`Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
|
|
13448
|
+
);
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13076
13451
|
this.routes = new Map(
|
|
13077
13452
|
Array.from(this.routes.entries()).sort(
|
|
13078
13453
|
([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
|
|
@@ -13088,7 +13463,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13088
13463
|
/**
|
|
13089
13464
|
* Find matching route for a given URL path
|
|
13090
13465
|
*/
|
|
13091
|
-
matchRoute(pathname) {
|
|
13466
|
+
matchRoute(pathname, options = {}) {
|
|
13092
13467
|
const routePathname = this.toRoutePathname(pathname);
|
|
13093
13468
|
const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
|
|
13094
13469
|
let matchedRoute = null;
|
|
@@ -13102,10 +13477,12 @@ var _RouteManager = class _RouteManager {
|
|
|
13102
13477
|
}
|
|
13103
13478
|
}
|
|
13104
13479
|
const layouts = this.findMatchingLayouts(normalizedPath);
|
|
13480
|
+
const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
|
|
13105
13481
|
return {
|
|
13106
13482
|
route: matchedRoute,
|
|
13107
13483
|
params,
|
|
13108
|
-
layouts
|
|
13484
|
+
layouts,
|
|
13485
|
+
slots
|
|
13109
13486
|
};
|
|
13110
13487
|
}
|
|
13111
13488
|
/**
|
|
@@ -13120,6 +13497,9 @@ var _RouteManager = class _RouteManager {
|
|
|
13120
13497
|
getLayouts() {
|
|
13121
13498
|
return new Map(this.layouts);
|
|
13122
13499
|
}
|
|
13500
|
+
getRouteSlots() {
|
|
13501
|
+
return new Map(this.routeSlots);
|
|
13502
|
+
}
|
|
13123
13503
|
/** Resolve route rules, inherited layouts, and the page export in precedence order. */
|
|
13124
13504
|
async resolveRouteRuntimeConfig(pattern) {
|
|
13125
13505
|
const routeEntry = this.routes.get(pattern);
|
|
@@ -13278,7 +13658,22 @@ var _RouteManager = class _RouteManager {
|
|
|
13278
13658
|
pattern: entry.pattern,
|
|
13279
13659
|
modulePath: toUrlPath(entry.modulePath)
|
|
13280
13660
|
}));
|
|
13281
|
-
|
|
13661
|
+
const slots = Array.from(this.routeSlots.values()).map((entry) => {
|
|
13662
|
+
const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
|
|
13663
|
+
return {
|
|
13664
|
+
name: entry.name,
|
|
13665
|
+
ownerPattern: entry.ownerPattern,
|
|
13666
|
+
pattern: entry.pattern,
|
|
13667
|
+
modulePath: toUrlPath(entry.modulePath),
|
|
13668
|
+
containerId: entry.containerId,
|
|
13669
|
+
interception: entry.interception,
|
|
13670
|
+
fallback: entry.fallback,
|
|
13671
|
+
shouldHydrate: metadata.shouldHydrate,
|
|
13672
|
+
isClientComponent: metadata.isClientComponent,
|
|
13673
|
+
segments: entry.route.segments
|
|
13674
|
+
};
|
|
13675
|
+
});
|
|
13676
|
+
return { routes, layouts, slots };
|
|
13282
13677
|
}
|
|
13283
13678
|
/**
|
|
13284
13679
|
* Load a route module dynamically
|
|
@@ -13355,6 +13750,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13355
13750
|
async discoverFileRoutes(source) {
|
|
13356
13751
|
const appDir = resolveAppPath(source.root, source.srcDir, "app");
|
|
13357
13752
|
const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
|
|
13753
|
+
const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
|
|
13358
13754
|
const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
|
|
13359
13755
|
const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
|
|
13360
13756
|
const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
|
|
@@ -13363,7 +13759,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13363
13759
|
appDir
|
|
13364
13760
|
);
|
|
13365
13761
|
for (const [kind, files, target] of [
|
|
13366
|
-
["page", pageFiles, this.routes],
|
|
13762
|
+
["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
|
|
13367
13763
|
["layout", layoutFiles, this.layouts],
|
|
13368
13764
|
["loading", loadingFiles, this.loadings],
|
|
13369
13765
|
["error", errorFiles, this.errors]
|
|
@@ -13387,6 +13783,32 @@ var _RouteManager = class _RouteManager {
|
|
|
13387
13783
|
});
|
|
13388
13784
|
}
|
|
13389
13785
|
}
|
|
13786
|
+
for (const file of [...pageFiles, ...slotDefaultFiles]) {
|
|
13787
|
+
const slot = parseRouteSlotFile(file);
|
|
13788
|
+
if (!slot) continue;
|
|
13789
|
+
const modulePath = import_path5.default.join(appDir, file);
|
|
13790
|
+
const pattern = this.createRoutePattern(slot.route);
|
|
13791
|
+
const ownerPattern = this.createRoutePattern(slot.ownerRoute);
|
|
13792
|
+
const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
|
|
13793
|
+
const existing = this.routeSlots.get(key);
|
|
13794
|
+
if (existing?.sourceRoot === source.root) {
|
|
13795
|
+
throw new Error(
|
|
13796
|
+
`Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
|
|
13797
|
+
);
|
|
13798
|
+
}
|
|
13799
|
+
this.routeSlots.set(key, {
|
|
13800
|
+
route: slot.route,
|
|
13801
|
+
modulePath,
|
|
13802
|
+
pattern,
|
|
13803
|
+
source: "file",
|
|
13804
|
+
sourceRoot: source.root,
|
|
13805
|
+
name: slot.name,
|
|
13806
|
+
ownerPattern,
|
|
13807
|
+
interception: slot.interception,
|
|
13808
|
+
fallback: slot.fallback,
|
|
13809
|
+
containerId: createRouteSlotContainerId(slot.name, ownerPattern)
|
|
13810
|
+
});
|
|
13811
|
+
}
|
|
13390
13812
|
for (const file of metadataImageFiles) {
|
|
13391
13813
|
const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
|
|
13392
13814
|
const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
|
|
@@ -13512,6 +13934,71 @@ var _RouteManager = class _RouteManager {
|
|
|
13512
13934
|
}
|
|
13513
13935
|
return matchingLayouts;
|
|
13514
13936
|
}
|
|
13937
|
+
findMatchingRouteSlots(pathname, interceptFrom) {
|
|
13938
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13939
|
+
for (const entry of this.routeSlots.values()) {
|
|
13940
|
+
if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
|
|
13941
|
+
const key = `${entry.ownerPattern}:${entry.name}`;
|
|
13942
|
+
const entries = groups.get(key) ?? [];
|
|
13943
|
+
entries.push(entry);
|
|
13944
|
+
groups.set(key, entries);
|
|
13945
|
+
}
|
|
13946
|
+
const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
|
|
13947
|
+
const matches = [];
|
|
13948
|
+
for (const entries of groups.values()) {
|
|
13949
|
+
const candidates = entries.filter((entry) => !entry.fallback).filter(
|
|
13950
|
+
(entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
|
|
13951
|
+
).map((entry) => ({
|
|
13952
|
+
entry,
|
|
13953
|
+
match: matchRoute(pathname, entry.route.segments)
|
|
13954
|
+
})).filter((candidate) => candidate.match.matches).sort((left, right) => {
|
|
13955
|
+
if (left.entry.interception !== right.entry.interception) {
|
|
13956
|
+
return left.entry.interception ? -1 : 1;
|
|
13957
|
+
}
|
|
13958
|
+
return routeSpecificity(right.entry) - routeSpecificity(left.entry);
|
|
13959
|
+
});
|
|
13960
|
+
const selected = candidates[0];
|
|
13961
|
+
if (selected) {
|
|
13962
|
+
matches.push({
|
|
13963
|
+
name: selected.entry.name,
|
|
13964
|
+
ownerPattern: selected.entry.ownerPattern,
|
|
13965
|
+
containerId: selected.entry.containerId,
|
|
13966
|
+
interception: selected.entry.interception,
|
|
13967
|
+
fallback: false,
|
|
13968
|
+
route: selected.entry,
|
|
13969
|
+
params: selected.match.params
|
|
13970
|
+
});
|
|
13971
|
+
continue;
|
|
13972
|
+
}
|
|
13973
|
+
const fallback = entries.find((entry) => entry.fallback);
|
|
13974
|
+
if (fallback) {
|
|
13975
|
+
matches.push({
|
|
13976
|
+
name: fallback.name,
|
|
13977
|
+
ownerPattern: fallback.ownerPattern,
|
|
13978
|
+
containerId: fallback.containerId,
|
|
13979
|
+
interception: false,
|
|
13980
|
+
fallback: true,
|
|
13981
|
+
route: fallback,
|
|
13982
|
+
params: {}
|
|
13983
|
+
});
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
return matches.sort((left, right) => {
|
|
13987
|
+
const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
|
|
13988
|
+
return ownerDifference || left.name.localeCompare(right.name);
|
|
13989
|
+
});
|
|
13990
|
+
}
|
|
13991
|
+
matchesRoutePrefix(pathname, pattern) {
|
|
13992
|
+
if (pattern === "/") return true;
|
|
13993
|
+
const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
|
|
13994
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
13995
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
13996
|
+
for (let index = 0; index < patternSegments.length; index++) {
|
|
13997
|
+
const segment = patternSegments[index];
|
|
13998
|
+
if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
|
|
13999
|
+
}
|
|
14000
|
+
return true;
|
|
14001
|
+
}
|
|
13515
14002
|
findNearestBoundary(pathname, boundaries) {
|
|
13516
14003
|
const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
|
|
13517
14004
|
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
@@ -14114,7 +14601,7 @@ function mergeMetadata(base, next) {
|
|
|
14114
14601
|
__name(mergeMetadata, "mergeMetadata");
|
|
14115
14602
|
function addMetadataImageReference(metadata, reference) {
|
|
14116
14603
|
if (reference.kind === "opengraph") {
|
|
14117
|
-
const openGraph = { ...metadata.openGraph
|
|
14604
|
+
const openGraph = { ...metadata.openGraph };
|
|
14118
14605
|
if (!hasMetadataImages(openGraph.images) && !hasMetadataImages(openGraph.image)) {
|
|
14119
14606
|
openGraph.images = [
|
|
14120
14607
|
{
|
|
@@ -14131,7 +14618,7 @@ function addMetadataImageReference(metadata, reference) {
|
|
|
14131
14618
|
openGraph
|
|
14132
14619
|
};
|
|
14133
14620
|
}
|
|
14134
|
-
const twitter = { ...metadata.twitter
|
|
14621
|
+
const twitter = { ...metadata.twitter };
|
|
14135
14622
|
if (!hasMetadataImages(twitter.images)) {
|
|
14136
14623
|
twitter.images = [reference.href];
|
|
14137
14624
|
twitter.card = twitter.card || "summary_large_image";
|
|
@@ -14737,8 +15224,8 @@ var _FarmI18nRuntime = class _FarmI18nRuntime {
|
|
|
14737
15224
|
cookie: this.config.cookie,
|
|
14738
15225
|
direction: getFarmLocaleDirection(resolution.locale, this.config.direction),
|
|
14739
15226
|
messages: {
|
|
14740
|
-
...this.catalogs[this.config.fallbackLocale]
|
|
14741
|
-
...this.catalogs[resolution.locale]
|
|
15227
|
+
...this.catalogs[this.config.fallbackLocale],
|
|
15228
|
+
...this.catalogs[resolution.locale]
|
|
14742
15229
|
}
|
|
14743
15230
|
};
|
|
14744
15231
|
}
|
|
@@ -15040,7 +15527,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15040
15527
|
async runWithRequestContext(request, fn) {
|
|
15041
15528
|
return _runWithCurrentRequest(
|
|
15042
15529
|
request,
|
|
15043
|
-
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15530
|
+
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15531
|
+
redirect: false
|
|
15532
|
+
}) : fn()
|
|
15044
15533
|
);
|
|
15045
15534
|
}
|
|
15046
15535
|
async resolveRouteContext(input) {
|
|
@@ -15063,11 +15552,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15063
15552
|
/**
|
|
15064
15553
|
* Check if a path should be served from SSG cache
|
|
15065
15554
|
*/
|
|
15066
|
-
shouldServeSSG(pathname) {
|
|
15555
|
+
async shouldServeSSG(pathname) {
|
|
15067
15556
|
const ssgPage = matchSSGPage(pathname, this.ssgManifest);
|
|
15068
15557
|
if (!ssgPage) return null;
|
|
15069
|
-
const cached = this.getCachedSSGPage(pathname);
|
|
15070
|
-
if (cached && this.dataCache.
|
|
15558
|
+
const cached = await this.getCachedSSGPage(pathname);
|
|
15559
|
+
if (cached && await this.dataCache.isStaleAsync(cached)) {
|
|
15071
15560
|
this.regenerateSSGPage(ssgPage);
|
|
15072
15561
|
}
|
|
15073
15562
|
return ssgPage;
|
|
@@ -15079,12 +15568,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15079
15568
|
return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
|
|
15080
15569
|
}
|
|
15081
15570
|
getCachedSSGPage(urlPath) {
|
|
15082
|
-
return this.dataCache.
|
|
15571
|
+
return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
|
|
15083
15572
|
allowStale: true
|
|
15084
15573
|
});
|
|
15085
15574
|
}
|
|
15086
|
-
cacheSSGPage(page2, html, options) {
|
|
15087
|
-
this.dataCache.
|
|
15575
|
+
async cacheSSGPage(page2, html, options) {
|
|
15576
|
+
await this.dataCache.setAsync(
|
|
15088
15577
|
this.getSSGCacheKey(page2.urlPath),
|
|
15089
15578
|
{ html, document: options.document },
|
|
15090
15579
|
{
|
|
@@ -15096,11 +15585,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15096
15585
|
);
|
|
15097
15586
|
}
|
|
15098
15587
|
getCachedPPRShell(pathname, search) {
|
|
15099
|
-
return this.dataCache.
|
|
15588
|
+
return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
|
|
15100
15589
|
}
|
|
15101
|
-
cachePPRShell(options, html) {
|
|
15590
|
+
async cachePPRShell(options, html) {
|
|
15102
15591
|
const key = this.getPPRCacheKey(options.pathname, options.search);
|
|
15103
|
-
this.dataCache.
|
|
15592
|
+
await this.dataCache.setAsync(
|
|
15104
15593
|
key,
|
|
15105
15594
|
{ html },
|
|
15106
15595
|
{
|
|
@@ -15198,7 +15687,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15198
15687
|
}
|
|
15199
15688
|
const { renderToString } = await import("react-dom/server");
|
|
15200
15689
|
const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
|
|
15201
|
-
this.cacheSSGPage(page2, html, { document: false });
|
|
15690
|
+
await this.cacheSSGPage(page2, html, { document: false });
|
|
15202
15691
|
logger.info(`ISR: Regenerated ${page2.urlPath}`);
|
|
15203
15692
|
} catch (error) {
|
|
15204
15693
|
logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
|
|
@@ -15212,7 +15701,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15212
15701
|
* Serve a pre-rendered SSG page
|
|
15213
15702
|
*/
|
|
15214
15703
|
async serveSSGPage(req, res, page2) {
|
|
15215
|
-
const cached = this.getCachedSSGPage(page2.urlPath);
|
|
15704
|
+
const cached = await this.getCachedSSGPage(page2.urlPath);
|
|
15216
15705
|
if (cached) {
|
|
15217
15706
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15218
15707
|
res.setHeader("X-Farm-SSG", "cached");
|
|
@@ -15230,9 +15719,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15230
15719
|
if (fs2.existsSync(htmlPath)) {
|
|
15231
15720
|
const stat = fs2.statSync(htmlPath);
|
|
15232
15721
|
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
15233
|
-
this.cacheSSGPage(page2, html, {
|
|
15234
|
-
|
|
15235
|
-
|
|
15722
|
+
await this.cacheSSGPage(page2, html, {
|
|
15723
|
+
document: true,
|
|
15724
|
+
createdAt: stat.mtimeMs
|
|
15725
|
+
});
|
|
15726
|
+
const fileCacheEntry = await this.getCachedSSGPage(page2.urlPath);
|
|
15727
|
+
if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
|
|
15236
15728
|
this.regenerateSSGPage(page2);
|
|
15237
15729
|
}
|
|
15238
15730
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -15278,6 +15770,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15278
15770
|
let pathname = "/";
|
|
15279
15771
|
let params = {};
|
|
15280
15772
|
let layouts = [];
|
|
15773
|
+
let routeSlots = [];
|
|
15281
15774
|
let searchParamsObject = {};
|
|
15282
15775
|
let middlewareMap = /* @__PURE__ */ new Map();
|
|
15283
15776
|
let middlewareContext = /* @__PURE__ */ new Map();
|
|
@@ -15310,7 +15803,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15310
15803
|
}
|
|
15311
15804
|
this.applyDeploymentHeaders(req, res);
|
|
15312
15805
|
if (process.env.NODE_ENV === "production") {
|
|
15313
|
-
const ssgPage = this.shouldServeSSG(pathname);
|
|
15806
|
+
const ssgPage = await this.shouldServeSSG(pathname);
|
|
15314
15807
|
if (ssgPage) {
|
|
15315
15808
|
const served = await this.serveSSGPage(req, res, ssgPage);
|
|
15316
15809
|
if (served) {
|
|
@@ -15323,6 +15816,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15323
15816
|
const route = match.route;
|
|
15324
15817
|
params = match.params;
|
|
15325
15818
|
layouts = match.layouts;
|
|
15819
|
+
routeSlots = match.slots ?? [];
|
|
15326
15820
|
if (!route) {
|
|
15327
15821
|
emitFarmEvent({ type: "route.notFound", pathname });
|
|
15328
15822
|
await this.render404(req, res);
|
|
@@ -15339,7 +15833,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15339
15833
|
errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
|
|
15340
15834
|
middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
|
|
15341
15835
|
middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
|
|
15342
|
-
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
15836
|
+
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
15837
|
+
exposedOnly: true
|
|
15838
|
+
});
|
|
15343
15839
|
const currentRequest = createWebRequestFromFarmRequest(req);
|
|
15344
15840
|
const routeContext = await this.resolveRouteContext({
|
|
15345
15841
|
request: currentRequest,
|
|
@@ -15403,8 +15899,16 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15403
15899
|
revalidate: renderingConfig.revalidate
|
|
15404
15900
|
} : void 0;
|
|
15405
15901
|
if (renderingConfig.ppr && pprBypassReason) {
|
|
15406
|
-
emitFarmEvent({
|
|
15407
|
-
|
|
15902
|
+
emitFarmEvent({
|
|
15903
|
+
type: "ppr.shell.bypass",
|
|
15904
|
+
route: pathname,
|
|
15905
|
+
reason: pprBypassReason
|
|
15906
|
+
});
|
|
15907
|
+
emitFarmEvent({
|
|
15908
|
+
type: "cache.bypass",
|
|
15909
|
+
route: pathname,
|
|
15910
|
+
reason: pprBypassReason
|
|
15911
|
+
});
|
|
15408
15912
|
if (pprBypassReason === "refresh") {
|
|
15409
15913
|
pprRefreshRoute = pathname;
|
|
15410
15914
|
emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
|
|
@@ -15412,14 +15916,22 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15412
15916
|
}
|
|
15413
15917
|
if (pprShellOptions) {
|
|
15414
15918
|
const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
|
|
15415
|
-
const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
|
|
15919
|
+
const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
|
|
15416
15920
|
if (cachedPPRShell) {
|
|
15417
|
-
emitFarmEvent({
|
|
15921
|
+
emitFarmEvent({
|
|
15922
|
+
type: "ppr.shell.hit",
|
|
15923
|
+
route: pathname,
|
|
15924
|
+
key: pprCacheKey
|
|
15925
|
+
});
|
|
15418
15926
|
this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
|
|
15419
15927
|
completeRender(res.statusCode || 200, pathname);
|
|
15420
15928
|
return;
|
|
15421
15929
|
}
|
|
15422
|
-
emitFarmEvent({
|
|
15930
|
+
emitFarmEvent({
|
|
15931
|
+
type: "ppr.shell.miss",
|
|
15932
|
+
route: pathname,
|
|
15933
|
+
key: pprCacheKey
|
|
15934
|
+
});
|
|
15423
15935
|
}
|
|
15424
15936
|
let LoadingFallbackComponent = null;
|
|
15425
15937
|
if (loadingBoundaryEntry) {
|
|
@@ -15443,14 +15955,77 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15443
15955
|
);
|
|
15444
15956
|
const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
|
|
15445
15957
|
const isClientComponent = moduleMetadata.isClientComponent;
|
|
15958
|
+
const renderedRouteSlots = await Promise.all(
|
|
15959
|
+
routeSlots.map(async (slot) => {
|
|
15960
|
+
const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
|
|
15961
|
+
if (!slotModule.default) {
|
|
15962
|
+
throw new Error(
|
|
15963
|
+
`Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
|
|
15964
|
+
);
|
|
15965
|
+
}
|
|
15966
|
+
const slotContext = await this.resolveRouteContext({
|
|
15967
|
+
request: currentRequest,
|
|
15968
|
+
rawRequest: req,
|
|
15969
|
+
params: slot.params,
|
|
15970
|
+
search: searchParamsObject,
|
|
15971
|
+
path: pathname
|
|
15972
|
+
});
|
|
15973
|
+
const rawSlotProps = withFarmRouteContext(
|
|
15974
|
+
{
|
|
15975
|
+
params: slot.params,
|
|
15976
|
+
searchParams: Promise.resolve(searchParamsObject),
|
|
15977
|
+
path: pathname,
|
|
15978
|
+
middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
|
|
15979
|
+
context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
|
|
15980
|
+
},
|
|
15981
|
+
slotContext
|
|
15982
|
+
);
|
|
15983
|
+
const slotProps = await parseRouteModuleProps(slotModule, {
|
|
15984
|
+
props: rawSlotProps,
|
|
15985
|
+
search: searchParamsObject,
|
|
15986
|
+
routePath: slot.route.pattern
|
|
15987
|
+
});
|
|
15988
|
+
const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
|
|
15989
|
+
return {
|
|
15990
|
+
...slot,
|
|
15991
|
+
module: slotModule,
|
|
15992
|
+
props: slotProps,
|
|
15993
|
+
isClientComponent: metadata.isClientComponent,
|
|
15994
|
+
shouldHydrate: metadata.shouldHydrate
|
|
15995
|
+
};
|
|
15996
|
+
})
|
|
15997
|
+
);
|
|
15446
15998
|
const shouldHydrate = moduleMetadata.shouldHydrate;
|
|
15999
|
+
const hasHydratableRouteSlots = renderedRouteSlots.some(
|
|
16000
|
+
(slot) => slot.isClientComponent || slot.shouldHydrate
|
|
16001
|
+
);
|
|
15447
16002
|
req.__FARM_PAGE_PATH__ = route.modulePath;
|
|
15448
16003
|
req.__FARM_ROUTE__ = pathname;
|
|
15449
16004
|
req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
|
|
15450
16005
|
req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
|
|
16006
|
+
req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
|
|
15451
16007
|
req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
|
|
15452
16008
|
loadingBoundaryEntry.modulePath.indexOf("/src/app/")
|
|
15453
16009
|
) : null;
|
|
16010
|
+
req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
|
|
16011
|
+
name: slot.name,
|
|
16012
|
+
ownerPattern: slot.ownerPattern,
|
|
16013
|
+
containerId: slot.containerId,
|
|
16014
|
+
interception: slot.interception,
|
|
16015
|
+
fallback: slot.fallback,
|
|
16016
|
+
modulePath: slot.route.modulePath,
|
|
16017
|
+
isClientComponent: slot.isClientComponent,
|
|
16018
|
+
shouldHydrate: slot.shouldHydrate,
|
|
16019
|
+
props: {
|
|
16020
|
+
params: slot.props.params,
|
|
16021
|
+
search: slot.props.search,
|
|
16022
|
+
searchParams: slot.props.search,
|
|
16023
|
+
..."data" in slot.props ? { data: slot.props.data } : {},
|
|
16024
|
+
...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
|
|
16025
|
+
...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
16026
|
+
path: pathname
|
|
16027
|
+
}
|
|
16028
|
+
}));
|
|
15454
16029
|
req.__FARM_PROPS__ = {
|
|
15455
16030
|
params: pageProps.params,
|
|
15456
16031
|
search: pageProps.search,
|
|
@@ -15510,12 +16085,32 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15510
16085
|
let wrappedElement = pageElement;
|
|
15511
16086
|
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
15512
16087
|
const layoutModule = layoutModules[i];
|
|
16088
|
+
const layoutEntry = layouts[i];
|
|
15513
16089
|
const LayoutComponent = layoutModule.default;
|
|
16090
|
+
const slotProps = {};
|
|
16091
|
+
for (const slot of renderedRouteSlots) {
|
|
16092
|
+
if (slot.ownerPattern !== layoutEntry.pattern) continue;
|
|
16093
|
+
let slotElement = import_react4.default.createElement(
|
|
16094
|
+
slot.module.default,
|
|
16095
|
+
slot.props
|
|
16096
|
+
);
|
|
16097
|
+
slotElement = import_react4.default.createElement(
|
|
16098
|
+
"div",
|
|
16099
|
+
{
|
|
16100
|
+
id: slot.containerId,
|
|
16101
|
+
"data-farm-route-slot": slot.name,
|
|
16102
|
+
"data-farm-slot-owner": slot.ownerPattern
|
|
16103
|
+
},
|
|
16104
|
+
slotElement
|
|
16105
|
+
);
|
|
16106
|
+
slotProps[slot.name] = slotElement;
|
|
16107
|
+
}
|
|
15514
16108
|
wrappedElement = import_react4.default.createElement(
|
|
15515
16109
|
LayoutComponent,
|
|
15516
16110
|
{
|
|
15517
16111
|
children: wrappedElement,
|
|
15518
|
-
params
|
|
16112
|
+
params,
|
|
16113
|
+
...slotProps
|
|
15519
16114
|
}
|
|
15520
16115
|
);
|
|
15521
16116
|
}
|
|
@@ -15552,7 +16147,10 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15552
16147
|
routeManifest,
|
|
15553
16148
|
captureStaticShell: Boolean(pprShellOptions),
|
|
15554
16149
|
observabilityRoute: pathname,
|
|
15555
|
-
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16150
|
+
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16151
|
+
type: "ppr.suspense.holeDetected",
|
|
16152
|
+
route: pathname
|
|
16153
|
+
}) : void 0,
|
|
15556
16154
|
onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
|
|
15557
16155
|
}
|
|
15558
16156
|
);
|
|
@@ -15600,7 +16198,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15600
16198
|
}
|
|
15601
16199
|
emitFarmEvent({ type: "render.error", route: pathname, error });
|
|
15602
16200
|
if (pprRefreshRoute) {
|
|
15603
|
-
emitFarmEvent({
|
|
16201
|
+
emitFarmEvent({
|
|
16202
|
+
type: "ppr.refresh.error",
|
|
16203
|
+
route: pprRefreshRoute,
|
|
16204
|
+
error
|
|
16205
|
+
});
|
|
15604
16206
|
}
|
|
15605
16207
|
logger.error(`Error rendering page: ${error}`);
|
|
15606
16208
|
if (res.headersSent || res.writableEnded) {
|
|
@@ -15653,7 +16255,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15653
16255
|
if (typeof layoutModule.generateMetadata === "function") {
|
|
15654
16256
|
metadata = mergeMetadata(
|
|
15655
16257
|
metadata,
|
|
15656
|
-
await layoutModule.generateMetadata({
|
|
16258
|
+
await layoutModule.generateMetadata({
|
|
16259
|
+
params: options.pageProps.params
|
|
16260
|
+
})
|
|
15657
16261
|
);
|
|
15658
16262
|
}
|
|
15659
16263
|
}
|
|
@@ -15884,7 +16488,13 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15884
16488
|
clientEntry: "/@farm/client.js",
|
|
15885
16489
|
routes: {},
|
|
15886
16490
|
layouts: {},
|
|
15887
|
-
|
|
16491
|
+
slots: [],
|
|
16492
|
+
sharedAssets: [
|
|
16493
|
+
{
|
|
16494
|
+
tag: "link",
|
|
16495
|
+
attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
|
|
16496
|
+
}
|
|
16497
|
+
]
|
|
15888
16498
|
};
|
|
15889
16499
|
for (const routeEntry of manifest.routes) {
|
|
15890
16500
|
clientManifest.routes[routeEntry.pattern] = {
|
|
@@ -15906,9 +16516,26 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15906
16516
|
assets: []
|
|
15907
16517
|
};
|
|
15908
16518
|
}
|
|
15909
|
-
const
|
|
16519
|
+
for (const slotEntry of manifest.slots ?? []) {
|
|
16520
|
+
clientManifest.slots.push({
|
|
16521
|
+
...slotEntry,
|
|
16522
|
+
preloads: [slotEntry.modulePath],
|
|
16523
|
+
assets: []
|
|
16524
|
+
});
|
|
16525
|
+
}
|
|
16526
|
+
const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
|
|
16527
|
+
(slot) => ({
|
|
16528
|
+
...slot,
|
|
16529
|
+
modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
|
|
16530
|
+
})
|
|
16531
|
+
);
|
|
16532
|
+
const deferredProps = prepareDeferredData({
|
|
16533
|
+
page: req.__FARM_PROPS__ || {},
|
|
16534
|
+
slots: routeSlotPayload
|
|
16535
|
+
});
|
|
15910
16536
|
const propsScript = `<script>
|
|
15911
|
-
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
|
|
16537
|
+
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
|
|
16538
|
+
window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
|
|
15912
16539
|
window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
|
|
15913
16540
|
window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
|
|
15914
16541
|
window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
|
|
@@ -15921,7 +16548,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
|
|
|
15921
16548
|
window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
|
|
15922
16549
|
${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
|
|
15923
16550
|
</script>`;
|
|
15924
|
-
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
|
|
16551
|
+
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
|
|
15925
16552
|
const {
|
|
15926
16553
|
title,
|
|
15927
16554
|
tags: metaTags,
|
|
@@ -16032,7 +16659,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16032
16659
|
didError = true;
|
|
16033
16660
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16034
16661
|
logger.error(`SSR shell error: ${error}`);
|
|
16035
|
-
emitFarmEvent({
|
|
16662
|
+
emitFarmEvent({
|
|
16663
|
+
type: "render.error",
|
|
16664
|
+
route: observabilityRoute,
|
|
16665
|
+
error
|
|
16666
|
+
});
|
|
16036
16667
|
}
|
|
16037
16668
|
if (clearMiddlewareData) {
|
|
16038
16669
|
clearMiddlewareData();
|
|
@@ -16043,7 +16674,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16043
16674
|
didError = true;
|
|
16044
16675
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16045
16676
|
logger.error(`SSR streaming error: ${error}`);
|
|
16046
|
-
emitFarmEvent({
|
|
16677
|
+
emitFarmEvent({
|
|
16678
|
+
type: "render.error",
|
|
16679
|
+
route: observabilityRoute,
|
|
16680
|
+
error
|
|
16681
|
+
});
|
|
16047
16682
|
}
|
|
16048
16683
|
}
|
|
16049
16684
|
});
|
|
@@ -16212,17 +16847,14 @@ var _FarmApp = class _FarmApp {
|
|
|
16212
16847
|
_setDefaultFarmI18nRuntime(this.i18nRuntime);
|
|
16213
16848
|
this.viteServer = viteServer;
|
|
16214
16849
|
this.routeManager = new RouteManager(this.config, viteServer);
|
|
16215
|
-
this.serverRenderer = new ServerRenderer(
|
|
16216
|
-
this.config,
|
|
16217
|
-
this.routeManager,
|
|
16218
|
-
this.i18nRuntime
|
|
16219
|
-
);
|
|
16850
|
+
this.serverRenderer = new ServerRenderer(this.config, this.routeManager, this.i18nRuntime);
|
|
16220
16851
|
}
|
|
16221
16852
|
async initialize() {
|
|
16222
16853
|
if (process.env.FARM_VERBOSE) {
|
|
16223
16854
|
logger.info("Initializing Farm.js application...");
|
|
16224
16855
|
}
|
|
16225
16856
|
await initStorage(this.config.storage);
|
|
16857
|
+
await configureFarmCache(this.config.cache);
|
|
16226
16858
|
await this.i18nRuntime.initialize();
|
|
16227
16859
|
await this.verifyAppStructure();
|
|
16228
16860
|
await this.routeManager.discoverRoutes();
|
|
@@ -16254,6 +16886,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16254
16886
|
preset: config.preset ?? "node-server",
|
|
16255
16887
|
deploy: config.deploy || {},
|
|
16256
16888
|
storage: config.storage || {},
|
|
16889
|
+
cache: config.cache || {},
|
|
16257
16890
|
integrations: config.integrations || {},
|
|
16258
16891
|
plugins: config.plugins || [],
|
|
16259
16892
|
migrations: config.migrations || { commands: [] },
|
|
@@ -16661,6 +17294,29 @@ var fs3 = __toESM(require("fs"));
|
|
|
16661
17294
|
var path10 = __toESM(require("path"));
|
|
16662
17295
|
init_route_runtime();
|
|
16663
17296
|
|
|
17297
|
+
// src/api/runtime.ts
|
|
17298
|
+
init_cache_invalidation();
|
|
17299
|
+
|
|
17300
|
+
// src/api/endpoint.ts
|
|
17301
|
+
var import_better_call = require("better-call");
|
|
17302
|
+
var _EndpointFailure = class _EndpointFailure extends Error {
|
|
17303
|
+
constructor(code, data, options) {
|
|
17304
|
+
super(options.message);
|
|
17305
|
+
this.name = "EndpointFailure";
|
|
17306
|
+
this.code = code;
|
|
17307
|
+
this.data = data;
|
|
17308
|
+
this.status = options.status;
|
|
17309
|
+
}
|
|
17310
|
+
};
|
|
17311
|
+
__name(_EndpointFailure, "EndpointFailure");
|
|
17312
|
+
var EndpointFailure = _EndpointFailure;
|
|
17313
|
+
function isEndpointFailure(value) {
|
|
17314
|
+
return value instanceof EndpointFailure;
|
|
17315
|
+
}
|
|
17316
|
+
__name(isEndpointFailure, "isEndpointFailure");
|
|
17317
|
+
var EMPTY_ENDPOINT_MIDDLEWARE = Object.freeze([]);
|
|
17318
|
+
var EMPTY_ENDPOINT_CONTEXT = Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
17319
|
+
|
|
16664
17320
|
// src/api/runtime.ts
|
|
16665
17321
|
function matchAPIRoute(routes, pathname) {
|
|
16666
17322
|
const exactRoute = routes.get(pathname);
|
|
@@ -16693,10 +17349,10 @@ __name(invokeAPIRouteEndpoint, "invokeAPIRouteEndpoint");
|
|
|
16693
17349
|
async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
16694
17350
|
const farmHandler = endpoint.__handler || (isFarmContextHandler(endpoint) ? endpoint : null);
|
|
16695
17351
|
if (!farmHandler) {
|
|
16696
|
-
const
|
|
17352
|
+
const result = await endpoint(request, {
|
|
16697
17353
|
params: Promise.resolve(params)
|
|
16698
17354
|
});
|
|
16699
|
-
return normalizeRouteResponse(
|
|
17355
|
+
return normalizeRouteResponse(result);
|
|
16700
17356
|
}
|
|
16701
17357
|
const url = new URL(request.url);
|
|
16702
17358
|
const query = {};
|
|
@@ -16705,7 +17361,7 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
16705
17361
|
});
|
|
16706
17362
|
let body = void 0;
|
|
16707
17363
|
if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
|
|
16708
|
-
body = await
|
|
17364
|
+
body = await readRequestBody(request);
|
|
16709
17365
|
}
|
|
16710
17366
|
const headers = Object.fromEntries(request.headers.entries());
|
|
16711
17367
|
const types = endpoint.__types || {};
|
|
@@ -16721,15 +17377,30 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
16721
17377
|
if (headersValidation instanceof Response) {
|
|
16722
17378
|
return headersValidation;
|
|
16723
17379
|
}
|
|
16724
|
-
const
|
|
17380
|
+
const handlerContext = {
|
|
16725
17381
|
query: queryValidation,
|
|
16726
17382
|
body: bodyValidation,
|
|
16727
17383
|
headers: headersValidation,
|
|
16728
17384
|
request,
|
|
16729
17385
|
context: {},
|
|
16730
17386
|
params
|
|
16731
|
-
}
|
|
16732
|
-
|
|
17387
|
+
};
|
|
17388
|
+
let execution;
|
|
17389
|
+
try {
|
|
17390
|
+
execution = typeof endpoint.__farmInvoke === "function" ? await endpoint.__farmInvoke(handlerContext) : {
|
|
17391
|
+
result: await farmHandler(handlerContext),
|
|
17392
|
+
context: handlerContext.context,
|
|
17393
|
+
handlerExecuted: true,
|
|
17394
|
+
invalidations: []
|
|
17395
|
+
};
|
|
17396
|
+
} catch (error) {
|
|
17397
|
+
if (isEndpointFailure(error)) {
|
|
17398
|
+
return createEndpointFailureResponse(error);
|
|
17399
|
+
}
|
|
17400
|
+
throw error;
|
|
17401
|
+
}
|
|
17402
|
+
const response = normalizeRouteResponse(execution.result);
|
|
17403
|
+
return attachEndpointInvalidations(response, execution.invalidations);
|
|
16733
17404
|
}
|
|
16734
17405
|
__name(invokeAPIRouteEndpointInContext, "invokeAPIRouteEndpointInContext");
|
|
16735
17406
|
function normalizeRouteResponse(result) {
|
|
@@ -16749,6 +17420,40 @@ function isWebResponse2(value) {
|
|
|
16749
17420
|
return value instanceof Response || typeof value === "object" && value !== null && "headers" in value && "status" in value && typeof value.arrayBuffer === "function";
|
|
16750
17421
|
}
|
|
16751
17422
|
__name(isWebResponse2, "isWebResponse");
|
|
17423
|
+
function attachEndpointInvalidations(response, keys) {
|
|
17424
|
+
const existing = decodeFarmCacheInvalidations(
|
|
17425
|
+
response.headers.get(FARM_CACHE_INVALIDATION_HEADER)
|
|
17426
|
+
);
|
|
17427
|
+
const encoded = encodeFarmCacheInvalidations([...existing, ...keys]);
|
|
17428
|
+
if (!encoded) return response;
|
|
17429
|
+
const headers = new Headers(response.headers);
|
|
17430
|
+
headers.set(FARM_CACHE_INVALIDATION_HEADER, encoded);
|
|
17431
|
+
return new Response(response.body, {
|
|
17432
|
+
status: response.status,
|
|
17433
|
+
statusText: response.statusText,
|
|
17434
|
+
headers
|
|
17435
|
+
});
|
|
17436
|
+
}
|
|
17437
|
+
__name(attachEndpointInvalidations, "attachEndpointInvalidations");
|
|
17438
|
+
function createEndpointFailureResponse(failure) {
|
|
17439
|
+
return new Response(
|
|
17440
|
+
JSON.stringify({
|
|
17441
|
+
error: {
|
|
17442
|
+
code: failure.code,
|
|
17443
|
+
message: failure.message,
|
|
17444
|
+
data: failure.data
|
|
17445
|
+
}
|
|
17446
|
+
}),
|
|
17447
|
+
{
|
|
17448
|
+
status: failure.status,
|
|
17449
|
+
headers: {
|
|
17450
|
+
"cache-control": "no-store",
|
|
17451
|
+
"content-type": "application/json"
|
|
17452
|
+
}
|
|
17453
|
+
}
|
|
17454
|
+
);
|
|
17455
|
+
}
|
|
17456
|
+
__name(createEndpointFailureResponse, "createEndpointFailureResponse");
|
|
16752
17457
|
function isFarmContextHandler(endpoint) {
|
|
16753
17458
|
if (typeof endpoint !== "function") {
|
|
16754
17459
|
return false;
|
|
@@ -16760,17 +17465,50 @@ function isFarmContextHandler(endpoint) {
|
|
|
16760
17465
|
return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
|
|
16761
17466
|
}
|
|
16762
17467
|
__name(isFarmContextHandler, "isFarmContextHandler");
|
|
16763
|
-
async function
|
|
17468
|
+
async function readRequestBody(request) {
|
|
17469
|
+
const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
16764
17470
|
try {
|
|
17471
|
+
if (contentType === "multipart/form-data") {
|
|
17472
|
+
return formDataToObject(await request.clone().formData());
|
|
17473
|
+
}
|
|
16765
17474
|
const text2 = await request.clone().text();
|
|
16766
|
-
if (text2)
|
|
17475
|
+
if (!text2) return void 0;
|
|
17476
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
17477
|
+
return searchParamsToObject2(new URLSearchParams(text2));
|
|
17478
|
+
}
|
|
17479
|
+
if (contentType === "application/json" || contentType?.endsWith("+json")) {
|
|
16767
17480
|
return JSON.parse(text2);
|
|
16768
17481
|
}
|
|
17482
|
+
return JSON.parse(text2);
|
|
16769
17483
|
} catch {
|
|
16770
17484
|
}
|
|
16771
17485
|
return void 0;
|
|
16772
17486
|
}
|
|
16773
|
-
__name(
|
|
17487
|
+
__name(readRequestBody, "readRequestBody");
|
|
17488
|
+
function formDataToObject(formData) {
|
|
17489
|
+
return entriesToObject(formData.entries());
|
|
17490
|
+
}
|
|
17491
|
+
__name(formDataToObject, "formDataToObject");
|
|
17492
|
+
function searchParamsToObject2(searchParams) {
|
|
17493
|
+
return entriesToObject(searchParams.entries());
|
|
17494
|
+
}
|
|
17495
|
+
__name(searchParamsToObject2, "searchParamsToObject");
|
|
17496
|
+
function entriesToObject(entries) {
|
|
17497
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
17498
|
+
for (const [key, value] of entries) {
|
|
17499
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
17500
|
+
const current = output[key];
|
|
17501
|
+
if (current === void 0) {
|
|
17502
|
+
output[key] = value;
|
|
17503
|
+
} else if (Array.isArray(current)) {
|
|
17504
|
+
current.push(value);
|
|
17505
|
+
} else {
|
|
17506
|
+
output[key] = [current, value];
|
|
17507
|
+
}
|
|
17508
|
+
}
|
|
17509
|
+
return output;
|
|
17510
|
+
}
|
|
17511
|
+
__name(entriesToObject, "entriesToObject");
|
|
16774
17512
|
function validateInput(schema, value, error) {
|
|
16775
17513
|
if (!schema || typeof schema.parse !== "function") {
|
|
16776
17514
|
return value;
|
|
@@ -17777,7 +18515,7 @@ var _MiddlewareManager = class _MiddlewareManager {
|
|
|
17777
18515
|
if (!nestedMatch.matched) {
|
|
17778
18516
|
return { matched: false };
|
|
17779
18517
|
}
|
|
17780
|
-
const params = { ...nestedMatch.params
|
|
18518
|
+
const params = { ...nestedMatch.params };
|
|
17781
18519
|
delete params.__farmRest;
|
|
17782
18520
|
return {
|
|
17783
18521
|
matched: true,
|
|
@@ -17925,6 +18663,7 @@ async function generateRouteTypes(options) {
|
|
|
17925
18663
|
absolute: false
|
|
17926
18664
|
});
|
|
17927
18665
|
for (const file of pageFiles) {
|
|
18666
|
+
if (parseRouteSlotFile(file)) continue;
|
|
17928
18667
|
const route = parseRoutePath(file);
|
|
17929
18668
|
if (route.type === "page") {
|
|
17930
18669
|
const pattern = createRoutePattern(route);
|
|
@@ -18678,7 +19417,7 @@ function isResolvedEnvScope(value) {
|
|
|
18678
19417
|
}
|
|
18679
19418
|
__name(isResolvedEnvScope, "isResolvedEnvScope");
|
|
18680
19419
|
function isPotentialProgrammaticRouteSourceFile(normalizedFile, srcDirSlug) {
|
|
18681
|
-
return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) &&
|
|
19420
|
+
return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) && !normalizedFile.endsWith(".d.ts") && !normalizedFile.endsWith("/farm-routes.d.ts") && !normalizedFile.endsWith("/farm-env.d.ts") && !normalizedFile.endsWith("/lib/api.generated.ts");
|
|
18682
19421
|
}
|
|
18683
19422
|
__name(isPotentialProgrammaticRouteSourceFile, "isPotentialProgrammaticRouteSourceFile");
|
|
18684
19423
|
function fileContainsProgrammaticPageRoute(file) {
|
|
@@ -18921,7 +19660,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
18921
19660
|
}, "isProgrammaticRouteSourceFile");
|
|
18922
19661
|
const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
|
|
18923
19662
|
const normalized = file.replace(/\\/g, "/");
|
|
18924
|
-
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
19663
|
+
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|default|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
18925
19664
|
normalized
|
|
18926
19665
|
);
|
|
18927
19666
|
}, "isAppRuntimeFile");
|
|
@@ -19612,7 +20351,10 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19612
20351
|
method: req.method || "GET"
|
|
19613
20352
|
});
|
|
19614
20353
|
}
|
|
19615
|
-
const
|
|
20354
|
+
const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
|
|
20355
|
+
const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
|
|
20356
|
+
interceptFrom: interceptFromHeader
|
|
20357
|
+
});
|
|
19616
20358
|
if (pm) {
|
|
19617
20359
|
await pm.runHookParallel("afterRouteMatch", {
|
|
19618
20360
|
pathname: targetPath,
|
|
@@ -19628,7 +20370,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19628
20370
|
res.end(JSON.stringify({ error: "Route not found" }));
|
|
19629
20371
|
return;
|
|
19630
20372
|
}
|
|
19631
|
-
const { route, params, layouts } = match;
|
|
20373
|
+
const { route, params, layouts, slots } = match;
|
|
19632
20374
|
if (!route) {
|
|
19633
20375
|
res.statusCode = 404;
|
|
19634
20376
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -19683,6 +20425,54 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19683
20425
|
search: searchParams,
|
|
19684
20426
|
routePath: route.pattern
|
|
19685
20427
|
});
|
|
20428
|
+
const routeSlots = await Promise.all(
|
|
20429
|
+
slots.map(async (slot) => {
|
|
20430
|
+
const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
|
|
20431
|
+
const slotMetadata = getClientModuleMetadata(
|
|
20432
|
+
slot.route.modulePath,
|
|
20433
|
+
server.config.root
|
|
20434
|
+
);
|
|
20435
|
+
const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
|
|
20436
|
+
request,
|
|
20437
|
+
params: slot.params,
|
|
20438
|
+
search: searchParams,
|
|
20439
|
+
path: targetUrl.pathname
|
|
20440
|
+
});
|
|
20441
|
+
const slotProps = await parseRouteModuleProps2(slotModule, {
|
|
20442
|
+
props: withFarmRouteContext(
|
|
20443
|
+
{
|
|
20444
|
+
params: slot.params,
|
|
20445
|
+
searchParams: Promise.resolve(searchParams),
|
|
20446
|
+
path: targetUrl.pathname
|
|
20447
|
+
},
|
|
20448
|
+
slotContext
|
|
20449
|
+
),
|
|
20450
|
+
search: searchParams,
|
|
20451
|
+
routePath: slot.route.pattern
|
|
20452
|
+
});
|
|
20453
|
+
return {
|
|
20454
|
+
name: slot.name,
|
|
20455
|
+
ownerPattern: slot.ownerPattern,
|
|
20456
|
+
containerId: slot.containerId,
|
|
20457
|
+
interception: slot.interception,
|
|
20458
|
+
fallback: slot.fallback,
|
|
20459
|
+
modulePath: slot.route.modulePath,
|
|
20460
|
+
isClientComponent: slotMetadata.isClientComponent,
|
|
20461
|
+
shouldHydrate: slotMetadata.shouldHydrate,
|
|
20462
|
+
props: {
|
|
20463
|
+
params: slotProps.params,
|
|
20464
|
+
search: slotProps.search,
|
|
20465
|
+
searchParams: slotProps.search,
|
|
20466
|
+
..."data" in slotProps ? { data: slotProps.data } : {},
|
|
20467
|
+
...slotProps.__farmCanonicalPath ? {
|
|
20468
|
+
__farmCanonicalPath: slotProps.__farmCanonicalPath
|
|
20469
|
+
} : {},
|
|
20470
|
+
...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
20471
|
+
path: targetUrl.pathname
|
|
20472
|
+
}
|
|
20473
|
+
};
|
|
20474
|
+
})
|
|
20475
|
+
);
|
|
19686
20476
|
const projectRoot = server.config.root;
|
|
19687
20477
|
const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
|
|
19688
20478
|
if (absolutePath.startsWith(projectRoot)) {
|
|
@@ -19703,13 +20493,21 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19703
20493
|
},
|
|
19704
20494
|
canonicalPath: routeProps.__farmCanonicalPath,
|
|
19705
20495
|
modulePath: toUrlPath(route.modulePath),
|
|
19706
|
-
isClientComponent,
|
|
19707
|
-
shouldHydrate,
|
|
20496
|
+
isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
|
|
20497
|
+
shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
|
|
19708
20498
|
metadata: {
|
|
19709
20499
|
title: mergedMetadata.title,
|
|
19710
20500
|
description: mergedMetadata.description
|
|
19711
20501
|
},
|
|
19712
20502
|
layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
|
|
20503
|
+
routeSlots: routeSlots.map((slot) => ({
|
|
20504
|
+
...slot,
|
|
20505
|
+
modulePath: toUrlPath(slot.modulePath)
|
|
20506
|
+
})),
|
|
20507
|
+
interception: routeSlots.some((slot) => slot.interception) ? {
|
|
20508
|
+
from: interceptFromHeader,
|
|
20509
|
+
slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
|
|
20510
|
+
} : void 0,
|
|
19713
20511
|
i18n: getFarmI18nClientSnapshot()
|
|
19714
20512
|
};
|
|
19715
20513
|
await sendWebResponse(
|
|
@@ -20045,6 +20843,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20045
20843
|
export const getManifest = () => ({
|
|
20046
20844
|
routes: {},
|
|
20047
20845
|
layouts: {},
|
|
20846
|
+
slots: [],
|
|
20048
20847
|
clientEntry: "/@farm/client.js",
|
|
20049
20848
|
sharedAssets: []
|
|
20050
20849
|
});
|
|
@@ -20055,6 +20854,7 @@ export const getManifest = () => ({
|
|
|
20055
20854
|
clientEntry: "/@farm/client.js",
|
|
20056
20855
|
routes: {},
|
|
20057
20856
|
layouts: {},
|
|
20857
|
+
slots: [],
|
|
20058
20858
|
sharedAssets: [
|
|
20059
20859
|
{
|
|
20060
20860
|
tag: "link",
|
|
@@ -20084,6 +20884,13 @@ export const getManifest = () => ({
|
|
|
20084
20884
|
assets: []
|
|
20085
20885
|
};
|
|
20086
20886
|
}
|
|
20887
|
+
for (const slot of manifest.slots) {
|
|
20888
|
+
fullManifest.slots.push({
|
|
20889
|
+
...slot,
|
|
20890
|
+
preloads: [slot.modulePath],
|
|
20891
|
+
assets: []
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20087
20894
|
return `
|
|
20088
20895
|
// Auto-generated manifest for SPA navigation (TanStack Start pattern)
|
|
20089
20896
|
// This manifest is inlined in the server bundle - no file on disk
|
|
@@ -20726,7 +21533,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
|
|
|
20726
21533
|
|
|
20727
21534
|
// Get manifest from window (inlined by server in HTML)
|
|
20728
21535
|
// Fallback to empty manifest if not available yet
|
|
20729
|
-
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
|
|
21536
|
+
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
|
|
20730
21537
|
|
|
20731
21538
|
// ====== CLIENT-SIDE ROUTE MATCHING ======
|
|
20732
21539
|
// Matches URL to route using manifest (no server request!)
|
|
@@ -21065,6 +21872,9 @@ let LayoutComponent = null;
|
|
|
21065
21872
|
|
|
21066
21873
|
// Track if we've taken over rendering from SSR
|
|
21067
21874
|
let hasClientTakenOver = false;
|
|
21875
|
+
const routeSlotRoots = new Map();
|
|
21876
|
+
const routeSlotDefinitions = new Map();
|
|
21877
|
+
let activeRouteInterception = null;
|
|
21068
21878
|
|
|
21069
21879
|
function normalizeServerProps(rawProps) {
|
|
21070
21880
|
const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
|
|
@@ -21077,6 +21887,123 @@ function normalizeServerProps(rawProps) {
|
|
|
21077
21887
|
return props;
|
|
21078
21888
|
}
|
|
21079
21889
|
|
|
21890
|
+
function getRouteSlotKey(slot) {
|
|
21891
|
+
return slot.ownerPattern + ':' + slot.name;
|
|
21892
|
+
}
|
|
21893
|
+
|
|
21894
|
+
async function renderRouteSlot(slot, mode = 'render') {
|
|
21895
|
+
const container = document.getElementById(slot.containerId);
|
|
21896
|
+
if (!container || !slot.modulePath) return false;
|
|
21897
|
+
if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
|
|
21898
|
+
return false;
|
|
21899
|
+
}
|
|
21900
|
+
|
|
21901
|
+
let slotModule = pageModuleCache.get(slot.modulePath);
|
|
21902
|
+
if (!slotModule) {
|
|
21903
|
+
slotModule = await import(/* @vite-ignore */ slot.modulePath);
|
|
21904
|
+
pageModuleCache.set(slot.modulePath, slotModule);
|
|
21905
|
+
}
|
|
21906
|
+
const SlotComponent = slotModule?.default;
|
|
21907
|
+
if (!SlotComponent) return false;
|
|
21908
|
+
|
|
21909
|
+
const props = reviveDeferredData(
|
|
21910
|
+
normalizeServerProps(slot.props || {}),
|
|
21911
|
+
window.__FARM_DEFERRED_DATA__ || {},
|
|
21912
|
+
);
|
|
21913
|
+
const element = wrapWithIntegrationProviders(
|
|
21914
|
+
React.createElement(SlotComponent, props),
|
|
21915
|
+
);
|
|
21916
|
+
const key = getRouteSlotKey(slot);
|
|
21917
|
+
const existingRoot = routeSlotRoots.get(key);
|
|
21918
|
+
|
|
21919
|
+
if (mode === 'hydrate') {
|
|
21920
|
+
if (existingRoot) return true;
|
|
21921
|
+
const root = hydrateRoot(container, element);
|
|
21922
|
+
routeSlotRoots.set(key, root);
|
|
21923
|
+
} else {
|
|
21924
|
+
if (existingRoot) {
|
|
21925
|
+
try { existingRoot.unmount(); } catch (error) {}
|
|
21926
|
+
}
|
|
21927
|
+
const root = createRoot(container);
|
|
21928
|
+
root.render(element);
|
|
21929
|
+
routeSlotRoots.set(key, root);
|
|
21930
|
+
}
|
|
21931
|
+
|
|
21932
|
+
routeSlotDefinitions.set(key, slot);
|
|
21933
|
+
return true;
|
|
21934
|
+
}
|
|
21935
|
+
|
|
21936
|
+
async function hydrateInitialRouteSlots() {
|
|
21937
|
+
const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
|
|
21938
|
+
? window.__FARM_ROUTE_SLOTS__
|
|
21939
|
+
: [];
|
|
21940
|
+
let hydrated = false;
|
|
21941
|
+
|
|
21942
|
+
for (const slot of slots) {
|
|
21943
|
+
routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
|
|
21944
|
+
if (!slot.isClientComponent && !slot.shouldHydrate) continue;
|
|
21945
|
+
try {
|
|
21946
|
+
hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
|
|
21947
|
+
} catch (error) {
|
|
21948
|
+
console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
|
|
21949
|
+
}
|
|
21950
|
+
}
|
|
21951
|
+
|
|
21952
|
+
return hydrated;
|
|
21953
|
+
}
|
|
21954
|
+
|
|
21955
|
+
async function renderRouteInterception(pageData) {
|
|
21956
|
+
const slots = Array.isArray(pageData.routeSlots)
|
|
21957
|
+
? pageData.routeSlots.filter((slot) => slot.interception)
|
|
21958
|
+
: [];
|
|
21959
|
+
if (!pageData.interception || slots.length === 0) return false;
|
|
21960
|
+
|
|
21961
|
+
const previous = new Map();
|
|
21962
|
+
for (const slot of slots) {
|
|
21963
|
+
const key = getRouteSlotKey(slot);
|
|
21964
|
+
previous.set(key, routeSlotDefinitions.get(key) || null);
|
|
21965
|
+
if (!(await renderRouteSlot(slot, 'intercept'))) {
|
|
21966
|
+
return false;
|
|
21967
|
+
}
|
|
21968
|
+
}
|
|
21969
|
+
|
|
21970
|
+
activeRouteInterception = {
|
|
21971
|
+
from: pageData.interception.from,
|
|
21972
|
+
slots,
|
|
21973
|
+
previous,
|
|
21974
|
+
};
|
|
21975
|
+
return true;
|
|
21976
|
+
}
|
|
21977
|
+
|
|
21978
|
+
async function clearRouteInterception(destination) {
|
|
21979
|
+
if (!activeRouteInterception) return false;
|
|
21980
|
+
const active = activeRouteInterception;
|
|
21981
|
+
activeRouteInterception = null;
|
|
21982
|
+
|
|
21983
|
+
for (const slot of active.slots) {
|
|
21984
|
+
const key = getRouteSlotKey(slot);
|
|
21985
|
+
const root = routeSlotRoots.get(key);
|
|
21986
|
+
if (root) {
|
|
21987
|
+
try { root.unmount(); } catch (error) {}
|
|
21988
|
+
routeSlotRoots.delete(key);
|
|
21989
|
+
}
|
|
21990
|
+
|
|
21991
|
+
const previous = active.previous.get(key);
|
|
21992
|
+
if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
|
|
21993
|
+
await renderRouteSlot(previous, 'render');
|
|
21994
|
+
} else {
|
|
21995
|
+
const container = document.getElementById(slot.containerId);
|
|
21996
|
+
if (container) container.replaceChildren();
|
|
21997
|
+
if (previous) routeSlotDefinitions.set(key, previous);
|
|
21998
|
+
else routeSlotDefinitions.delete(key);
|
|
21999
|
+
}
|
|
22000
|
+
}
|
|
22001
|
+
|
|
22002
|
+
if (!active.from) return false;
|
|
22003
|
+
const background = new URL(active.from, window.location.origin);
|
|
22004
|
+
return destination === background.pathname + background.search;
|
|
22005
|
+
}
|
|
22006
|
+
|
|
21080
22007
|
function applyCanonicalPathFromProps(props) {
|
|
21081
22008
|
const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
|
|
21082
22009
|
? props.__farmCanonicalPath
|
|
@@ -21311,6 +22238,17 @@ async function tryHydrateImportedPage(
|
|
|
21311
22238
|
async function renderPage(pageData) {
|
|
21312
22239
|
const container = document.getElementById('root');
|
|
21313
22240
|
if (!container) return;
|
|
22241
|
+
const destination = window.location.pathname + window.location.search;
|
|
22242
|
+
|
|
22243
|
+
if (pageData.interception) {
|
|
22244
|
+
if (await renderRouteInterception(pageData)) return;
|
|
22245
|
+
window.location.assign(destination);
|
|
22246
|
+
return;
|
|
22247
|
+
}
|
|
22248
|
+
|
|
22249
|
+
if (await clearRouteInterception(destination)) {
|
|
22250
|
+
return;
|
|
22251
|
+
}
|
|
21314
22252
|
|
|
21315
22253
|
const route = {
|
|
21316
22254
|
modulePath: pageData.modulePath,
|
|
@@ -21539,7 +22477,9 @@ async function hydrate() {
|
|
|
21539
22477
|
window.__FARM_SHOULD_HYDRATE__ === true ||
|
|
21540
22478
|
isClientComponent ||
|
|
21541
22479
|
await moduleLooksClient(modulePath);
|
|
22480
|
+
const hydratedSlots = await hydrateInitialRouteSlots();
|
|
21542
22481
|
if (!shouldHydrate) {
|
|
22482
|
+
if (hydratedSlots) replayPreHydrationClicks();
|
|
21543
22483
|
console.log('[Farm.js] Server component - SPA router ready')
|
|
21544
22484
|
return
|
|
21545
22485
|
}
|