@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/vite.cjs
CHANGED
|
@@ -118,7 +118,7 @@ function createFarmMarkdownRouteModule(input) {
|
|
|
118
118
|
...props,
|
|
119
119
|
components: {
|
|
120
120
|
...components,
|
|
121
|
-
...props?.components
|
|
121
|
+
...props?.components
|
|
122
122
|
}
|
|
123
123
|
})
|
|
124
124
|
);
|
|
@@ -635,7 +635,11 @@ async function prepareFarmWorkflowsForNitro(config) {
|
|
|
635
635
|
};
|
|
636
636
|
}
|
|
637
637
|
const handlerPath = path22.join(generatedDir, "http-handler.mjs");
|
|
638
|
-
await fs8.writeFile(
|
|
638
|
+
await fs8.writeFile(
|
|
639
|
+
handlerPath,
|
|
640
|
+
createNitroWorkflowHTTPHandler(workflowConfig, workflows),
|
|
641
|
+
"utf8"
|
|
642
|
+
);
|
|
639
643
|
const manifestPath = path22.join(generatedDir, "manifest.json");
|
|
640
644
|
await fs8.writeFile(
|
|
641
645
|
manifestPath,
|
|
@@ -709,13 +713,7 @@ function normalizeSchedule(schedule) {
|
|
|
709
713
|
return (Array.isArray(schedule) ? schedule : [schedule]).map((value) => value.trim()).filter(Boolean);
|
|
710
714
|
}
|
|
711
715
|
function resolveWorkflowDefinition(module2) {
|
|
712
|
-
const candidates = [
|
|
713
|
-
module2.default,
|
|
714
|
-
module2.workflow,
|
|
715
|
-
module2.cron,
|
|
716
|
-
module2.task,
|
|
717
|
-
module2.job
|
|
718
|
-
];
|
|
716
|
+
const candidates = [module2.default, module2.workflow, module2.cron, module2.task, module2.job];
|
|
719
717
|
for (const candidate of candidates) {
|
|
720
718
|
if (candidate && typeof candidate === "object" && typeof candidate.run === "function") {
|
|
721
719
|
return candidate;
|
|
@@ -1708,8 +1706,8 @@ function compareFarmRouteRuleSpecificity(left, right) {
|
|
|
1708
1706
|
}
|
|
1709
1707
|
function getFarmRouteRuleSpecificity(pattern) {
|
|
1710
1708
|
return normalizeRoutePattern(pattern).split("/").filter(Boolean).reduce((score, segment) => {
|
|
1711
|
-
if (segment === "**" ||
|
|
1712
|
-
if (segment === "*" ||
|
|
1709
|
+
if (segment === "**" || segment.startsWith("[[...")) return score + 1;
|
|
1710
|
+
if (segment === "*" || segment.startsWith("[...")) return score + 10;
|
|
1713
1711
|
if (/^\[.+\]$/.test(segment) || /^:.+$/.test(segment)) return score + 50;
|
|
1714
1712
|
return score + 100;
|
|
1715
1713
|
}, 0);
|
|
@@ -1769,22 +1767,50 @@ var init_route_rules = __esm({
|
|
|
1769
1767
|
// src/cache-invalidation.ts
|
|
1770
1768
|
function getFarmCacheInvalidationState() {
|
|
1771
1769
|
return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
|
|
1772
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1770
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1771
|
+
taskListeners: /* @__PURE__ */ new Set()
|
|
1773
1772
|
});
|
|
1774
1773
|
}
|
|
1774
|
+
function encodeFarmCacheInvalidations(keys) {
|
|
1775
|
+
const normalized = Array.from(
|
|
1776
|
+
new Set(keys.filter((key) => typeof key === "string" && key.length > 0))
|
|
1777
|
+
);
|
|
1778
|
+
if (normalized.length === 0) return null;
|
|
1779
|
+
return encodeURIComponent(JSON.stringify(normalized));
|
|
1780
|
+
}
|
|
1781
|
+
function decodeFarmCacheInvalidations(value) {
|
|
1782
|
+
if (!value) return [];
|
|
1783
|
+
try {
|
|
1784
|
+
const parsed = JSON.parse(decodeURIComponent(value));
|
|
1785
|
+
return Array.isArray(parsed) ? Array.from(
|
|
1786
|
+
new Set(parsed.filter((key) => typeof key === "string" && key.length > 0))
|
|
1787
|
+
) : [];
|
|
1788
|
+
} catch {
|
|
1789
|
+
return [];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1775
1792
|
function subscribeFarmCacheInvalidation(listener) {
|
|
1776
1793
|
const state = getFarmCacheInvalidationState();
|
|
1777
1794
|
state.listeners.add(listener);
|
|
1778
1795
|
return () => state.listeners.delete(listener);
|
|
1779
1796
|
}
|
|
1780
|
-
|
|
1797
|
+
function subscribeFarmCacheTask(listener) {
|
|
1798
|
+
const state = getFarmCacheInvalidationState();
|
|
1799
|
+
state.taskListeners.add(listener);
|
|
1800
|
+
return () => state.taskListeners.delete(listener);
|
|
1801
|
+
}
|
|
1802
|
+
var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
|
|
1781
1803
|
var init_cache_invalidation = __esm({
|
|
1782
1804
|
"src/cache-invalidation.ts"() {
|
|
1783
1805
|
"use strict";
|
|
1806
|
+
FARM_CACHE_INVALIDATION_HEADER = "x-farm-cache-invalidations";
|
|
1784
1807
|
FARM_CACHE_INVALIDATION_STATE = /* @__PURE__ */ Symbol.for("farm.cacheInvalidationState");
|
|
1785
1808
|
globalState = globalThis;
|
|
1786
1809
|
__name(getFarmCacheInvalidationState, "getFarmCacheInvalidationState");
|
|
1810
|
+
__name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
|
|
1811
|
+
__name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
|
|
1787
1812
|
__name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
|
|
1813
|
+
__name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
|
|
1788
1814
|
}
|
|
1789
1815
|
});
|
|
1790
1816
|
|
|
@@ -1888,6 +1914,9 @@ var init_server_action_security = __esm({
|
|
|
1888
1914
|
subscribeFarmCacheInvalidation((key) => {
|
|
1889
1915
|
getServerActionExecutionContext()?.invalidations.add(key);
|
|
1890
1916
|
});
|
|
1917
|
+
subscribeFarmCacheTask((task) => {
|
|
1918
|
+
getServerActionExecutionContext()?.cacheTasks.add(task);
|
|
1919
|
+
});
|
|
1891
1920
|
__name(getServerActionStorage, "getServerActionStorage");
|
|
1892
1921
|
__name(parseBodySizeLimit, "parseBodySizeLimit");
|
|
1893
1922
|
__name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
|
|
@@ -4833,7 +4862,9 @@ function readManifest(contentDir) {
|
|
|
4833
4862
|
const manifestPath = import_node_path7.default.join(contentDir, FARM_DOCS_LAST_MODIFIED_MANIFEST);
|
|
4834
4863
|
if (!(0, import_node_fs5.existsSync)(manifestPath)) return null;
|
|
4835
4864
|
try {
|
|
4836
|
-
const parsed = JSON.parse(
|
|
4865
|
+
const parsed = JSON.parse(
|
|
4866
|
+
(0, import_node_fs5.readFileSync)(manifestPath, "utf8")
|
|
4867
|
+
);
|
|
4837
4868
|
if (parsed.version !== 1 || !parsed.pages || typeof parsed.pages !== "object") return null;
|
|
4838
4869
|
const pages = Object.fromEntries(
|
|
4839
4870
|
Object.entries(parsed.pages).filter(
|
|
@@ -11115,16 +11146,7 @@ __export(devtools_client_exports, {
|
|
|
11115
11146
|
function parseShortcut(shortcut) {
|
|
11116
11147
|
const tokens = shortcut.toLowerCase().split("+").map((token) => token.trim()).filter(Boolean);
|
|
11117
11148
|
const key = tokens.find(
|
|
11118
|
-
(token) => ![
|
|
11119
|
-
"alt",
|
|
11120
|
-
"ctrl",
|
|
11121
|
-
"control",
|
|
11122
|
-
"meta",
|
|
11123
|
-
"cmd",
|
|
11124
|
-
"command",
|
|
11125
|
-
"mod",
|
|
11126
|
-
"shift"
|
|
11127
|
-
].includes(token)
|
|
11149
|
+
(token) => !["alt", "ctrl", "control", "meta", "cmd", "command", "mod", "shift"].includes(token)
|
|
11128
11150
|
);
|
|
11129
11151
|
if (!key) {
|
|
11130
11152
|
return null;
|
|
@@ -12063,11 +12085,51 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
|
|
|
12063
12085
|
// src/cache.ts
|
|
12064
12086
|
init_cache_invalidation();
|
|
12065
12087
|
var _FarmDataCache = class _FarmDataCache {
|
|
12066
|
-
constructor() {
|
|
12088
|
+
constructor(config = {}) {
|
|
12067
12089
|
this.entries = /* @__PURE__ */ new Map();
|
|
12068
12090
|
this.inflight = /* @__PURE__ */ new Map();
|
|
12069
12091
|
this.invalidatedTagVersions = /* @__PURE__ */ new Map();
|
|
12070
12092
|
this.version = 0;
|
|
12093
|
+
this.namespace = "farm";
|
|
12094
|
+
this.local = true;
|
|
12095
|
+
this.lease = {
|
|
12096
|
+
enabled: true,
|
|
12097
|
+
ttlMs: 1e4,
|
|
12098
|
+
waitTimeoutMs: 1e4,
|
|
12099
|
+
pollIntervalMs: 25
|
|
12100
|
+
};
|
|
12101
|
+
this.configure(config);
|
|
12102
|
+
}
|
|
12103
|
+
configure(config = {}) {
|
|
12104
|
+
this.adapter = config.adapter;
|
|
12105
|
+
this.namespace = normalizeCacheNamespace(config.namespace || "farm");
|
|
12106
|
+
this.local = !config.adapter;
|
|
12107
|
+
this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
|
|
12108
|
+
enabled: true,
|
|
12109
|
+
ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
|
|
12110
|
+
waitTimeoutMs: normalizePositiveDuration(
|
|
12111
|
+
config.lease?.waitTimeoutMs,
|
|
12112
|
+
1e4,
|
|
12113
|
+
"cache.lease.waitTimeoutMs"
|
|
12114
|
+
),
|
|
12115
|
+
pollIntervalMs: normalizePositiveDuration(
|
|
12116
|
+
config.lease?.pollIntervalMs,
|
|
12117
|
+
25,
|
|
12118
|
+
"cache.lease.pollIntervalMs"
|
|
12119
|
+
)
|
|
12120
|
+
};
|
|
12121
|
+
if (!this.local) {
|
|
12122
|
+
this.entries.clear();
|
|
12123
|
+
this.inflight.clear();
|
|
12124
|
+
this.invalidatedTagVersions.clear();
|
|
12125
|
+
this.version = 0;
|
|
12126
|
+
}
|
|
12127
|
+
}
|
|
12128
|
+
get adapterName() {
|
|
12129
|
+
return this.adapter?.name || (this.adapter ? "custom" : "memory");
|
|
12130
|
+
}
|
|
12131
|
+
get hasAdapter() {
|
|
12132
|
+
return this.adapter !== void 0;
|
|
12071
12133
|
}
|
|
12072
12134
|
get size() {
|
|
12073
12135
|
return this.entries.size;
|
|
@@ -12103,6 +12165,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12103
12165
|
});
|
|
12104
12166
|
return this.toPublicEntry(entry);
|
|
12105
12167
|
}
|
|
12168
|
+
async getEntryAsync(key, options = {}) {
|
|
12169
|
+
if (this.local) {
|
|
12170
|
+
const localEntry = this.getEntry(key, options);
|
|
12171
|
+
if (localEntry) return localEntry;
|
|
12172
|
+
}
|
|
12173
|
+
if (!this.adapter) {
|
|
12174
|
+
return this.local ? void 0 : this.getEntry(key, options);
|
|
12175
|
+
}
|
|
12176
|
+
const entry = await this.adapter.get(this.createAdapterKey(key));
|
|
12177
|
+
if (!entry) {
|
|
12178
|
+
emitFarmEvent({ type: "cache.miss", key });
|
|
12179
|
+
return void 0;
|
|
12180
|
+
}
|
|
12181
|
+
assertFarmCacheEntry(entry, key);
|
|
12182
|
+
const stale = await this.isAdapterEntryStale(entry, options.now);
|
|
12183
|
+
if (stale) {
|
|
12184
|
+
emitFarmEvent({
|
|
12185
|
+
type: "cache.stale",
|
|
12186
|
+
key,
|
|
12187
|
+
tags: [...entry.tags],
|
|
12188
|
+
revalidate: entry.revalidate
|
|
12189
|
+
});
|
|
12190
|
+
if (!options.allowStale) {
|
|
12191
|
+
emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
|
|
12192
|
+
return void 0;
|
|
12193
|
+
}
|
|
12194
|
+
}
|
|
12195
|
+
emitFarmEvent({
|
|
12196
|
+
type: "cache.hit",
|
|
12197
|
+
key,
|
|
12198
|
+
tags: [...entry.tags],
|
|
12199
|
+
revalidate: entry.revalidate,
|
|
12200
|
+
stale
|
|
12201
|
+
});
|
|
12202
|
+
if (this.local && !stale) {
|
|
12203
|
+
this.hydrateLocalEntry(entry);
|
|
12204
|
+
}
|
|
12205
|
+
return { ...entry, key };
|
|
12206
|
+
}
|
|
12106
12207
|
set(key, value, options = {}) {
|
|
12107
12208
|
const tags = /* @__PURE__ */ new Set();
|
|
12108
12209
|
for (const tag of options.tags ?? []) {
|
|
@@ -12115,6 +12216,7 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12115
12216
|
key,
|
|
12116
12217
|
value,
|
|
12117
12218
|
tags,
|
|
12219
|
+
tagVersions: void 0,
|
|
12118
12220
|
createdAt: options.createdAt ?? Date.now(),
|
|
12119
12221
|
createdVersion: ++this.version,
|
|
12120
12222
|
revalidate: normalizeRevalidate(options.revalidate)
|
|
@@ -12128,11 +12230,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12128
12230
|
});
|
|
12129
12231
|
return this.toPublicEntry(entry);
|
|
12130
12232
|
}
|
|
12233
|
+
async setAsync(key, value, options = {}, tagVersions) {
|
|
12234
|
+
const tags = normalizeCacheOptionsTags(options);
|
|
12235
|
+
const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
|
|
12236
|
+
const entry = {
|
|
12237
|
+
key,
|
|
12238
|
+
value,
|
|
12239
|
+
tags: Array.from(tags),
|
|
12240
|
+
tagVersions: capturedVersions,
|
|
12241
|
+
createdAt: options.createdAt ?? Date.now(),
|
|
12242
|
+
createdVersion: ++this.version,
|
|
12243
|
+
revalidate: normalizeRevalidate(options.revalidate)
|
|
12244
|
+
};
|
|
12245
|
+
if (this.local) {
|
|
12246
|
+
this.hydrateLocalEntry(entry);
|
|
12247
|
+
}
|
|
12248
|
+
if (this.adapter) {
|
|
12249
|
+
await this.adapter.set(this.createAdapterKey(key), entry);
|
|
12250
|
+
}
|
|
12251
|
+
emitFarmEvent({
|
|
12252
|
+
type: "cache.set",
|
|
12253
|
+
key,
|
|
12254
|
+
tags: [...entry.tags],
|
|
12255
|
+
revalidate: entry.revalidate
|
|
12256
|
+
});
|
|
12257
|
+
return entry;
|
|
12258
|
+
}
|
|
12131
12259
|
delete(key) {
|
|
12132
12260
|
const deleted = this.entries.delete(key);
|
|
12133
12261
|
emitFarmEvent({ type: "cache.delete", key, deleted });
|
|
12134
12262
|
return deleted;
|
|
12135
12263
|
}
|
|
12264
|
+
async deleteAsync(key) {
|
|
12265
|
+
const deleted = this.entries.delete(key);
|
|
12266
|
+
if (this.adapter) {
|
|
12267
|
+
await this.adapter.delete(this.createAdapterKey(key));
|
|
12268
|
+
}
|
|
12269
|
+
emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
|
|
12270
|
+
return this.adapter ? true : deleted;
|
|
12271
|
+
}
|
|
12136
12272
|
clear() {
|
|
12137
12273
|
const count = this.entries.size;
|
|
12138
12274
|
this.entries.clear();
|
|
@@ -12141,6 +12277,10 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12141
12277
|
this.version = 0;
|
|
12142
12278
|
emitFarmEvent({ type: "cache.clear", count });
|
|
12143
12279
|
}
|
|
12280
|
+
async clearAsync() {
|
|
12281
|
+
this.clear();
|
|
12282
|
+
await this.adapter?.clear?.();
|
|
12283
|
+
}
|
|
12144
12284
|
isStale(entry, now = Date.now()) {
|
|
12145
12285
|
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
12146
12286
|
return true;
|
|
@@ -12153,6 +12293,12 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12153
12293
|
}
|
|
12154
12294
|
return false;
|
|
12155
12295
|
}
|
|
12296
|
+
async isStaleAsync(entry, now = Date.now()) {
|
|
12297
|
+
if (this.adapter) {
|
|
12298
|
+
return this.isAdapterEntryStale(entry, now);
|
|
12299
|
+
}
|
|
12300
|
+
return this.isStale(entry, now);
|
|
12301
|
+
}
|
|
12156
12302
|
revalidateTag(tag, options = {}) {
|
|
12157
12303
|
const normalized = normalizeCacheTag(tag);
|
|
12158
12304
|
const count = this.invalidateTag(normalized);
|
|
@@ -12161,6 +12307,15 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12161
12307
|
);
|
|
12162
12308
|
return count;
|
|
12163
12309
|
}
|
|
12310
|
+
async revalidateTagAsync(tag, options = {}) {
|
|
12311
|
+
const normalized = normalizeCacheTag(tag);
|
|
12312
|
+
const count = this.invalidateTag(normalized);
|
|
12313
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
|
|
12314
|
+
emitFarmEvent(
|
|
12315
|
+
options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
|
|
12316
|
+
);
|
|
12317
|
+
return count;
|
|
12318
|
+
}
|
|
12164
12319
|
revalidatePath(routePath) {
|
|
12165
12320
|
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
12166
12321
|
const pathTag = createPathCacheTag(normalizedPath);
|
|
@@ -12177,8 +12332,25 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12177
12332
|
}
|
|
12178
12333
|
return count;
|
|
12179
12334
|
}
|
|
12335
|
+
async revalidatePathAsync(routePath) {
|
|
12336
|
+
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
12337
|
+
const pathTag = createPathCacheTag(normalizedPath);
|
|
12338
|
+
const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
|
|
12339
|
+
const count = this.invalidateTag(pathTag);
|
|
12340
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
|
|
12341
|
+
emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
|
|
12342
|
+
if (pprCount > 0) {
|
|
12343
|
+
emitFarmEvent({
|
|
12344
|
+
type: "ppr.shell.invalidated",
|
|
12345
|
+
route: normalizedPath,
|
|
12346
|
+
reason: "revalidatePath",
|
|
12347
|
+
count: pprCount
|
|
12348
|
+
});
|
|
12349
|
+
}
|
|
12350
|
+
return count;
|
|
12351
|
+
}
|
|
12180
12352
|
async getOrSet(key, producer, options = {}) {
|
|
12181
|
-
const cached = this.
|
|
12353
|
+
const cached = await this.getEntryAsync(key);
|
|
12182
12354
|
if (cached) {
|
|
12183
12355
|
return cached.value;
|
|
12184
12356
|
}
|
|
@@ -12187,10 +12359,8 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12187
12359
|
emitFarmEvent({ type: "cache.dedupe", key });
|
|
12188
12360
|
return inflight;
|
|
12189
12361
|
}
|
|
12190
|
-
const
|
|
12191
|
-
|
|
12192
|
-
return value;
|
|
12193
|
-
}).catch((error) => {
|
|
12362
|
+
const tags = Array.from(normalizeCacheOptionsTags(options));
|
|
12363
|
+
const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
|
|
12194
12364
|
emitFarmEvent({ type: "cache.error", key, operation: "set", error });
|
|
12195
12365
|
throw error;
|
|
12196
12366
|
}).finally(() => {
|
|
@@ -12199,6 +12369,40 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12199
12369
|
this.inflight.set(key, promise);
|
|
12200
12370
|
return promise;
|
|
12201
12371
|
}
|
|
12372
|
+
async fillCacheEntry(key, producer, options, tags) {
|
|
12373
|
+
const leaseKey = `${this.namespace}:lease:${key}`;
|
|
12374
|
+
let leaseToken;
|
|
12375
|
+
if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
|
|
12376
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
12377
|
+
if (!leaseToken) {
|
|
12378
|
+
const shared = await this.waitForAdapterEntry(key);
|
|
12379
|
+
if (shared) {
|
|
12380
|
+
emitFarmEvent({ type: "cache.dedupe", key });
|
|
12381
|
+
return shared.value;
|
|
12382
|
+
}
|
|
12383
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
12384
|
+
}
|
|
12385
|
+
}
|
|
12386
|
+
try {
|
|
12387
|
+
const initialTagVersions = await this.getAdapterTagVersions(tags);
|
|
12388
|
+
const value = await producer();
|
|
12389
|
+
await this.setAsync(key, value, options, initialTagVersions);
|
|
12390
|
+
return value;
|
|
12391
|
+
} finally {
|
|
12392
|
+
if (leaseToken && this.adapter?.releaseLease) {
|
|
12393
|
+
await this.adapter.releaseLease(leaseKey, leaseToken);
|
|
12394
|
+
}
|
|
12395
|
+
}
|
|
12396
|
+
}
|
|
12397
|
+
async waitForAdapterEntry(key) {
|
|
12398
|
+
const deadline = Date.now() + this.lease.waitTimeoutMs;
|
|
12399
|
+
while (Date.now() < deadline) {
|
|
12400
|
+
await delay(this.lease.pollIntervalMs);
|
|
12401
|
+
const entry = await this.getEntryAsync(key);
|
|
12402
|
+
if (entry) return entry;
|
|
12403
|
+
}
|
|
12404
|
+
return void 0;
|
|
12405
|
+
}
|
|
12202
12406
|
countEntriesForTag(tag) {
|
|
12203
12407
|
let count = 0;
|
|
12204
12408
|
for (const entry of this.entries.values()) {
|
|
@@ -12226,11 +12430,53 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12226
12430
|
key: entry.key,
|
|
12227
12431
|
value: entry.value,
|
|
12228
12432
|
tags: Array.from(entry.tags),
|
|
12433
|
+
tagVersions: entry.tagVersions,
|
|
12229
12434
|
createdAt: entry.createdAt,
|
|
12230
12435
|
createdVersion: entry.createdVersion,
|
|
12231
12436
|
revalidate: entry.revalidate
|
|
12232
12437
|
};
|
|
12233
12438
|
}
|
|
12439
|
+
hydrateLocalEntry(entry) {
|
|
12440
|
+
this.entries.set(entry.key, {
|
|
12441
|
+
key: entry.key,
|
|
12442
|
+
value: entry.value,
|
|
12443
|
+
tags: new Set(entry.tags.map(normalizeCacheTag)),
|
|
12444
|
+
tagVersions: entry.tagVersions,
|
|
12445
|
+
createdAt: entry.createdAt,
|
|
12446
|
+
createdVersion: entry.createdVersion ?? ++this.version,
|
|
12447
|
+
revalidate: normalizeRevalidate(entry.revalidate)
|
|
12448
|
+
});
|
|
12449
|
+
}
|
|
12450
|
+
createAdapterKey(key) {
|
|
12451
|
+
return `${this.namespace}:entry:${key}`;
|
|
12452
|
+
}
|
|
12453
|
+
createAdapterTag(tag) {
|
|
12454
|
+
return `${this.namespace}:tag:${tag}`;
|
|
12455
|
+
}
|
|
12456
|
+
async getAdapterTagVersions(tags) {
|
|
12457
|
+
if (!this.adapter?.getTagVersions || tags.length === 0) return {};
|
|
12458
|
+
const normalized = tags.map(normalizeCacheTag);
|
|
12459
|
+
const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
|
|
12460
|
+
const versions = await this.adapter.getTagVersions(physicalTags);
|
|
12461
|
+
return Object.fromEntries(
|
|
12462
|
+
normalized.map((tag, index) => [
|
|
12463
|
+
tag,
|
|
12464
|
+
normalizeAdapterVersion(versions[physicalTags[index]])
|
|
12465
|
+
])
|
|
12466
|
+
);
|
|
12467
|
+
}
|
|
12468
|
+
async isAdapterEntryStale(entry, now = Date.now()) {
|
|
12469
|
+
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
12470
|
+
return true;
|
|
12471
|
+
}
|
|
12472
|
+
const currentVersions = await this.getAdapterTagVersions(entry.tags);
|
|
12473
|
+
for (const tag of entry.tags) {
|
|
12474
|
+
if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
|
|
12475
|
+
return true;
|
|
12476
|
+
}
|
|
12477
|
+
}
|
|
12478
|
+
return false;
|
|
12479
|
+
}
|
|
12234
12480
|
};
|
|
12235
12481
|
__name(_FarmDataCache, "FarmDataCache");
|
|
12236
12482
|
var FarmDataCache = _FarmDataCache;
|
|
@@ -12243,6 +12489,10 @@ function getFarmDataCache() {
|
|
|
12243
12489
|
return sharedFarmDataCache;
|
|
12244
12490
|
}
|
|
12245
12491
|
__name(getFarmDataCache, "getFarmDataCache");
|
|
12492
|
+
function configureFarmCache(config) {
|
|
12493
|
+
sharedFarmDataCache.configure(config);
|
|
12494
|
+
}
|
|
12495
|
+
__name(configureFarmCache, "configureFarmCache");
|
|
12246
12496
|
function createPathCacheTag(routePath) {
|
|
12247
12497
|
return `path:${normalizeRevalidatePath(routePath)}`;
|
|
12248
12498
|
}
|
|
@@ -12303,6 +12553,52 @@ function normalizeCacheTag(tag) {
|
|
|
12303
12553
|
return normalized;
|
|
12304
12554
|
}
|
|
12305
12555
|
__name(normalizeCacheTag, "normalizeCacheTag");
|
|
12556
|
+
function normalizeCacheNamespace(namespace) {
|
|
12557
|
+
if (typeof namespace !== "string") {
|
|
12558
|
+
throw new TypeError("Cache namespace must be a string.");
|
|
12559
|
+
}
|
|
12560
|
+
const normalized = namespace.trim().replace(/:+$/g, "");
|
|
12561
|
+
if (!normalized) {
|
|
12562
|
+
throw new Error("Cache namespace cannot be empty.");
|
|
12563
|
+
}
|
|
12564
|
+
return normalized;
|
|
12565
|
+
}
|
|
12566
|
+
__name(normalizeCacheNamespace, "normalizeCacheNamespace");
|
|
12567
|
+
function normalizeAdapterVersion(value) {
|
|
12568
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
12569
|
+
}
|
|
12570
|
+
__name(normalizeAdapterVersion, "normalizeAdapterVersion");
|
|
12571
|
+
function normalizePositiveDuration(value, fallback, name) {
|
|
12572
|
+
if (value === void 0) return fallback;
|
|
12573
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
12574
|
+
throw new TypeError(`${name} must be a positive number of milliseconds.`);
|
|
12575
|
+
}
|
|
12576
|
+
return Math.floor(value);
|
|
12577
|
+
}
|
|
12578
|
+
__name(normalizePositiveDuration, "normalizePositiveDuration");
|
|
12579
|
+
function delay(ms) {
|
|
12580
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
12581
|
+
}
|
|
12582
|
+
__name(delay, "delay");
|
|
12583
|
+
function normalizeCacheOptionsTags(options) {
|
|
12584
|
+
const tags = /* @__PURE__ */ new Set();
|
|
12585
|
+
for (const tag of options.tags ?? []) {
|
|
12586
|
+
tags.add(normalizeCacheTag(tag));
|
|
12587
|
+
}
|
|
12588
|
+
for (const routePath of options.paths ?? []) {
|
|
12589
|
+
tags.add(createPathCacheTag(routePath));
|
|
12590
|
+
}
|
|
12591
|
+
return tags;
|
|
12592
|
+
}
|
|
12593
|
+
__name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
|
|
12594
|
+
function assertFarmCacheEntry(entry, expectedKey) {
|
|
12595
|
+
if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
|
|
12596
|
+
throw new TypeError(
|
|
12597
|
+
`Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
|
|
12598
|
+
);
|
|
12599
|
+
}
|
|
12600
|
+
}
|
|
12601
|
+
__name(assertFarmCacheEntry, "assertFarmCacheEntry");
|
|
12306
12602
|
function getFunctionCacheIdentity(fn) {
|
|
12307
12603
|
if (fn.name) {
|
|
12308
12604
|
return `name:${fn.name}`;
|
|
@@ -13443,6 +13739,76 @@ function normalizePathname(pathname) {
|
|
|
13443
13739
|
}
|
|
13444
13740
|
__name(normalizePathname, "normalizePathname");
|
|
13445
13741
|
|
|
13742
|
+
// src/routing/route-slots.ts
|
|
13743
|
+
var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
|
|
13744
|
+
function parseRouteSlotFile(filePath) {
|
|
13745
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
13746
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
13747
|
+
const fileName = parts.at(-1) ?? "";
|
|
13748
|
+
const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
13749
|
+
if (baseName !== "page" && baseName !== "default") return null;
|
|
13750
|
+
const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
|
|
13751
|
+
if (slotIndex < 0) return null;
|
|
13752
|
+
if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
|
|
13753
|
+
throw new Error(`Nested route slots are not supported in "${filePath}"`);
|
|
13754
|
+
}
|
|
13755
|
+
const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
|
|
13756
|
+
const name = slotMatch?.[1];
|
|
13757
|
+
if (!name) return null;
|
|
13758
|
+
const ownerParts = parts.slice(0, slotIndex);
|
|
13759
|
+
const contentParts = parts.slice(slotIndex + 1, -1);
|
|
13760
|
+
const marker = parseInterceptionMarker(contentParts[0]);
|
|
13761
|
+
let targetBase = ownerParts;
|
|
13762
|
+
let targetParts = contentParts;
|
|
13763
|
+
if (marker) {
|
|
13764
|
+
targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
|
|
13765
|
+
targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
|
|
13766
|
+
}
|
|
13767
|
+
const ownerFile = [...ownerParts, "layout.tsx"].join("/");
|
|
13768
|
+
const routeFile = [
|
|
13769
|
+
...baseName === "default" ? ownerParts : targetBase,
|
|
13770
|
+
...baseName === "default" ? [] : targetParts,
|
|
13771
|
+
"page.tsx"
|
|
13772
|
+
].join("/");
|
|
13773
|
+
return {
|
|
13774
|
+
name,
|
|
13775
|
+
ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
|
|
13776
|
+
route: parseRoutePath(routeFile || "page.tsx"),
|
|
13777
|
+
interception: marker !== null,
|
|
13778
|
+
fallback: baseName === "default"
|
|
13779
|
+
};
|
|
13780
|
+
}
|
|
13781
|
+
__name(parseRouteSlotFile, "parseRouteSlotFile");
|
|
13782
|
+
function createRouteSlotContainerId(name, ownerPattern) {
|
|
13783
|
+
const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
13784
|
+
return `__farm_slot_${name}_${owner || "root"}__`;
|
|
13785
|
+
}
|
|
13786
|
+
__name(createRouteSlotContainerId, "createRouteSlotContainerId");
|
|
13787
|
+
function parseInterceptionMarker(segment) {
|
|
13788
|
+
if (!segment) return null;
|
|
13789
|
+
if (segment.startsWith("(...)")) {
|
|
13790
|
+
return {
|
|
13791
|
+
up: 0,
|
|
13792
|
+
root: true,
|
|
13793
|
+
remainder: segment.slice(5)
|
|
13794
|
+
};
|
|
13795
|
+
}
|
|
13796
|
+
if (segment.startsWith("(.)")) {
|
|
13797
|
+
return {
|
|
13798
|
+
up: 0,
|
|
13799
|
+
remainder: segment.slice(3)
|
|
13800
|
+
};
|
|
13801
|
+
}
|
|
13802
|
+
let remainder = segment;
|
|
13803
|
+
let up = 0;
|
|
13804
|
+
while (remainder.startsWith("(..)")) {
|
|
13805
|
+
up += 1;
|
|
13806
|
+
remainder = remainder.slice(4);
|
|
13807
|
+
}
|
|
13808
|
+
return up > 0 ? { up, remainder } : null;
|
|
13809
|
+
}
|
|
13810
|
+
__name(parseInterceptionMarker, "parseInterceptionMarker");
|
|
13811
|
+
|
|
13446
13812
|
// src/routing/route-manager.ts
|
|
13447
13813
|
function routeSpecificity(entry) {
|
|
13448
13814
|
return entry.route.segments.reduce((score, segment) => {
|
|
@@ -13456,6 +13822,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13456
13822
|
constructor(config, viteServer) {
|
|
13457
13823
|
this.routes = /* @__PURE__ */ new Map();
|
|
13458
13824
|
this.layouts = /* @__PURE__ */ new Map();
|
|
13825
|
+
this.routeSlots = /* @__PURE__ */ new Map();
|
|
13459
13826
|
this.loadings = /* @__PURE__ */ new Map();
|
|
13460
13827
|
this.errors = /* @__PURE__ */ new Map();
|
|
13461
13828
|
this.metadataImages = /* @__PURE__ */ new Map();
|
|
@@ -13471,6 +13838,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13471
13838
|
async discoverRoutes() {
|
|
13472
13839
|
this.routes.clear();
|
|
13473
13840
|
this.layouts.clear();
|
|
13841
|
+
this.routeSlots.clear();
|
|
13474
13842
|
this.loadings.clear();
|
|
13475
13843
|
this.errors.clear();
|
|
13476
13844
|
this.metadataImages.clear();
|
|
@@ -13481,6 +13849,13 @@ var _RouteManager = class _RouteManager {
|
|
|
13481
13849
|
await this.discoverFileRoutes(source);
|
|
13482
13850
|
await this.discoverProgrammaticRoutes(source);
|
|
13483
13851
|
}
|
|
13852
|
+
for (const slot of this.routeSlots.values()) {
|
|
13853
|
+
if (slot.interception && !this.routes.has(slot.pattern)) {
|
|
13854
|
+
throw new Error(
|
|
13855
|
+
`Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
|
|
13856
|
+
);
|
|
13857
|
+
}
|
|
13858
|
+
}
|
|
13484
13859
|
this.routes = new Map(
|
|
13485
13860
|
Array.from(this.routes.entries()).sort(
|
|
13486
13861
|
([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
|
|
@@ -13496,7 +13871,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13496
13871
|
/**
|
|
13497
13872
|
* Find matching route for a given URL path
|
|
13498
13873
|
*/
|
|
13499
|
-
matchRoute(pathname) {
|
|
13874
|
+
matchRoute(pathname, options = {}) {
|
|
13500
13875
|
const routePathname = this.toRoutePathname(pathname);
|
|
13501
13876
|
const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
|
|
13502
13877
|
let matchedRoute = null;
|
|
@@ -13510,10 +13885,12 @@ var _RouteManager = class _RouteManager {
|
|
|
13510
13885
|
}
|
|
13511
13886
|
}
|
|
13512
13887
|
const layouts = this.findMatchingLayouts(normalizedPath);
|
|
13888
|
+
const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
|
|
13513
13889
|
return {
|
|
13514
13890
|
route: matchedRoute,
|
|
13515
13891
|
params,
|
|
13516
|
-
layouts
|
|
13892
|
+
layouts,
|
|
13893
|
+
slots
|
|
13517
13894
|
};
|
|
13518
13895
|
}
|
|
13519
13896
|
/**
|
|
@@ -13528,6 +13905,9 @@ var _RouteManager = class _RouteManager {
|
|
|
13528
13905
|
getLayouts() {
|
|
13529
13906
|
return new Map(this.layouts);
|
|
13530
13907
|
}
|
|
13908
|
+
getRouteSlots() {
|
|
13909
|
+
return new Map(this.routeSlots);
|
|
13910
|
+
}
|
|
13531
13911
|
/** Resolve route rules, inherited layouts, and the page export in precedence order. */
|
|
13532
13912
|
async resolveRouteRuntimeConfig(pattern) {
|
|
13533
13913
|
const routeEntry = this.routes.get(pattern);
|
|
@@ -13686,7 +14066,22 @@ var _RouteManager = class _RouteManager {
|
|
|
13686
14066
|
pattern: entry.pattern,
|
|
13687
14067
|
modulePath: toUrlPath(entry.modulePath)
|
|
13688
14068
|
}));
|
|
13689
|
-
|
|
14069
|
+
const slots = Array.from(this.routeSlots.values()).map((entry) => {
|
|
14070
|
+
const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
|
|
14071
|
+
return {
|
|
14072
|
+
name: entry.name,
|
|
14073
|
+
ownerPattern: entry.ownerPattern,
|
|
14074
|
+
pattern: entry.pattern,
|
|
14075
|
+
modulePath: toUrlPath(entry.modulePath),
|
|
14076
|
+
containerId: entry.containerId,
|
|
14077
|
+
interception: entry.interception,
|
|
14078
|
+
fallback: entry.fallback,
|
|
14079
|
+
shouldHydrate: metadata.shouldHydrate,
|
|
14080
|
+
isClientComponent: metadata.isClientComponent,
|
|
14081
|
+
segments: entry.route.segments
|
|
14082
|
+
};
|
|
14083
|
+
});
|
|
14084
|
+
return { routes, layouts, slots };
|
|
13690
14085
|
}
|
|
13691
14086
|
/**
|
|
13692
14087
|
* Load a route module dynamically
|
|
@@ -13763,6 +14158,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13763
14158
|
async discoverFileRoutes(source) {
|
|
13764
14159
|
const appDir = resolveAppPath(source.root, source.srcDir, "app");
|
|
13765
14160
|
const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
|
|
14161
|
+
const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
|
|
13766
14162
|
const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
|
|
13767
14163
|
const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
|
|
13768
14164
|
const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
|
|
@@ -13771,7 +14167,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13771
14167
|
appDir
|
|
13772
14168
|
);
|
|
13773
14169
|
for (const [kind, files, target] of [
|
|
13774
|
-
["page", pageFiles, this.routes],
|
|
14170
|
+
["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
|
|
13775
14171
|
["layout", layoutFiles, this.layouts],
|
|
13776
14172
|
["loading", loadingFiles, this.loadings],
|
|
13777
14173
|
["error", errorFiles, this.errors]
|
|
@@ -13795,6 +14191,32 @@ var _RouteManager = class _RouteManager {
|
|
|
13795
14191
|
});
|
|
13796
14192
|
}
|
|
13797
14193
|
}
|
|
14194
|
+
for (const file of [...pageFiles, ...slotDefaultFiles]) {
|
|
14195
|
+
const slot = parseRouteSlotFile(file);
|
|
14196
|
+
if (!slot) continue;
|
|
14197
|
+
const modulePath = import_path5.default.join(appDir, file);
|
|
14198
|
+
const pattern = this.createRoutePattern(slot.route);
|
|
14199
|
+
const ownerPattern = this.createRoutePattern(slot.ownerRoute);
|
|
14200
|
+
const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
|
|
14201
|
+
const existing = this.routeSlots.get(key);
|
|
14202
|
+
if (existing?.sourceRoot === source.root) {
|
|
14203
|
+
throw new Error(
|
|
14204
|
+
`Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
|
|
14205
|
+
);
|
|
14206
|
+
}
|
|
14207
|
+
this.routeSlots.set(key, {
|
|
14208
|
+
route: slot.route,
|
|
14209
|
+
modulePath,
|
|
14210
|
+
pattern,
|
|
14211
|
+
source: "file",
|
|
14212
|
+
sourceRoot: source.root,
|
|
14213
|
+
name: slot.name,
|
|
14214
|
+
ownerPattern,
|
|
14215
|
+
interception: slot.interception,
|
|
14216
|
+
fallback: slot.fallback,
|
|
14217
|
+
containerId: createRouteSlotContainerId(slot.name, ownerPattern)
|
|
14218
|
+
});
|
|
14219
|
+
}
|
|
13798
14220
|
for (const file of metadataImageFiles) {
|
|
13799
14221
|
const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
|
|
13800
14222
|
const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
|
|
@@ -13920,6 +14342,71 @@ var _RouteManager = class _RouteManager {
|
|
|
13920
14342
|
}
|
|
13921
14343
|
return matchingLayouts;
|
|
13922
14344
|
}
|
|
14345
|
+
findMatchingRouteSlots(pathname, interceptFrom) {
|
|
14346
|
+
const groups = /* @__PURE__ */ new Map();
|
|
14347
|
+
for (const entry of this.routeSlots.values()) {
|
|
14348
|
+
if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
|
|
14349
|
+
const key = `${entry.ownerPattern}:${entry.name}`;
|
|
14350
|
+
const entries = groups.get(key) ?? [];
|
|
14351
|
+
entries.push(entry);
|
|
14352
|
+
groups.set(key, entries);
|
|
14353
|
+
}
|
|
14354
|
+
const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
|
|
14355
|
+
const matches = [];
|
|
14356
|
+
for (const entries of groups.values()) {
|
|
14357
|
+
const candidates = entries.filter((entry) => !entry.fallback).filter(
|
|
14358
|
+
(entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
|
|
14359
|
+
).map((entry) => ({
|
|
14360
|
+
entry,
|
|
14361
|
+
match: matchRoute(pathname, entry.route.segments)
|
|
14362
|
+
})).filter((candidate) => candidate.match.matches).sort((left, right) => {
|
|
14363
|
+
if (left.entry.interception !== right.entry.interception) {
|
|
14364
|
+
return left.entry.interception ? -1 : 1;
|
|
14365
|
+
}
|
|
14366
|
+
return routeSpecificity(right.entry) - routeSpecificity(left.entry);
|
|
14367
|
+
});
|
|
14368
|
+
const selected = candidates[0];
|
|
14369
|
+
if (selected) {
|
|
14370
|
+
matches.push({
|
|
14371
|
+
name: selected.entry.name,
|
|
14372
|
+
ownerPattern: selected.entry.ownerPattern,
|
|
14373
|
+
containerId: selected.entry.containerId,
|
|
14374
|
+
interception: selected.entry.interception,
|
|
14375
|
+
fallback: false,
|
|
14376
|
+
route: selected.entry,
|
|
14377
|
+
params: selected.match.params
|
|
14378
|
+
});
|
|
14379
|
+
continue;
|
|
14380
|
+
}
|
|
14381
|
+
const fallback = entries.find((entry) => entry.fallback);
|
|
14382
|
+
if (fallback) {
|
|
14383
|
+
matches.push({
|
|
14384
|
+
name: fallback.name,
|
|
14385
|
+
ownerPattern: fallback.ownerPattern,
|
|
14386
|
+
containerId: fallback.containerId,
|
|
14387
|
+
interception: false,
|
|
14388
|
+
fallback: true,
|
|
14389
|
+
route: fallback,
|
|
14390
|
+
params: {}
|
|
14391
|
+
});
|
|
14392
|
+
}
|
|
14393
|
+
}
|
|
14394
|
+
return matches.sort((left, right) => {
|
|
14395
|
+
const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
|
|
14396
|
+
return ownerDifference || left.name.localeCompare(right.name);
|
|
14397
|
+
});
|
|
14398
|
+
}
|
|
14399
|
+
matchesRoutePrefix(pathname, pattern) {
|
|
14400
|
+
if (pattern === "/") return true;
|
|
14401
|
+
const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
|
|
14402
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
14403
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
14404
|
+
for (let index = 0; index < patternSegments.length; index++) {
|
|
14405
|
+
const segment = patternSegments[index];
|
|
14406
|
+
if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
|
|
14407
|
+
}
|
|
14408
|
+
return true;
|
|
14409
|
+
}
|
|
13923
14410
|
findNearestBoundary(pathname, boundaries) {
|
|
13924
14411
|
const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
|
|
13925
14412
|
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
@@ -14522,7 +15009,7 @@ function mergeMetadata(base, next) {
|
|
|
14522
15009
|
__name(mergeMetadata, "mergeMetadata");
|
|
14523
15010
|
function addMetadataImageReference(metadata, reference) {
|
|
14524
15011
|
if (reference.kind === "opengraph") {
|
|
14525
|
-
const openGraph = { ...metadata.openGraph
|
|
15012
|
+
const openGraph = { ...metadata.openGraph };
|
|
14526
15013
|
if (!hasMetadataImages(openGraph.images) && !hasMetadataImages(openGraph.image)) {
|
|
14527
15014
|
openGraph.images = [
|
|
14528
15015
|
{
|
|
@@ -14539,7 +15026,7 @@ function addMetadataImageReference(metadata, reference) {
|
|
|
14539
15026
|
openGraph
|
|
14540
15027
|
};
|
|
14541
15028
|
}
|
|
14542
|
-
const twitter = { ...metadata.twitter
|
|
15029
|
+
const twitter = { ...metadata.twitter };
|
|
14543
15030
|
if (!hasMetadataImages(twitter.images)) {
|
|
14544
15031
|
twitter.images = [reference.href];
|
|
14545
15032
|
twitter.card = twitter.card || "summary_large_image";
|
|
@@ -15145,8 +15632,8 @@ var _FarmI18nRuntime = class _FarmI18nRuntime {
|
|
|
15145
15632
|
cookie: this.config.cookie,
|
|
15146
15633
|
direction: getFarmLocaleDirection(resolution.locale, this.config.direction),
|
|
15147
15634
|
messages: {
|
|
15148
|
-
...this.catalogs[this.config.fallbackLocale]
|
|
15149
|
-
...this.catalogs[resolution.locale]
|
|
15635
|
+
...this.catalogs[this.config.fallbackLocale],
|
|
15636
|
+
...this.catalogs[resolution.locale]
|
|
15150
15637
|
}
|
|
15151
15638
|
};
|
|
15152
15639
|
}
|
|
@@ -15448,7 +15935,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15448
15935
|
async runWithRequestContext(request, fn) {
|
|
15449
15936
|
return _runWithCurrentRequest(
|
|
15450
15937
|
request,
|
|
15451
|
-
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15938
|
+
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15939
|
+
redirect: false
|
|
15940
|
+
}) : fn()
|
|
15452
15941
|
);
|
|
15453
15942
|
}
|
|
15454
15943
|
async resolveRouteContext(input) {
|
|
@@ -15471,11 +15960,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15471
15960
|
/**
|
|
15472
15961
|
* Check if a path should be served from SSG cache
|
|
15473
15962
|
*/
|
|
15474
|
-
shouldServeSSG(pathname) {
|
|
15963
|
+
async shouldServeSSG(pathname) {
|
|
15475
15964
|
const ssgPage = matchSSGPage(pathname, this.ssgManifest);
|
|
15476
15965
|
if (!ssgPage) return null;
|
|
15477
|
-
const cached = this.getCachedSSGPage(pathname);
|
|
15478
|
-
if (cached && this.dataCache.
|
|
15966
|
+
const cached = await this.getCachedSSGPage(pathname);
|
|
15967
|
+
if (cached && await this.dataCache.isStaleAsync(cached)) {
|
|
15479
15968
|
this.regenerateSSGPage(ssgPage);
|
|
15480
15969
|
}
|
|
15481
15970
|
return ssgPage;
|
|
@@ -15487,12 +15976,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15487
15976
|
return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
|
|
15488
15977
|
}
|
|
15489
15978
|
getCachedSSGPage(urlPath) {
|
|
15490
|
-
return this.dataCache.
|
|
15979
|
+
return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
|
|
15491
15980
|
allowStale: true
|
|
15492
15981
|
});
|
|
15493
15982
|
}
|
|
15494
|
-
cacheSSGPage(page2, html, options) {
|
|
15495
|
-
this.dataCache.
|
|
15983
|
+
async cacheSSGPage(page2, html, options) {
|
|
15984
|
+
await this.dataCache.setAsync(
|
|
15496
15985
|
this.getSSGCacheKey(page2.urlPath),
|
|
15497
15986
|
{ html, document: options.document },
|
|
15498
15987
|
{
|
|
@@ -15504,11 +15993,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15504
15993
|
);
|
|
15505
15994
|
}
|
|
15506
15995
|
getCachedPPRShell(pathname, search) {
|
|
15507
|
-
return this.dataCache.
|
|
15996
|
+
return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
|
|
15508
15997
|
}
|
|
15509
|
-
cachePPRShell(options, html) {
|
|
15998
|
+
async cachePPRShell(options, html) {
|
|
15510
15999
|
const key = this.getPPRCacheKey(options.pathname, options.search);
|
|
15511
|
-
this.dataCache.
|
|
16000
|
+
await this.dataCache.setAsync(
|
|
15512
16001
|
key,
|
|
15513
16002
|
{ html },
|
|
15514
16003
|
{
|
|
@@ -15606,7 +16095,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15606
16095
|
}
|
|
15607
16096
|
const { renderToString } = await import("react-dom/server");
|
|
15608
16097
|
const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
|
|
15609
|
-
this.cacheSSGPage(page2, html, { document: false });
|
|
16098
|
+
await this.cacheSSGPage(page2, html, { document: false });
|
|
15610
16099
|
logger.info(`ISR: Regenerated ${page2.urlPath}`);
|
|
15611
16100
|
} catch (error) {
|
|
15612
16101
|
logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
|
|
@@ -15620,7 +16109,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15620
16109
|
* Serve a pre-rendered SSG page
|
|
15621
16110
|
*/
|
|
15622
16111
|
async serveSSGPage(req, res, page2) {
|
|
15623
|
-
const cached = this.getCachedSSGPage(page2.urlPath);
|
|
16112
|
+
const cached = await this.getCachedSSGPage(page2.urlPath);
|
|
15624
16113
|
if (cached) {
|
|
15625
16114
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15626
16115
|
res.setHeader("X-Farm-SSG", "cached");
|
|
@@ -15638,9 +16127,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15638
16127
|
if (fs2.existsSync(htmlPath)) {
|
|
15639
16128
|
const stat = fs2.statSync(htmlPath);
|
|
15640
16129
|
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
15641
|
-
this.cacheSSGPage(page2, html, {
|
|
15642
|
-
|
|
15643
|
-
|
|
16130
|
+
await this.cacheSSGPage(page2, html, {
|
|
16131
|
+
document: true,
|
|
16132
|
+
createdAt: stat.mtimeMs
|
|
16133
|
+
});
|
|
16134
|
+
const fileCacheEntry = await this.getCachedSSGPage(page2.urlPath);
|
|
16135
|
+
if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
|
|
15644
16136
|
this.regenerateSSGPage(page2);
|
|
15645
16137
|
}
|
|
15646
16138
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -15686,6 +16178,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15686
16178
|
let pathname = "/";
|
|
15687
16179
|
let params = {};
|
|
15688
16180
|
let layouts = [];
|
|
16181
|
+
let routeSlots = [];
|
|
15689
16182
|
let searchParamsObject = {};
|
|
15690
16183
|
let middlewareMap = /* @__PURE__ */ new Map();
|
|
15691
16184
|
let middlewareContext = /* @__PURE__ */ new Map();
|
|
@@ -15718,7 +16211,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15718
16211
|
}
|
|
15719
16212
|
this.applyDeploymentHeaders(req, res);
|
|
15720
16213
|
if (process.env.NODE_ENV === "production") {
|
|
15721
|
-
const ssgPage = this.shouldServeSSG(pathname);
|
|
16214
|
+
const ssgPage = await this.shouldServeSSG(pathname);
|
|
15722
16215
|
if (ssgPage) {
|
|
15723
16216
|
const served = await this.serveSSGPage(req, res, ssgPage);
|
|
15724
16217
|
if (served) {
|
|
@@ -15731,6 +16224,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15731
16224
|
const route = match.route;
|
|
15732
16225
|
params = match.params;
|
|
15733
16226
|
layouts = match.layouts;
|
|
16227
|
+
routeSlots = match.slots ?? [];
|
|
15734
16228
|
if (!route) {
|
|
15735
16229
|
emitFarmEvent({ type: "route.notFound", pathname });
|
|
15736
16230
|
await this.render404(req, res);
|
|
@@ -15747,7 +16241,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15747
16241
|
errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
|
|
15748
16242
|
middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
|
|
15749
16243
|
middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
|
|
15750
|
-
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
16244
|
+
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
16245
|
+
exposedOnly: true
|
|
16246
|
+
});
|
|
15751
16247
|
const currentRequest = createWebRequestFromFarmRequest(req);
|
|
15752
16248
|
const routeContext = await this.resolveRouteContext({
|
|
15753
16249
|
request: currentRequest,
|
|
@@ -15811,8 +16307,16 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15811
16307
|
revalidate: renderingConfig.revalidate
|
|
15812
16308
|
} : void 0;
|
|
15813
16309
|
if (renderingConfig.ppr && pprBypassReason) {
|
|
15814
|
-
emitFarmEvent({
|
|
15815
|
-
|
|
16310
|
+
emitFarmEvent({
|
|
16311
|
+
type: "ppr.shell.bypass",
|
|
16312
|
+
route: pathname,
|
|
16313
|
+
reason: pprBypassReason
|
|
16314
|
+
});
|
|
16315
|
+
emitFarmEvent({
|
|
16316
|
+
type: "cache.bypass",
|
|
16317
|
+
route: pathname,
|
|
16318
|
+
reason: pprBypassReason
|
|
16319
|
+
});
|
|
15816
16320
|
if (pprBypassReason === "refresh") {
|
|
15817
16321
|
pprRefreshRoute = pathname;
|
|
15818
16322
|
emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
|
|
@@ -15820,14 +16324,22 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15820
16324
|
}
|
|
15821
16325
|
if (pprShellOptions) {
|
|
15822
16326
|
const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
|
|
15823
|
-
const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
|
|
16327
|
+
const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
|
|
15824
16328
|
if (cachedPPRShell) {
|
|
15825
|
-
emitFarmEvent({
|
|
16329
|
+
emitFarmEvent({
|
|
16330
|
+
type: "ppr.shell.hit",
|
|
16331
|
+
route: pathname,
|
|
16332
|
+
key: pprCacheKey
|
|
16333
|
+
});
|
|
15826
16334
|
this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
|
|
15827
16335
|
completeRender(res.statusCode || 200, pathname);
|
|
15828
16336
|
return;
|
|
15829
16337
|
}
|
|
15830
|
-
emitFarmEvent({
|
|
16338
|
+
emitFarmEvent({
|
|
16339
|
+
type: "ppr.shell.miss",
|
|
16340
|
+
route: pathname,
|
|
16341
|
+
key: pprCacheKey
|
|
16342
|
+
});
|
|
15831
16343
|
}
|
|
15832
16344
|
let LoadingFallbackComponent = null;
|
|
15833
16345
|
if (loadingBoundaryEntry) {
|
|
@@ -15851,14 +16363,77 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15851
16363
|
);
|
|
15852
16364
|
const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
|
|
15853
16365
|
const isClientComponent = moduleMetadata.isClientComponent;
|
|
16366
|
+
const renderedRouteSlots = await Promise.all(
|
|
16367
|
+
routeSlots.map(async (slot) => {
|
|
16368
|
+
const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
|
|
16369
|
+
if (!slotModule.default) {
|
|
16370
|
+
throw new Error(
|
|
16371
|
+
`Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
|
|
16372
|
+
);
|
|
16373
|
+
}
|
|
16374
|
+
const slotContext = await this.resolveRouteContext({
|
|
16375
|
+
request: currentRequest,
|
|
16376
|
+
rawRequest: req,
|
|
16377
|
+
params: slot.params,
|
|
16378
|
+
search: searchParamsObject,
|
|
16379
|
+
path: pathname
|
|
16380
|
+
});
|
|
16381
|
+
const rawSlotProps = withFarmRouteContext(
|
|
16382
|
+
{
|
|
16383
|
+
params: slot.params,
|
|
16384
|
+
searchParams: Promise.resolve(searchParamsObject),
|
|
16385
|
+
path: pathname,
|
|
16386
|
+
middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
|
|
16387
|
+
context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
|
|
16388
|
+
},
|
|
16389
|
+
slotContext
|
|
16390
|
+
);
|
|
16391
|
+
const slotProps = await parseRouteModuleProps(slotModule, {
|
|
16392
|
+
props: rawSlotProps,
|
|
16393
|
+
search: searchParamsObject,
|
|
16394
|
+
routePath: slot.route.pattern
|
|
16395
|
+
});
|
|
16396
|
+
const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
|
|
16397
|
+
return {
|
|
16398
|
+
...slot,
|
|
16399
|
+
module: slotModule,
|
|
16400
|
+
props: slotProps,
|
|
16401
|
+
isClientComponent: metadata.isClientComponent,
|
|
16402
|
+
shouldHydrate: metadata.shouldHydrate
|
|
16403
|
+
};
|
|
16404
|
+
})
|
|
16405
|
+
);
|
|
15854
16406
|
const shouldHydrate = moduleMetadata.shouldHydrate;
|
|
16407
|
+
const hasHydratableRouteSlots = renderedRouteSlots.some(
|
|
16408
|
+
(slot) => slot.isClientComponent || slot.shouldHydrate
|
|
16409
|
+
);
|
|
15855
16410
|
req.__FARM_PAGE_PATH__ = route.modulePath;
|
|
15856
16411
|
req.__FARM_ROUTE__ = pathname;
|
|
15857
16412
|
req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
|
|
15858
16413
|
req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
|
|
16414
|
+
req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
|
|
15859
16415
|
req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
|
|
15860
16416
|
loadingBoundaryEntry.modulePath.indexOf("/src/app/")
|
|
15861
16417
|
) : null;
|
|
16418
|
+
req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
|
|
16419
|
+
name: slot.name,
|
|
16420
|
+
ownerPattern: slot.ownerPattern,
|
|
16421
|
+
containerId: slot.containerId,
|
|
16422
|
+
interception: slot.interception,
|
|
16423
|
+
fallback: slot.fallback,
|
|
16424
|
+
modulePath: slot.route.modulePath,
|
|
16425
|
+
isClientComponent: slot.isClientComponent,
|
|
16426
|
+
shouldHydrate: slot.shouldHydrate,
|
|
16427
|
+
props: {
|
|
16428
|
+
params: slot.props.params,
|
|
16429
|
+
search: slot.props.search,
|
|
16430
|
+
searchParams: slot.props.search,
|
|
16431
|
+
..."data" in slot.props ? { data: slot.props.data } : {},
|
|
16432
|
+
...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
|
|
16433
|
+
...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
16434
|
+
path: pathname
|
|
16435
|
+
}
|
|
16436
|
+
}));
|
|
15862
16437
|
req.__FARM_PROPS__ = {
|
|
15863
16438
|
params: pageProps.params,
|
|
15864
16439
|
search: pageProps.search,
|
|
@@ -15918,12 +16493,32 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15918
16493
|
let wrappedElement = pageElement;
|
|
15919
16494
|
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
15920
16495
|
const layoutModule = layoutModules[i];
|
|
16496
|
+
const layoutEntry = layouts[i];
|
|
15921
16497
|
const LayoutComponent = layoutModule.default;
|
|
16498
|
+
const slotProps = {};
|
|
16499
|
+
for (const slot of renderedRouteSlots) {
|
|
16500
|
+
if (slot.ownerPattern !== layoutEntry.pattern) continue;
|
|
16501
|
+
let slotElement = import_react4.default.createElement(
|
|
16502
|
+
slot.module.default,
|
|
16503
|
+
slot.props
|
|
16504
|
+
);
|
|
16505
|
+
slotElement = import_react4.default.createElement(
|
|
16506
|
+
"div",
|
|
16507
|
+
{
|
|
16508
|
+
id: slot.containerId,
|
|
16509
|
+
"data-farm-route-slot": slot.name,
|
|
16510
|
+
"data-farm-slot-owner": slot.ownerPattern
|
|
16511
|
+
},
|
|
16512
|
+
slotElement
|
|
16513
|
+
);
|
|
16514
|
+
slotProps[slot.name] = slotElement;
|
|
16515
|
+
}
|
|
15922
16516
|
wrappedElement = import_react4.default.createElement(
|
|
15923
16517
|
LayoutComponent,
|
|
15924
16518
|
{
|
|
15925
16519
|
children: wrappedElement,
|
|
15926
|
-
params
|
|
16520
|
+
params,
|
|
16521
|
+
...slotProps
|
|
15927
16522
|
}
|
|
15928
16523
|
);
|
|
15929
16524
|
}
|
|
@@ -15960,7 +16555,10 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15960
16555
|
routeManifest,
|
|
15961
16556
|
captureStaticShell: Boolean(pprShellOptions),
|
|
15962
16557
|
observabilityRoute: pathname,
|
|
15963
|
-
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16558
|
+
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16559
|
+
type: "ppr.suspense.holeDetected",
|
|
16560
|
+
route: pathname
|
|
16561
|
+
}) : void 0,
|
|
15964
16562
|
onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
|
|
15965
16563
|
}
|
|
15966
16564
|
);
|
|
@@ -16008,7 +16606,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16008
16606
|
}
|
|
16009
16607
|
emitFarmEvent({ type: "render.error", route: pathname, error });
|
|
16010
16608
|
if (pprRefreshRoute) {
|
|
16011
|
-
emitFarmEvent({
|
|
16609
|
+
emitFarmEvent({
|
|
16610
|
+
type: "ppr.refresh.error",
|
|
16611
|
+
route: pprRefreshRoute,
|
|
16612
|
+
error
|
|
16613
|
+
});
|
|
16012
16614
|
}
|
|
16013
16615
|
logger.error(`Error rendering page: ${error}`);
|
|
16014
16616
|
if (res.headersSent || res.writableEnded) {
|
|
@@ -16061,7 +16663,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16061
16663
|
if (typeof layoutModule.generateMetadata === "function") {
|
|
16062
16664
|
metadata = mergeMetadata(
|
|
16063
16665
|
metadata,
|
|
16064
|
-
await layoutModule.generateMetadata({
|
|
16666
|
+
await layoutModule.generateMetadata({
|
|
16667
|
+
params: options.pageProps.params
|
|
16668
|
+
})
|
|
16065
16669
|
);
|
|
16066
16670
|
}
|
|
16067
16671
|
}
|
|
@@ -16292,7 +16896,13 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16292
16896
|
clientEntry: "/@farm/client.js",
|
|
16293
16897
|
routes: {},
|
|
16294
16898
|
layouts: {},
|
|
16295
|
-
|
|
16899
|
+
slots: [],
|
|
16900
|
+
sharedAssets: [
|
|
16901
|
+
{
|
|
16902
|
+
tag: "link",
|
|
16903
|
+
attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
|
|
16904
|
+
}
|
|
16905
|
+
]
|
|
16296
16906
|
};
|
|
16297
16907
|
for (const routeEntry of manifest.routes) {
|
|
16298
16908
|
clientManifest.routes[routeEntry.pattern] = {
|
|
@@ -16314,9 +16924,26 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16314
16924
|
assets: []
|
|
16315
16925
|
};
|
|
16316
16926
|
}
|
|
16317
|
-
const
|
|
16927
|
+
for (const slotEntry of manifest.slots ?? []) {
|
|
16928
|
+
clientManifest.slots.push({
|
|
16929
|
+
...slotEntry,
|
|
16930
|
+
preloads: [slotEntry.modulePath],
|
|
16931
|
+
assets: []
|
|
16932
|
+
});
|
|
16933
|
+
}
|
|
16934
|
+
const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
|
|
16935
|
+
(slot) => ({
|
|
16936
|
+
...slot,
|
|
16937
|
+
modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
|
|
16938
|
+
})
|
|
16939
|
+
);
|
|
16940
|
+
const deferredProps = prepareDeferredData({
|
|
16941
|
+
page: req.__FARM_PROPS__ || {},
|
|
16942
|
+
slots: routeSlotPayload
|
|
16943
|
+
});
|
|
16318
16944
|
const propsScript = `<script>
|
|
16319
|
-
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
|
|
16945
|
+
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
|
|
16946
|
+
window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
|
|
16320
16947
|
window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
|
|
16321
16948
|
window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
|
|
16322
16949
|
window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
|
|
@@ -16329,7 +16956,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
|
|
|
16329
16956
|
window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
|
|
16330
16957
|
${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
|
|
16331
16958
|
</script>`;
|
|
16332
|
-
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
|
|
16959
|
+
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
|
|
16333
16960
|
const {
|
|
16334
16961
|
title,
|
|
16335
16962
|
tags: metaTags,
|
|
@@ -16440,7 +17067,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16440
17067
|
didError = true;
|
|
16441
17068
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16442
17069
|
logger.error(`SSR shell error: ${error}`);
|
|
16443
|
-
emitFarmEvent({
|
|
17070
|
+
emitFarmEvent({
|
|
17071
|
+
type: "render.error",
|
|
17072
|
+
route: observabilityRoute,
|
|
17073
|
+
error
|
|
17074
|
+
});
|
|
16444
17075
|
}
|
|
16445
17076
|
if (clearMiddlewareData) {
|
|
16446
17077
|
clearMiddlewareData();
|
|
@@ -16451,7 +17082,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16451
17082
|
didError = true;
|
|
16452
17083
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16453
17084
|
logger.error(`SSR streaming error: ${error}`);
|
|
16454
|
-
emitFarmEvent({
|
|
17085
|
+
emitFarmEvent({
|
|
17086
|
+
type: "render.error",
|
|
17087
|
+
route: observabilityRoute,
|
|
17088
|
+
error
|
|
17089
|
+
});
|
|
16455
17090
|
}
|
|
16456
17091
|
}
|
|
16457
17092
|
});
|
|
@@ -16620,17 +17255,14 @@ var _FarmApp = class _FarmApp {
|
|
|
16620
17255
|
_setDefaultFarmI18nRuntime(this.i18nRuntime);
|
|
16621
17256
|
this.viteServer = viteServer;
|
|
16622
17257
|
this.routeManager = new RouteManager(this.config, viteServer);
|
|
16623
|
-
this.serverRenderer = new ServerRenderer(
|
|
16624
|
-
this.config,
|
|
16625
|
-
this.routeManager,
|
|
16626
|
-
this.i18nRuntime
|
|
16627
|
-
);
|
|
17258
|
+
this.serverRenderer = new ServerRenderer(this.config, this.routeManager, this.i18nRuntime);
|
|
16628
17259
|
}
|
|
16629
17260
|
async initialize() {
|
|
16630
17261
|
if (process.env.FARM_VERBOSE) {
|
|
16631
17262
|
logger.info("Initializing Farm.js application...");
|
|
16632
17263
|
}
|
|
16633
17264
|
await initStorage(this.config.storage);
|
|
17265
|
+
await configureFarmCache(this.config.cache);
|
|
16634
17266
|
await this.i18nRuntime.initialize();
|
|
16635
17267
|
await this.verifyAppStructure();
|
|
16636
17268
|
await this.routeManager.discoverRoutes();
|
|
@@ -16662,6 +17294,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16662
17294
|
preset: config.preset ?? "node-server",
|
|
16663
17295
|
deploy: config.deploy || {},
|
|
16664
17296
|
storage: config.storage || {},
|
|
17297
|
+
cache: config.cache || {},
|
|
16665
17298
|
integrations: config.integrations || {},
|
|
16666
17299
|
plugins: config.plugins || [],
|
|
16667
17300
|
migrations: config.migrations || { commands: [] },
|
|
@@ -17069,6 +17702,29 @@ var fs3 = __toESM(require("fs"));
|
|
|
17069
17702
|
var path10 = __toESM(require("path"));
|
|
17070
17703
|
init_route_runtime();
|
|
17071
17704
|
|
|
17705
|
+
// src/api/runtime.ts
|
|
17706
|
+
init_cache_invalidation();
|
|
17707
|
+
|
|
17708
|
+
// src/api/endpoint.ts
|
|
17709
|
+
var import_better_call = require("better-call");
|
|
17710
|
+
var _EndpointFailure = class _EndpointFailure extends Error {
|
|
17711
|
+
constructor(code, data, options) {
|
|
17712
|
+
super(options.message);
|
|
17713
|
+
this.name = "EndpointFailure";
|
|
17714
|
+
this.code = code;
|
|
17715
|
+
this.data = data;
|
|
17716
|
+
this.status = options.status;
|
|
17717
|
+
}
|
|
17718
|
+
};
|
|
17719
|
+
__name(_EndpointFailure, "EndpointFailure");
|
|
17720
|
+
var EndpointFailure = _EndpointFailure;
|
|
17721
|
+
function isEndpointFailure(value) {
|
|
17722
|
+
return value instanceof EndpointFailure;
|
|
17723
|
+
}
|
|
17724
|
+
__name(isEndpointFailure, "isEndpointFailure");
|
|
17725
|
+
var EMPTY_ENDPOINT_MIDDLEWARE = Object.freeze([]);
|
|
17726
|
+
var EMPTY_ENDPOINT_CONTEXT = Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
17727
|
+
|
|
17072
17728
|
// src/api/runtime.ts
|
|
17073
17729
|
function matchAPIRoute(routes, pathname) {
|
|
17074
17730
|
const exactRoute = routes.get(pathname);
|
|
@@ -17101,10 +17757,10 @@ __name(invokeAPIRouteEndpoint, "invokeAPIRouteEndpoint");
|
|
|
17101
17757
|
async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
17102
17758
|
const farmHandler = endpoint.__handler || (isFarmContextHandler(endpoint) ? endpoint : null);
|
|
17103
17759
|
if (!farmHandler) {
|
|
17104
|
-
const
|
|
17760
|
+
const result = await endpoint(request, {
|
|
17105
17761
|
params: Promise.resolve(params)
|
|
17106
17762
|
});
|
|
17107
|
-
return normalizeRouteResponse(
|
|
17763
|
+
return normalizeRouteResponse(result);
|
|
17108
17764
|
}
|
|
17109
17765
|
const url = new URL(request.url);
|
|
17110
17766
|
const query = {};
|
|
@@ -17113,7 +17769,7 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
17113
17769
|
});
|
|
17114
17770
|
let body = void 0;
|
|
17115
17771
|
if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
|
|
17116
|
-
body = await
|
|
17772
|
+
body = await readRequestBody(request);
|
|
17117
17773
|
}
|
|
17118
17774
|
const headers = Object.fromEntries(request.headers.entries());
|
|
17119
17775
|
const types = endpoint.__types || {};
|
|
@@ -17129,15 +17785,30 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
17129
17785
|
if (headersValidation instanceof Response) {
|
|
17130
17786
|
return headersValidation;
|
|
17131
17787
|
}
|
|
17132
|
-
const
|
|
17788
|
+
const handlerContext = {
|
|
17133
17789
|
query: queryValidation,
|
|
17134
17790
|
body: bodyValidation,
|
|
17135
17791
|
headers: headersValidation,
|
|
17136
17792
|
request,
|
|
17137
17793
|
context: {},
|
|
17138
17794
|
params
|
|
17139
|
-
}
|
|
17140
|
-
|
|
17795
|
+
};
|
|
17796
|
+
let execution;
|
|
17797
|
+
try {
|
|
17798
|
+
execution = typeof endpoint.__farmInvoke === "function" ? await endpoint.__farmInvoke(handlerContext) : {
|
|
17799
|
+
result: await farmHandler(handlerContext),
|
|
17800
|
+
context: handlerContext.context,
|
|
17801
|
+
handlerExecuted: true,
|
|
17802
|
+
invalidations: []
|
|
17803
|
+
};
|
|
17804
|
+
} catch (error) {
|
|
17805
|
+
if (isEndpointFailure(error)) {
|
|
17806
|
+
return createEndpointFailureResponse(error);
|
|
17807
|
+
}
|
|
17808
|
+
throw error;
|
|
17809
|
+
}
|
|
17810
|
+
const response = normalizeRouteResponse(execution.result);
|
|
17811
|
+
return attachEndpointInvalidations(response, execution.invalidations);
|
|
17141
17812
|
}
|
|
17142
17813
|
__name(invokeAPIRouteEndpointInContext, "invokeAPIRouteEndpointInContext");
|
|
17143
17814
|
function normalizeRouteResponse(result) {
|
|
@@ -17157,6 +17828,40 @@ function isWebResponse2(value) {
|
|
|
17157
17828
|
return value instanceof Response || typeof value === "object" && value !== null && "headers" in value && "status" in value && typeof value.arrayBuffer === "function";
|
|
17158
17829
|
}
|
|
17159
17830
|
__name(isWebResponse2, "isWebResponse");
|
|
17831
|
+
function attachEndpointInvalidations(response, keys) {
|
|
17832
|
+
const existing = decodeFarmCacheInvalidations(
|
|
17833
|
+
response.headers.get(FARM_CACHE_INVALIDATION_HEADER)
|
|
17834
|
+
);
|
|
17835
|
+
const encoded = encodeFarmCacheInvalidations([...existing, ...keys]);
|
|
17836
|
+
if (!encoded) return response;
|
|
17837
|
+
const headers = new Headers(response.headers);
|
|
17838
|
+
headers.set(FARM_CACHE_INVALIDATION_HEADER, encoded);
|
|
17839
|
+
return new Response(response.body, {
|
|
17840
|
+
status: response.status,
|
|
17841
|
+
statusText: response.statusText,
|
|
17842
|
+
headers
|
|
17843
|
+
});
|
|
17844
|
+
}
|
|
17845
|
+
__name(attachEndpointInvalidations, "attachEndpointInvalidations");
|
|
17846
|
+
function createEndpointFailureResponse(failure) {
|
|
17847
|
+
return new Response(
|
|
17848
|
+
JSON.stringify({
|
|
17849
|
+
error: {
|
|
17850
|
+
code: failure.code,
|
|
17851
|
+
message: failure.message,
|
|
17852
|
+
data: failure.data
|
|
17853
|
+
}
|
|
17854
|
+
}),
|
|
17855
|
+
{
|
|
17856
|
+
status: failure.status,
|
|
17857
|
+
headers: {
|
|
17858
|
+
"cache-control": "no-store",
|
|
17859
|
+
"content-type": "application/json"
|
|
17860
|
+
}
|
|
17861
|
+
}
|
|
17862
|
+
);
|
|
17863
|
+
}
|
|
17864
|
+
__name(createEndpointFailureResponse, "createEndpointFailureResponse");
|
|
17160
17865
|
function isFarmContextHandler(endpoint) {
|
|
17161
17866
|
if (typeof endpoint !== "function") {
|
|
17162
17867
|
return false;
|
|
@@ -17168,17 +17873,50 @@ function isFarmContextHandler(endpoint) {
|
|
|
17168
17873
|
return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
|
|
17169
17874
|
}
|
|
17170
17875
|
__name(isFarmContextHandler, "isFarmContextHandler");
|
|
17171
|
-
async function
|
|
17876
|
+
async function readRequestBody(request) {
|
|
17877
|
+
const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
17172
17878
|
try {
|
|
17879
|
+
if (contentType === "multipart/form-data") {
|
|
17880
|
+
return formDataToObject(await request.clone().formData());
|
|
17881
|
+
}
|
|
17173
17882
|
const text2 = await request.clone().text();
|
|
17174
|
-
if (text2)
|
|
17883
|
+
if (!text2) return void 0;
|
|
17884
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
17885
|
+
return searchParamsToObject2(new URLSearchParams(text2));
|
|
17886
|
+
}
|
|
17887
|
+
if (contentType === "application/json" || contentType?.endsWith("+json")) {
|
|
17175
17888
|
return JSON.parse(text2);
|
|
17176
17889
|
}
|
|
17890
|
+
return JSON.parse(text2);
|
|
17177
17891
|
} catch {
|
|
17178
17892
|
}
|
|
17179
17893
|
return void 0;
|
|
17180
17894
|
}
|
|
17181
|
-
__name(
|
|
17895
|
+
__name(readRequestBody, "readRequestBody");
|
|
17896
|
+
function formDataToObject(formData) {
|
|
17897
|
+
return entriesToObject(formData.entries());
|
|
17898
|
+
}
|
|
17899
|
+
__name(formDataToObject, "formDataToObject");
|
|
17900
|
+
function searchParamsToObject2(searchParams) {
|
|
17901
|
+
return entriesToObject(searchParams.entries());
|
|
17902
|
+
}
|
|
17903
|
+
__name(searchParamsToObject2, "searchParamsToObject");
|
|
17904
|
+
function entriesToObject(entries) {
|
|
17905
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
17906
|
+
for (const [key, value] of entries) {
|
|
17907
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
17908
|
+
const current = output[key];
|
|
17909
|
+
if (current === void 0) {
|
|
17910
|
+
output[key] = value;
|
|
17911
|
+
} else if (Array.isArray(current)) {
|
|
17912
|
+
current.push(value);
|
|
17913
|
+
} else {
|
|
17914
|
+
output[key] = [current, value];
|
|
17915
|
+
}
|
|
17916
|
+
}
|
|
17917
|
+
return output;
|
|
17918
|
+
}
|
|
17919
|
+
__name(entriesToObject, "entriesToObject");
|
|
17182
17920
|
function validateInput(schema, value, error) {
|
|
17183
17921
|
if (!schema || typeof schema.parse !== "function") {
|
|
17184
17922
|
return value;
|
|
@@ -18185,7 +18923,7 @@ var _MiddlewareManager = class _MiddlewareManager {
|
|
|
18185
18923
|
if (!nestedMatch.matched) {
|
|
18186
18924
|
return { matched: false };
|
|
18187
18925
|
}
|
|
18188
|
-
const params = { ...nestedMatch.params
|
|
18926
|
+
const params = { ...nestedMatch.params };
|
|
18189
18927
|
delete params.__farmRest;
|
|
18190
18928
|
return {
|
|
18191
18929
|
matched: true,
|
|
@@ -18333,6 +19071,7 @@ async function generateRouteTypes(options) {
|
|
|
18333
19071
|
absolute: false
|
|
18334
19072
|
});
|
|
18335
19073
|
for (const file of pageFiles) {
|
|
19074
|
+
if (parseRouteSlotFile(file)) continue;
|
|
18336
19075
|
const route = parseRoutePath(file);
|
|
18337
19076
|
if (route.type === "page") {
|
|
18338
19077
|
const pattern = createRoutePattern(route);
|
|
@@ -19067,6 +19806,12 @@ function transformError(id, message) {
|
|
|
19067
19806
|
}
|
|
19068
19807
|
__name(transformError, "transformError");
|
|
19069
19808
|
|
|
19809
|
+
// package.json
|
|
19810
|
+
var version = "0.1.0-beta.4";
|
|
19811
|
+
|
|
19812
|
+
// src/version.ts
|
|
19813
|
+
var FARM_VERSION = version;
|
|
19814
|
+
|
|
19070
19815
|
// src/after.ts
|
|
19071
19816
|
var import_node_async_hooks4 = require("async_hooks");
|
|
19072
19817
|
var AFTER_STORAGE = /* @__PURE__ */ Symbol.for("@farm.js/core/after-storage");
|
|
@@ -19447,7 +20192,7 @@ function isResolvedEnvScope(value) {
|
|
|
19447
20192
|
}
|
|
19448
20193
|
__name(isResolvedEnvScope, "isResolvedEnvScope");
|
|
19449
20194
|
function isPotentialProgrammaticRouteSourceFile(normalizedFile, srcDirSlug) {
|
|
19450
|
-
return normalizedFile.startsWith(`${srcDirSlug}/`) && /\.(ts|tsx|js|jsx)$/.test(normalizedFile) &&
|
|
20195
|
+
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");
|
|
19451
20196
|
}
|
|
19452
20197
|
__name(isPotentialProgrammaticRouteSourceFile, "isPotentialProgrammaticRouteSourceFile");
|
|
19453
20198
|
function fileContainsProgrammaticPageRoute(file) {
|
|
@@ -19690,7 +20435,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19690
20435
|
}, "isProgrammaticRouteSourceFile");
|
|
19691
20436
|
const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
|
|
19692
20437
|
const normalized = file.replace(/\\/g, "/");
|
|
19693
|
-
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(
|
|
20438
|
+
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(
|
|
19694
20439
|
normalized
|
|
19695
20440
|
);
|
|
19696
20441
|
}, "isAppRuntimeFile");
|
|
@@ -20381,7 +21126,10 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20381
21126
|
method: req.method || "GET"
|
|
20382
21127
|
});
|
|
20383
21128
|
}
|
|
20384
|
-
const
|
|
21129
|
+
const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
|
|
21130
|
+
const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
|
|
21131
|
+
interceptFrom: interceptFromHeader
|
|
21132
|
+
});
|
|
20385
21133
|
if (pm) {
|
|
20386
21134
|
await pm.runHookParallel("afterRouteMatch", {
|
|
20387
21135
|
pathname: targetPath,
|
|
@@ -20397,7 +21145,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20397
21145
|
res.end(JSON.stringify({ error: "Route not found" }));
|
|
20398
21146
|
return;
|
|
20399
21147
|
}
|
|
20400
|
-
const { route, params, layouts } = match;
|
|
21148
|
+
const { route, params, layouts, slots } = match;
|
|
20401
21149
|
if (!route) {
|
|
20402
21150
|
res.statusCode = 404;
|
|
20403
21151
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -20452,6 +21200,54 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20452
21200
|
search: searchParams,
|
|
20453
21201
|
routePath: route.pattern
|
|
20454
21202
|
});
|
|
21203
|
+
const routeSlots = await Promise.all(
|
|
21204
|
+
slots.map(async (slot) => {
|
|
21205
|
+
const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
|
|
21206
|
+
const slotMetadata = getClientModuleMetadata(
|
|
21207
|
+
slot.route.modulePath,
|
|
21208
|
+
server.config.root
|
|
21209
|
+
);
|
|
21210
|
+
const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
|
|
21211
|
+
request,
|
|
21212
|
+
params: slot.params,
|
|
21213
|
+
search: searchParams,
|
|
21214
|
+
path: targetUrl.pathname
|
|
21215
|
+
});
|
|
21216
|
+
const slotProps = await parseRouteModuleProps2(slotModule, {
|
|
21217
|
+
props: withFarmRouteContext(
|
|
21218
|
+
{
|
|
21219
|
+
params: slot.params,
|
|
21220
|
+
searchParams: Promise.resolve(searchParams),
|
|
21221
|
+
path: targetUrl.pathname
|
|
21222
|
+
},
|
|
21223
|
+
slotContext
|
|
21224
|
+
),
|
|
21225
|
+
search: searchParams,
|
|
21226
|
+
routePath: slot.route.pattern
|
|
21227
|
+
});
|
|
21228
|
+
return {
|
|
21229
|
+
name: slot.name,
|
|
21230
|
+
ownerPattern: slot.ownerPattern,
|
|
21231
|
+
containerId: slot.containerId,
|
|
21232
|
+
interception: slot.interception,
|
|
21233
|
+
fallback: slot.fallback,
|
|
21234
|
+
modulePath: slot.route.modulePath,
|
|
21235
|
+
isClientComponent: slotMetadata.isClientComponent,
|
|
21236
|
+
shouldHydrate: slotMetadata.shouldHydrate,
|
|
21237
|
+
props: {
|
|
21238
|
+
params: slotProps.params,
|
|
21239
|
+
search: slotProps.search,
|
|
21240
|
+
searchParams: slotProps.search,
|
|
21241
|
+
..."data" in slotProps ? { data: slotProps.data } : {},
|
|
21242
|
+
...slotProps.__farmCanonicalPath ? {
|
|
21243
|
+
__farmCanonicalPath: slotProps.__farmCanonicalPath
|
|
21244
|
+
} : {},
|
|
21245
|
+
...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
21246
|
+
path: targetUrl.pathname
|
|
21247
|
+
}
|
|
21248
|
+
};
|
|
21249
|
+
})
|
|
21250
|
+
);
|
|
20455
21251
|
const projectRoot = server.config.root;
|
|
20456
21252
|
const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
|
|
20457
21253
|
if (absolutePath.startsWith(projectRoot)) {
|
|
@@ -20472,13 +21268,21 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20472
21268
|
},
|
|
20473
21269
|
canonicalPath: routeProps.__farmCanonicalPath,
|
|
20474
21270
|
modulePath: toUrlPath(route.modulePath),
|
|
20475
|
-
isClientComponent,
|
|
20476
|
-
shouldHydrate,
|
|
21271
|
+
isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
|
|
21272
|
+
shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
|
|
20477
21273
|
metadata: {
|
|
20478
21274
|
title: mergedMetadata.title,
|
|
20479
21275
|
description: mergedMetadata.description
|
|
20480
21276
|
},
|
|
20481
21277
|
layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
|
|
21278
|
+
routeSlots: routeSlots.map((slot) => ({
|
|
21279
|
+
...slot,
|
|
21280
|
+
modulePath: toUrlPath(slot.modulePath)
|
|
21281
|
+
})),
|
|
21282
|
+
interception: routeSlots.some((slot) => slot.interception) ? {
|
|
21283
|
+
from: interceptFromHeader,
|
|
21284
|
+
slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
|
|
21285
|
+
} : void 0,
|
|
20482
21286
|
i18n: getFarmI18nClientSnapshot()
|
|
20483
21287
|
};
|
|
20484
21288
|
await sendWebResponse(
|
|
@@ -20814,6 +21618,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20814
21618
|
export const getManifest = () => ({
|
|
20815
21619
|
routes: {},
|
|
20816
21620
|
layouts: {},
|
|
21621
|
+
slots: [],
|
|
20817
21622
|
clientEntry: "/@farm/client.js",
|
|
20818
21623
|
sharedAssets: []
|
|
20819
21624
|
});
|
|
@@ -20824,6 +21629,7 @@ export const getManifest = () => ({
|
|
|
20824
21629
|
clientEntry: "/@farm/client.js",
|
|
20825
21630
|
routes: {},
|
|
20826
21631
|
layouts: {},
|
|
21632
|
+
slots: [],
|
|
20827
21633
|
sharedAssets: [
|
|
20828
21634
|
{
|
|
20829
21635
|
tag: "link",
|
|
@@ -20853,6 +21659,13 @@ export const getManifest = () => ({
|
|
|
20853
21659
|
assets: []
|
|
20854
21660
|
};
|
|
20855
21661
|
}
|
|
21662
|
+
for (const slot of manifest.slots) {
|
|
21663
|
+
fullManifest.slots.push({
|
|
21664
|
+
...slot,
|
|
21665
|
+
preloads: [slot.modulePath],
|
|
21666
|
+
assets: []
|
|
21667
|
+
});
|
|
21668
|
+
}
|
|
20856
21669
|
return `
|
|
20857
21670
|
// Auto-generated manifest for SPA navigation (TanStack Start pattern)
|
|
20858
21671
|
// This manifest is inlined in the server bundle - no file on disk
|
|
@@ -21495,7 +22308,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
|
|
|
21495
22308
|
|
|
21496
22309
|
// Get manifest from window (inlined by server in HTML)
|
|
21497
22310
|
// Fallback to empty manifest if not available yet
|
|
21498
|
-
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
|
|
22311
|
+
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
|
|
21499
22312
|
|
|
21500
22313
|
// ====== CLIENT-SIDE ROUTE MATCHING ======
|
|
21501
22314
|
// Matches URL to route using manifest (no server request!)
|
|
@@ -21834,6 +22647,9 @@ let LayoutComponent = null;
|
|
|
21834
22647
|
|
|
21835
22648
|
// Track if we've taken over rendering from SSR
|
|
21836
22649
|
let hasClientTakenOver = false;
|
|
22650
|
+
const routeSlotRoots = new Map();
|
|
22651
|
+
const routeSlotDefinitions = new Map();
|
|
22652
|
+
let activeRouteInterception = null;
|
|
21837
22653
|
|
|
21838
22654
|
function normalizeServerProps(rawProps) {
|
|
21839
22655
|
const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
|
|
@@ -21846,6 +22662,123 @@ function normalizeServerProps(rawProps) {
|
|
|
21846
22662
|
return props;
|
|
21847
22663
|
}
|
|
21848
22664
|
|
|
22665
|
+
function getRouteSlotKey(slot) {
|
|
22666
|
+
return slot.ownerPattern + ':' + slot.name;
|
|
22667
|
+
}
|
|
22668
|
+
|
|
22669
|
+
async function renderRouteSlot(slot, mode = 'render') {
|
|
22670
|
+
const container = document.getElementById(slot.containerId);
|
|
22671
|
+
if (!container || !slot.modulePath) return false;
|
|
22672
|
+
if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
|
|
22673
|
+
return false;
|
|
22674
|
+
}
|
|
22675
|
+
|
|
22676
|
+
let slotModule = pageModuleCache.get(slot.modulePath);
|
|
22677
|
+
if (!slotModule) {
|
|
22678
|
+
slotModule = await import(/* @vite-ignore */ slot.modulePath);
|
|
22679
|
+
pageModuleCache.set(slot.modulePath, slotModule);
|
|
22680
|
+
}
|
|
22681
|
+
const SlotComponent = slotModule?.default;
|
|
22682
|
+
if (!SlotComponent) return false;
|
|
22683
|
+
|
|
22684
|
+
const props = reviveDeferredData(
|
|
22685
|
+
normalizeServerProps(slot.props || {}),
|
|
22686
|
+
window.__FARM_DEFERRED_DATA__ || {},
|
|
22687
|
+
);
|
|
22688
|
+
const element = wrapWithIntegrationProviders(
|
|
22689
|
+
React.createElement(SlotComponent, props),
|
|
22690
|
+
);
|
|
22691
|
+
const key = getRouteSlotKey(slot);
|
|
22692
|
+
const existingRoot = routeSlotRoots.get(key);
|
|
22693
|
+
|
|
22694
|
+
if (mode === 'hydrate') {
|
|
22695
|
+
if (existingRoot) return true;
|
|
22696
|
+
const root = hydrateRoot(container, element);
|
|
22697
|
+
routeSlotRoots.set(key, root);
|
|
22698
|
+
} else {
|
|
22699
|
+
if (existingRoot) {
|
|
22700
|
+
try { existingRoot.unmount(); } catch (error) {}
|
|
22701
|
+
}
|
|
22702
|
+
const root = createRoot(container);
|
|
22703
|
+
root.render(element);
|
|
22704
|
+
routeSlotRoots.set(key, root);
|
|
22705
|
+
}
|
|
22706
|
+
|
|
22707
|
+
routeSlotDefinitions.set(key, slot);
|
|
22708
|
+
return true;
|
|
22709
|
+
}
|
|
22710
|
+
|
|
22711
|
+
async function hydrateInitialRouteSlots() {
|
|
22712
|
+
const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
|
|
22713
|
+
? window.__FARM_ROUTE_SLOTS__
|
|
22714
|
+
: [];
|
|
22715
|
+
let hydrated = false;
|
|
22716
|
+
|
|
22717
|
+
for (const slot of slots) {
|
|
22718
|
+
routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
|
|
22719
|
+
if (!slot.isClientComponent && !slot.shouldHydrate) continue;
|
|
22720
|
+
try {
|
|
22721
|
+
hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
|
|
22722
|
+
} catch (error) {
|
|
22723
|
+
console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
|
|
22724
|
+
}
|
|
22725
|
+
}
|
|
22726
|
+
|
|
22727
|
+
return hydrated;
|
|
22728
|
+
}
|
|
22729
|
+
|
|
22730
|
+
async function renderRouteInterception(pageData) {
|
|
22731
|
+
const slots = Array.isArray(pageData.routeSlots)
|
|
22732
|
+
? pageData.routeSlots.filter((slot) => slot.interception)
|
|
22733
|
+
: [];
|
|
22734
|
+
if (!pageData.interception || slots.length === 0) return false;
|
|
22735
|
+
|
|
22736
|
+
const previous = new Map();
|
|
22737
|
+
for (const slot of slots) {
|
|
22738
|
+
const key = getRouteSlotKey(slot);
|
|
22739
|
+
previous.set(key, routeSlotDefinitions.get(key) || null);
|
|
22740
|
+
if (!(await renderRouteSlot(slot, 'intercept'))) {
|
|
22741
|
+
return false;
|
|
22742
|
+
}
|
|
22743
|
+
}
|
|
22744
|
+
|
|
22745
|
+
activeRouteInterception = {
|
|
22746
|
+
from: pageData.interception.from,
|
|
22747
|
+
slots,
|
|
22748
|
+
previous,
|
|
22749
|
+
};
|
|
22750
|
+
return true;
|
|
22751
|
+
}
|
|
22752
|
+
|
|
22753
|
+
async function clearRouteInterception(destination) {
|
|
22754
|
+
if (!activeRouteInterception) return false;
|
|
22755
|
+
const active = activeRouteInterception;
|
|
22756
|
+
activeRouteInterception = null;
|
|
22757
|
+
|
|
22758
|
+
for (const slot of active.slots) {
|
|
22759
|
+
const key = getRouteSlotKey(slot);
|
|
22760
|
+
const root = routeSlotRoots.get(key);
|
|
22761
|
+
if (root) {
|
|
22762
|
+
try { root.unmount(); } catch (error) {}
|
|
22763
|
+
routeSlotRoots.delete(key);
|
|
22764
|
+
}
|
|
22765
|
+
|
|
22766
|
+
const previous = active.previous.get(key);
|
|
22767
|
+
if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
|
|
22768
|
+
await renderRouteSlot(previous, 'render');
|
|
22769
|
+
} else {
|
|
22770
|
+
const container = document.getElementById(slot.containerId);
|
|
22771
|
+
if (container) container.replaceChildren();
|
|
22772
|
+
if (previous) routeSlotDefinitions.set(key, previous);
|
|
22773
|
+
else routeSlotDefinitions.delete(key);
|
|
22774
|
+
}
|
|
22775
|
+
}
|
|
22776
|
+
|
|
22777
|
+
if (!active.from) return false;
|
|
22778
|
+
const background = new URL(active.from, window.location.origin);
|
|
22779
|
+
return destination === background.pathname + background.search;
|
|
22780
|
+
}
|
|
22781
|
+
|
|
21849
22782
|
function applyCanonicalPathFromProps(props) {
|
|
21850
22783
|
const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
|
|
21851
22784
|
? props.__farmCanonicalPath
|
|
@@ -22080,6 +23013,17 @@ async function tryHydrateImportedPage(
|
|
|
22080
23013
|
async function renderPage(pageData) {
|
|
22081
23014
|
const container = document.getElementById('root');
|
|
22082
23015
|
if (!container) return;
|
|
23016
|
+
const destination = window.location.pathname + window.location.search;
|
|
23017
|
+
|
|
23018
|
+
if (pageData.interception) {
|
|
23019
|
+
if (await renderRouteInterception(pageData)) return;
|
|
23020
|
+
window.location.assign(destination);
|
|
23021
|
+
return;
|
|
23022
|
+
}
|
|
23023
|
+
|
|
23024
|
+
if (await clearRouteInterception(destination)) {
|
|
23025
|
+
return;
|
|
23026
|
+
}
|
|
22083
23027
|
|
|
22084
23028
|
const route = {
|
|
22085
23029
|
modulePath: pageData.modulePath,
|
|
@@ -22308,7 +23252,9 @@ async function hydrate() {
|
|
|
22308
23252
|
window.__FARM_SHOULD_HYDRATE__ === true ||
|
|
22309
23253
|
isClientComponent ||
|
|
22310
23254
|
await moduleLooksClient(modulePath);
|
|
23255
|
+
const hydratedSlots = await hydrateInitialRouteSlots();
|
|
22311
23256
|
if (!shouldHydrate) {
|
|
23257
|
+
if (hydratedSlots) replayPreHydrationClicks();
|
|
22312
23258
|
console.log('[Farm.js] Server component - SPA router ready')
|
|
22313
23259
|
return
|
|
22314
23260
|
}
|
|
@@ -22573,7 +23519,7 @@ async function defineConfig2(config = {}) {
|
|
|
22573
23519
|
const isExposed = hostConfig === true || hostConfig === "0.0.0.0";
|
|
22574
23520
|
console.log("");
|
|
22575
23521
|
console.log(
|
|
22576
|
-
` ${pc.bold(pc.green("Farm.js"))} ${pc.dim(
|
|
23522
|
+
` ${pc.bold(pc.green("Farm.js"))} ${pc.dim(`v${FARM_VERSION}`)} ${pc.dim(`ready in ${elapsed}ms`)}`
|
|
22577
23523
|
);
|
|
22578
23524
|
console.log("");
|
|
22579
23525
|
console.log(
|