@farm.js/core 0.1.0-beta.3 → 0.1.0-beta.5
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/dist/agent-runtime.d.mts +2 -1
- package/dist/agent-runtime.d.ts +2 -1
- package/dist/api/route-manager.cjs +313 -10
- package/dist/api/route-manager.cjs.map +1 -1
- package/dist/api/route-manager.d.mts +3 -2
- package/dist/api/route-manager.d.ts +3 -2
- package/dist/api/route-manager.mjs +6 -5
- package/dist/api/runtime.cjs +313 -10
- package/dist/api/runtime.cjs.map +1 -1
- package/dist/api/runtime.d.mts +2 -1
- package/dist/api/runtime.d.ts +2 -1
- package/dist/api/runtime.mjs +4 -3
- package/dist/api.cjs +642 -57
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.mts +3 -2
- package/dist/api.d.ts +3 -2
- package/dist/api.mjs +29 -9
- package/dist/{app-DOKxo-LH.d.ts → app-BjN-da13.d.ts} +38 -3
- package/dist/{app-BB3Iu3xh.d.mts → app-CakAr8Be.d.mts} +38 -3
- package/dist/app-markdown.d.mts +2 -1
- package/dist/app-markdown.d.ts +2 -1
- package/dist/cache.cjs +395 -12
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.d.mts +100 -6
- package/dist/cache.d.ts +100 -6
- package/dist/cache.mjs +8 -2
- package/dist/{chunk-XUBZ7JI4.mjs → chunk-2CUKEMVR.mjs} +187 -16
- package/dist/chunk-2CUKEMVR.mjs.map +1 -0
- package/dist/{chunk-OHC6VCDI.mjs → chunk-2NHCNRF6.mjs} +521 -42
- package/dist/chunk-2NHCNRF6.mjs.map +1 -0
- package/dist/{chunk-6WXJ54TC.mjs → chunk-65A7QIKI.mjs} +5 -5
- package/dist/{chunk-6WXJ54TC.mjs.map → chunk-65A7QIKI.mjs.map} +1 -1
- package/dist/{chunk-5QH4IKY3.mjs → chunk-7N62DNSO.mjs} +2 -2
- package/dist/{chunk-XJSHJN4M.mjs → chunk-A2LUXHD2.mjs} +593 -49
- package/dist/chunk-A2LUXHD2.mjs.map +1 -0
- package/dist/chunk-ALCLXXTY.mjs +187 -0
- package/dist/chunk-ALCLXXTY.mjs.map +1 -0
- package/dist/{chunk-CSU4KJJF.mjs → chunk-C2ROET2V.mjs} +2 -2
- package/dist/{chunk-JNYVN7YP.mjs → chunk-EEABSBKK.mjs} +2 -2
- package/dist/{chunk-JNYVN7YP.mjs.map → chunk-EEABSBKK.mjs.map} +1 -1
- package/dist/{chunk-BIOIOWXZ.mjs → chunk-HNIQFZKB.mjs} +2 -2
- package/dist/{chunk-MH6FKW2I.mjs → chunk-J5YWQVI5.mjs} +4 -4
- package/dist/chunk-J5YWQVI5.mjs.map +1 -0
- package/dist/{chunk-G5I34UA6.mjs → chunk-JDEOUK5V.mjs} +4 -4
- package/dist/{chunk-T543TMFY.mjs → chunk-NM3CRAAL.mjs} +3 -2
- package/dist/chunk-NM3CRAAL.mjs.map +1 -0
- package/dist/{chunk-LWMGIEJA.mjs → chunk-PFE6GMNE.mjs} +47 -37
- package/dist/chunk-PFE6GMNE.mjs.map +1 -0
- package/dist/{chunk-6VS6CKAV.mjs → chunk-QM746KUO.mjs} +8 -1
- package/dist/chunk-QM746KUO.mjs.map +1 -0
- package/dist/{chunk-5FW6PQ3J.mjs → chunk-QTZZ2ISQ.mjs} +41 -16
- package/dist/chunk-QTZZ2ISQ.mjs.map +1 -0
- package/dist/{chunk-SHRJG6OG.mjs → chunk-RBRLLZL5.mjs} +18 -3
- package/dist/chunk-RBRLLZL5.mjs.map +1 -0
- package/dist/{chunk-NRRFGX45.mjs → chunk-TQAEEJB4.mjs} +3 -3
- package/dist/{chunk-45LKHSHJ.mjs → chunk-UB5UOSHB.mjs} +24 -12
- package/dist/chunk-UB5UOSHB.mjs.map +1 -0
- package/dist/chunk-V3XURYJO.mjs +756 -0
- package/dist/chunk-V3XURYJO.mjs.map +1 -0
- package/dist/{chunk-HZYXGV4K.mjs → chunk-VY2UYN5R.mjs} +24 -4
- package/dist/chunk-VY2UYN5R.mjs.map +1 -0
- package/dist/{chunk-C33RALN7.mjs → chunk-W2CRQFF6.mjs} +79 -15
- package/dist/chunk-W2CRQFF6.mjs.map +1 -0
- package/dist/{chunk-LG3YINQN.mjs → chunk-Z5CQMP54.mjs} +3 -3
- package/dist/{client-DiViK9yK.d.mts → client-BT1mFQas.d.mts} +23 -4
- package/dist/{client-DpEBJbts.d.ts → client-Nn0q4eO4.d.ts} +23 -4
- package/dist/{client-plugins-CTnsZz_A.d.ts → client-plugins-Cw4qUGsw.d.ts} +6 -0
- package/dist/{client-plugins-Cnr0D3kk.d.mts → client-plugins-DQQ1adXM.d.mts} +6 -0
- package/dist/client-plugins.d.mts +2 -1
- package/dist/client-plugins.d.ts +2 -1
- package/dist/client.cjs +665 -82
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.mts +71 -5
- package/dist/client.d.ts +71 -5
- package/dist/client.mjs +10 -7
- package/dist/config.d.mts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/{devtools-HE4FTUDN.mjs → devtools-LVC3VB5P.mjs} +4 -4
- package/dist/docs.cjs +11 -1
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.mjs +4 -4
- package/dist/index.cjs +2113 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.d.ts +16 -16
- package/dist/index.mjs +49 -21
- 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 +1455 -90
- 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 +15 -14
- package/dist/internal/config-runtime.cjs +12 -1
- 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 +3 -3
- package/dist/internal/production-runtime.cjs +282 -6
- 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 +4 -2
- package/dist/{metadata-eoVmHoyv.d.ts → metadata-BAPg_Nmo.d.ts} +1 -1
- package/dist/{metadata-Dp8AdvsB.d.mts → metadata-_6i9oFG3.d.mts} +1 -1
- package/dist/middleware.d.mts +4 -3
- package/dist/middleware.d.ts +4 -3
- package/dist/navigation.cjs +40 -15
- package/dist/navigation.cjs.map +1 -1
- package/dist/navigation.mjs +2 -2
- package/dist/plugin.cjs +913 -53
- 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 +11 -10
- package/dist/{production-runtime-BqTnUTai.d.ts → production-runtime-BoJDc5mc.d.ts} +1 -1
- package/dist/{production-runtime-DtDdG9fc.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 +3 -3
- package/dist/{runtime-C1B7pSGT.d.mts → runtime-9nQjVM7X.d.mts} +8 -9
- package/dist/{runtime-CdPHt0bv.d.ts → runtime-DgeS2skB.d.ts} +8 -9
- 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.d.mts +1 -0
- package/dist/server-fn-client.d.ts +1 -0
- 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 +279 -8
- 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 +1086 -76
- 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 +31 -16
- package/dist/server.mjs.map +1 -1
- package/dist/testing.cjs +341 -20
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.mts +3 -2
- package/dist/testing.d.ts +3 -2
- package/dist/testing.mjs +7 -6
- 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-8USa5BiY.d.mts → utils-CHXlMDkg.d.mts} +1 -1
- package/dist/{utils-DKJb6K6G.d.ts → utils-Drsyz1Vj.d.ts} +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/vite.cjs +914 -54
- 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 +11 -10
- package/package.json +1 -1
- package/types/api.d.ts +44 -0
- package/types/client.d.ts +85 -4
- package/dist/chunk-45LKHSHJ.mjs.map +0 -1
- package/dist/chunk-5FW6PQ3J.mjs.map +0 -1
- package/dist/chunk-6VS6CKAV.mjs.map +0 -1
- package/dist/chunk-C33RALN7.mjs.map +0 -1
- package/dist/chunk-GZWT6VI5.mjs +0 -382
- package/dist/chunk-GZWT6VI5.mjs.map +0 -1
- package/dist/chunk-HZYXGV4K.mjs.map +0 -1
- package/dist/chunk-LWMGIEJA.mjs.map +0 -1
- package/dist/chunk-MH6FKW2I.mjs.map +0 -1
- package/dist/chunk-OHC6VCDI.mjs.map +0 -1
- package/dist/chunk-SHRJG6OG.mjs.map +0 -1
- package/dist/chunk-T543TMFY.mjs.map +0 -1
- package/dist/chunk-XJSHJN4M.mjs.map +0 -1
- package/dist/chunk-XUBZ7JI4.mjs.map +0 -1
- /package/dist/{chunk-5QH4IKY3.mjs.map → chunk-7N62DNSO.mjs.map} +0 -0
- /package/dist/{chunk-CSU4KJJF.mjs.map → chunk-C2ROET2V.mjs.map} +0 -0
- /package/dist/{chunk-BIOIOWXZ.mjs.map → chunk-HNIQFZKB.mjs.map} +0 -0
- /package/dist/{chunk-G5I34UA6.mjs.map → chunk-JDEOUK5V.mjs.map} +0 -0
- /package/dist/{chunk-NRRFGX45.mjs.map → chunk-TQAEEJB4.mjs.map} +0 -0
- /package/dist/{chunk-LG3YINQN.mjs.map → chunk-Z5CQMP54.mjs.map} +0 -0
- /package/dist/{devtools-HE4FTUDN.mjs.map → devtools-LVC3VB5P.mjs.map} +0 -0
package/dist/plugin.cjs
CHANGED
|
@@ -1958,7 +1958,8 @@ var init_route_rules = __esm({
|
|
|
1958
1958
|
// src/cache-invalidation.ts
|
|
1959
1959
|
function getFarmCacheInvalidationState() {
|
|
1960
1960
|
return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
|
|
1961
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1961
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1962
|
+
taskListeners: /* @__PURE__ */ new Set()
|
|
1962
1963
|
});
|
|
1963
1964
|
}
|
|
1964
1965
|
function encodeFarmCacheInvalidations(keys) {
|
|
@@ -1984,6 +1985,11 @@ function subscribeFarmCacheInvalidation(listener) {
|
|
|
1984
1985
|
state.listeners.add(listener);
|
|
1985
1986
|
return () => state.listeners.delete(listener);
|
|
1986
1987
|
}
|
|
1988
|
+
function subscribeFarmCacheTask(listener) {
|
|
1989
|
+
const state = getFarmCacheInvalidationState();
|
|
1990
|
+
state.taskListeners.add(listener);
|
|
1991
|
+
return () => state.taskListeners.delete(listener);
|
|
1992
|
+
}
|
|
1987
1993
|
var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
|
|
1988
1994
|
var init_cache_invalidation = __esm({
|
|
1989
1995
|
"src/cache-invalidation.ts"() {
|
|
@@ -1995,6 +2001,7 @@ var init_cache_invalidation = __esm({
|
|
|
1995
2001
|
__name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
|
|
1996
2002
|
__name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
|
|
1997
2003
|
__name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
|
|
2004
|
+
__name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
|
|
1998
2005
|
}
|
|
1999
2006
|
});
|
|
2000
2007
|
|
|
@@ -2098,6 +2105,9 @@ var init_server_action_security = __esm({
|
|
|
2098
2105
|
subscribeFarmCacheInvalidation((key) => {
|
|
2099
2106
|
getServerActionExecutionContext()?.invalidations.add(key);
|
|
2100
2107
|
});
|
|
2108
|
+
subscribeFarmCacheTask((task) => {
|
|
2109
|
+
getServerActionExecutionContext()?.cacheTasks.add(task);
|
|
2110
|
+
});
|
|
2101
2111
|
__name(getServerActionStorage, "getServerActionStorage");
|
|
2102
2112
|
__name(parseBodySizeLimit, "parseBodySizeLimit");
|
|
2103
2113
|
__name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
|
|
@@ -11667,11 +11677,51 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
|
|
|
11667
11677
|
// src/cache.ts
|
|
11668
11678
|
init_cache_invalidation();
|
|
11669
11679
|
var _FarmDataCache = class _FarmDataCache {
|
|
11670
|
-
constructor() {
|
|
11680
|
+
constructor(config = {}) {
|
|
11671
11681
|
this.entries = /* @__PURE__ */ new Map();
|
|
11672
11682
|
this.inflight = /* @__PURE__ */ new Map();
|
|
11673
11683
|
this.invalidatedTagVersions = /* @__PURE__ */ new Map();
|
|
11674
11684
|
this.version = 0;
|
|
11685
|
+
this.namespace = "farm";
|
|
11686
|
+
this.local = true;
|
|
11687
|
+
this.lease = {
|
|
11688
|
+
enabled: true,
|
|
11689
|
+
ttlMs: 1e4,
|
|
11690
|
+
waitTimeoutMs: 1e4,
|
|
11691
|
+
pollIntervalMs: 25
|
|
11692
|
+
};
|
|
11693
|
+
this.configure(config);
|
|
11694
|
+
}
|
|
11695
|
+
configure(config = {}) {
|
|
11696
|
+
this.adapter = config.adapter;
|
|
11697
|
+
this.namespace = normalizeCacheNamespace(config.namespace || "farm");
|
|
11698
|
+
this.local = !config.adapter;
|
|
11699
|
+
this.lease = config.lease === false ? { ...this.lease, enabled: false } : {
|
|
11700
|
+
enabled: true,
|
|
11701
|
+
ttlMs: normalizePositiveDuration(config.lease?.ttlMs, 1e4, "cache.lease.ttlMs"),
|
|
11702
|
+
waitTimeoutMs: normalizePositiveDuration(
|
|
11703
|
+
config.lease?.waitTimeoutMs,
|
|
11704
|
+
1e4,
|
|
11705
|
+
"cache.lease.waitTimeoutMs"
|
|
11706
|
+
),
|
|
11707
|
+
pollIntervalMs: normalizePositiveDuration(
|
|
11708
|
+
config.lease?.pollIntervalMs,
|
|
11709
|
+
25,
|
|
11710
|
+
"cache.lease.pollIntervalMs"
|
|
11711
|
+
)
|
|
11712
|
+
};
|
|
11713
|
+
if (!this.local) {
|
|
11714
|
+
this.entries.clear();
|
|
11715
|
+
this.inflight.clear();
|
|
11716
|
+
this.invalidatedTagVersions.clear();
|
|
11717
|
+
this.version = 0;
|
|
11718
|
+
}
|
|
11719
|
+
}
|
|
11720
|
+
get adapterName() {
|
|
11721
|
+
return this.adapter?.name || (this.adapter ? "custom" : "memory");
|
|
11722
|
+
}
|
|
11723
|
+
get hasAdapter() {
|
|
11724
|
+
return this.adapter !== void 0;
|
|
11675
11725
|
}
|
|
11676
11726
|
get size() {
|
|
11677
11727
|
return this.entries.size;
|
|
@@ -11707,6 +11757,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11707
11757
|
});
|
|
11708
11758
|
return this.toPublicEntry(entry);
|
|
11709
11759
|
}
|
|
11760
|
+
async getEntryAsync(key, options = {}) {
|
|
11761
|
+
if (this.local) {
|
|
11762
|
+
const localEntry = this.getEntry(key, options);
|
|
11763
|
+
if (localEntry) return localEntry;
|
|
11764
|
+
}
|
|
11765
|
+
if (!this.adapter) {
|
|
11766
|
+
return this.local ? void 0 : this.getEntry(key, options);
|
|
11767
|
+
}
|
|
11768
|
+
const entry = await this.adapter.get(this.createAdapterKey(key));
|
|
11769
|
+
if (!entry) {
|
|
11770
|
+
emitFarmEvent({ type: "cache.miss", key });
|
|
11771
|
+
return void 0;
|
|
11772
|
+
}
|
|
11773
|
+
assertFarmCacheEntry(entry, key);
|
|
11774
|
+
const stale = await this.isAdapterEntryStale(entry, options.now);
|
|
11775
|
+
if (stale) {
|
|
11776
|
+
emitFarmEvent({
|
|
11777
|
+
type: "cache.stale",
|
|
11778
|
+
key,
|
|
11779
|
+
tags: [...entry.tags],
|
|
11780
|
+
revalidate: entry.revalidate
|
|
11781
|
+
});
|
|
11782
|
+
if (!options.allowStale) {
|
|
11783
|
+
emitFarmEvent({ type: "cache.miss", key, reason: "stale" });
|
|
11784
|
+
return void 0;
|
|
11785
|
+
}
|
|
11786
|
+
}
|
|
11787
|
+
emitFarmEvent({
|
|
11788
|
+
type: "cache.hit",
|
|
11789
|
+
key,
|
|
11790
|
+
tags: [...entry.tags],
|
|
11791
|
+
revalidate: entry.revalidate,
|
|
11792
|
+
stale
|
|
11793
|
+
});
|
|
11794
|
+
if (this.local && !stale) {
|
|
11795
|
+
this.hydrateLocalEntry(entry);
|
|
11796
|
+
}
|
|
11797
|
+
return { ...entry, key };
|
|
11798
|
+
}
|
|
11710
11799
|
set(key, value, options = {}) {
|
|
11711
11800
|
const tags = /* @__PURE__ */ new Set();
|
|
11712
11801
|
for (const tag of options.tags ?? []) {
|
|
@@ -11719,6 +11808,7 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11719
11808
|
key,
|
|
11720
11809
|
value,
|
|
11721
11810
|
tags,
|
|
11811
|
+
tagVersions: void 0,
|
|
11722
11812
|
createdAt: options.createdAt ?? Date.now(),
|
|
11723
11813
|
createdVersion: ++this.version,
|
|
11724
11814
|
revalidate: normalizeRevalidate(options.revalidate)
|
|
@@ -11732,11 +11822,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11732
11822
|
});
|
|
11733
11823
|
return this.toPublicEntry(entry);
|
|
11734
11824
|
}
|
|
11825
|
+
async setAsync(key, value, options = {}, tagVersions) {
|
|
11826
|
+
const tags = normalizeCacheOptionsTags(options);
|
|
11827
|
+
const capturedVersions = tagVersions ?? await this.getAdapterTagVersions(Array.from(tags.values()));
|
|
11828
|
+
const entry = {
|
|
11829
|
+
key,
|
|
11830
|
+
value,
|
|
11831
|
+
tags: Array.from(tags),
|
|
11832
|
+
tagVersions: capturedVersions,
|
|
11833
|
+
createdAt: options.createdAt ?? Date.now(),
|
|
11834
|
+
createdVersion: ++this.version,
|
|
11835
|
+
revalidate: normalizeRevalidate(options.revalidate)
|
|
11836
|
+
};
|
|
11837
|
+
if (this.local) {
|
|
11838
|
+
this.hydrateLocalEntry(entry);
|
|
11839
|
+
}
|
|
11840
|
+
if (this.adapter) {
|
|
11841
|
+
await this.adapter.set(this.createAdapterKey(key), entry);
|
|
11842
|
+
}
|
|
11843
|
+
emitFarmEvent({
|
|
11844
|
+
type: "cache.set",
|
|
11845
|
+
key,
|
|
11846
|
+
tags: [...entry.tags],
|
|
11847
|
+
revalidate: entry.revalidate
|
|
11848
|
+
});
|
|
11849
|
+
return entry;
|
|
11850
|
+
}
|
|
11735
11851
|
delete(key) {
|
|
11736
11852
|
const deleted = this.entries.delete(key);
|
|
11737
11853
|
emitFarmEvent({ type: "cache.delete", key, deleted });
|
|
11738
11854
|
return deleted;
|
|
11739
11855
|
}
|
|
11856
|
+
async deleteAsync(key) {
|
|
11857
|
+
const deleted = this.entries.delete(key);
|
|
11858
|
+
if (this.adapter) {
|
|
11859
|
+
await this.adapter.delete(this.createAdapterKey(key));
|
|
11860
|
+
}
|
|
11861
|
+
emitFarmEvent({ type: "cache.delete", key, deleted: this.adapter ? true : deleted });
|
|
11862
|
+
return this.adapter ? true : deleted;
|
|
11863
|
+
}
|
|
11740
11864
|
clear() {
|
|
11741
11865
|
const count = this.entries.size;
|
|
11742
11866
|
this.entries.clear();
|
|
@@ -11745,6 +11869,10 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11745
11869
|
this.version = 0;
|
|
11746
11870
|
emitFarmEvent({ type: "cache.clear", count });
|
|
11747
11871
|
}
|
|
11872
|
+
async clearAsync() {
|
|
11873
|
+
this.clear();
|
|
11874
|
+
await this.adapter?.clear?.();
|
|
11875
|
+
}
|
|
11748
11876
|
isStale(entry, now = Date.now()) {
|
|
11749
11877
|
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
11750
11878
|
return true;
|
|
@@ -11757,6 +11885,12 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11757
11885
|
}
|
|
11758
11886
|
return false;
|
|
11759
11887
|
}
|
|
11888
|
+
async isStaleAsync(entry, now = Date.now()) {
|
|
11889
|
+
if (this.adapter) {
|
|
11890
|
+
return this.isAdapterEntryStale(entry, now);
|
|
11891
|
+
}
|
|
11892
|
+
return this.isStale(entry, now);
|
|
11893
|
+
}
|
|
11760
11894
|
revalidateTag(tag, options = {}) {
|
|
11761
11895
|
const normalized = normalizeCacheTag(tag);
|
|
11762
11896
|
const count = this.invalidateTag(normalized);
|
|
@@ -11765,6 +11899,15 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11765
11899
|
);
|
|
11766
11900
|
return count;
|
|
11767
11901
|
}
|
|
11902
|
+
async revalidateTagAsync(tag, options = {}) {
|
|
11903
|
+
const normalized = normalizeCacheTag(tag);
|
|
11904
|
+
const count = this.invalidateTag(normalized);
|
|
11905
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(normalized)]);
|
|
11906
|
+
emitFarmEvent(
|
|
11907
|
+
options.source === "updateTag" ? { type: "cache.updateTag", tag: normalized, count } : { type: "cache.revalidateTag", tag: normalized, profile: options.profile, count }
|
|
11908
|
+
);
|
|
11909
|
+
return count;
|
|
11910
|
+
}
|
|
11768
11911
|
revalidatePath(routePath) {
|
|
11769
11912
|
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
11770
11913
|
const pathTag = createPathCacheTag(normalizedPath);
|
|
@@ -11781,8 +11924,25 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11781
11924
|
}
|
|
11782
11925
|
return count;
|
|
11783
11926
|
}
|
|
11927
|
+
async revalidatePathAsync(routePath) {
|
|
11928
|
+
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
11929
|
+
const pathTag = createPathCacheTag(normalizedPath);
|
|
11930
|
+
const pprCount = this.countEntriesForTags([pathTag, "ppr"]);
|
|
11931
|
+
const count = this.invalidateTag(pathTag);
|
|
11932
|
+
await this.adapter?.invalidateTags?.([this.createAdapterTag(pathTag)]);
|
|
11933
|
+
emitFarmEvent({ type: "cache.revalidatePath", path: normalizedPath, count });
|
|
11934
|
+
if (pprCount > 0) {
|
|
11935
|
+
emitFarmEvent({
|
|
11936
|
+
type: "ppr.shell.invalidated",
|
|
11937
|
+
route: normalizedPath,
|
|
11938
|
+
reason: "revalidatePath",
|
|
11939
|
+
count: pprCount
|
|
11940
|
+
});
|
|
11941
|
+
}
|
|
11942
|
+
return count;
|
|
11943
|
+
}
|
|
11784
11944
|
async getOrSet(key, producer, options = {}) {
|
|
11785
|
-
const cached = this.
|
|
11945
|
+
const cached = await this.getEntryAsync(key);
|
|
11786
11946
|
if (cached) {
|
|
11787
11947
|
return cached.value;
|
|
11788
11948
|
}
|
|
@@ -11791,10 +11951,8 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11791
11951
|
emitFarmEvent({ type: "cache.dedupe", key });
|
|
11792
11952
|
return inflight;
|
|
11793
11953
|
}
|
|
11794
|
-
const
|
|
11795
|
-
|
|
11796
|
-
return value;
|
|
11797
|
-
}).catch((error) => {
|
|
11954
|
+
const tags = Array.from(normalizeCacheOptionsTags(options));
|
|
11955
|
+
const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
|
|
11798
11956
|
emitFarmEvent({ type: "cache.error", key, operation: "set", error });
|
|
11799
11957
|
throw error;
|
|
11800
11958
|
}).finally(() => {
|
|
@@ -11803,6 +11961,40 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11803
11961
|
this.inflight.set(key, promise);
|
|
11804
11962
|
return promise;
|
|
11805
11963
|
}
|
|
11964
|
+
async fillCacheEntry(key, producer, options, tags) {
|
|
11965
|
+
const leaseKey = `${this.namespace}:lease:${key}`;
|
|
11966
|
+
let leaseToken;
|
|
11967
|
+
if (this.adapter?.acquireLease && this.adapter.releaseLease && this.lease.enabled) {
|
|
11968
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
11969
|
+
if (!leaseToken) {
|
|
11970
|
+
const shared = await this.waitForAdapterEntry(key);
|
|
11971
|
+
if (shared) {
|
|
11972
|
+
emitFarmEvent({ type: "cache.dedupe", key });
|
|
11973
|
+
return shared.value;
|
|
11974
|
+
}
|
|
11975
|
+
leaseToken = await this.adapter.acquireLease(leaseKey, this.lease.ttlMs);
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
try {
|
|
11979
|
+
const initialTagVersions = await this.getAdapterTagVersions(tags);
|
|
11980
|
+
const value = await producer();
|
|
11981
|
+
await this.setAsync(key, value, options, initialTagVersions);
|
|
11982
|
+
return value;
|
|
11983
|
+
} finally {
|
|
11984
|
+
if (leaseToken && this.adapter?.releaseLease) {
|
|
11985
|
+
await this.adapter.releaseLease(leaseKey, leaseToken);
|
|
11986
|
+
}
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
async waitForAdapterEntry(key) {
|
|
11990
|
+
const deadline = Date.now() + this.lease.waitTimeoutMs;
|
|
11991
|
+
while (Date.now() < deadline) {
|
|
11992
|
+
await delay(this.lease.pollIntervalMs);
|
|
11993
|
+
const entry = await this.getEntryAsync(key);
|
|
11994
|
+
if (entry) return entry;
|
|
11995
|
+
}
|
|
11996
|
+
return void 0;
|
|
11997
|
+
}
|
|
11806
11998
|
countEntriesForTag(tag) {
|
|
11807
11999
|
let count = 0;
|
|
11808
12000
|
for (const entry of this.entries.values()) {
|
|
@@ -11830,11 +12022,53 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
11830
12022
|
key: entry.key,
|
|
11831
12023
|
value: entry.value,
|
|
11832
12024
|
tags: Array.from(entry.tags),
|
|
12025
|
+
tagVersions: entry.tagVersions,
|
|
11833
12026
|
createdAt: entry.createdAt,
|
|
11834
12027
|
createdVersion: entry.createdVersion,
|
|
11835
12028
|
revalidate: entry.revalidate
|
|
11836
12029
|
};
|
|
11837
12030
|
}
|
|
12031
|
+
hydrateLocalEntry(entry) {
|
|
12032
|
+
this.entries.set(entry.key, {
|
|
12033
|
+
key: entry.key,
|
|
12034
|
+
value: entry.value,
|
|
12035
|
+
tags: new Set(entry.tags.map(normalizeCacheTag)),
|
|
12036
|
+
tagVersions: entry.tagVersions,
|
|
12037
|
+
createdAt: entry.createdAt,
|
|
12038
|
+
createdVersion: entry.createdVersion ?? ++this.version,
|
|
12039
|
+
revalidate: normalizeRevalidate(entry.revalidate)
|
|
12040
|
+
});
|
|
12041
|
+
}
|
|
12042
|
+
createAdapterKey(key) {
|
|
12043
|
+
return `${this.namespace}:entry:${key}`;
|
|
12044
|
+
}
|
|
12045
|
+
createAdapterTag(tag) {
|
|
12046
|
+
return `${this.namespace}:tag:${tag}`;
|
|
12047
|
+
}
|
|
12048
|
+
async getAdapterTagVersions(tags) {
|
|
12049
|
+
if (!this.adapter?.getTagVersions || tags.length === 0) return {};
|
|
12050
|
+
const normalized = tags.map(normalizeCacheTag);
|
|
12051
|
+
const physicalTags = normalized.map((tag) => this.createAdapterTag(tag));
|
|
12052
|
+
const versions = await this.adapter.getTagVersions(physicalTags);
|
|
12053
|
+
return Object.fromEntries(
|
|
12054
|
+
normalized.map((tag, index) => [
|
|
12055
|
+
tag,
|
|
12056
|
+
normalizeAdapterVersion(versions[physicalTags[index]])
|
|
12057
|
+
])
|
|
12058
|
+
);
|
|
12059
|
+
}
|
|
12060
|
+
async isAdapterEntryStale(entry, now = Date.now()) {
|
|
12061
|
+
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
12062
|
+
return true;
|
|
12063
|
+
}
|
|
12064
|
+
const currentVersions = await this.getAdapterTagVersions(entry.tags);
|
|
12065
|
+
for (const tag of entry.tags) {
|
|
12066
|
+
if (normalizeAdapterVersion(currentVersions[tag]) > normalizeAdapterVersion(entry.tagVersions?.[tag])) {
|
|
12067
|
+
return true;
|
|
12068
|
+
}
|
|
12069
|
+
}
|
|
12070
|
+
return false;
|
|
12071
|
+
}
|
|
11838
12072
|
};
|
|
11839
12073
|
__name(_FarmDataCache, "FarmDataCache");
|
|
11840
12074
|
var FarmDataCache = _FarmDataCache;
|
|
@@ -11847,6 +12081,10 @@ function getFarmDataCache() {
|
|
|
11847
12081
|
return sharedFarmDataCache;
|
|
11848
12082
|
}
|
|
11849
12083
|
__name(getFarmDataCache, "getFarmDataCache");
|
|
12084
|
+
function configureFarmCache(config) {
|
|
12085
|
+
sharedFarmDataCache.configure(config);
|
|
12086
|
+
}
|
|
12087
|
+
__name(configureFarmCache, "configureFarmCache");
|
|
11850
12088
|
function createPathCacheTag(routePath) {
|
|
11851
12089
|
return `path:${normalizeRevalidatePath(routePath)}`;
|
|
11852
12090
|
}
|
|
@@ -11907,6 +12145,52 @@ function normalizeCacheTag(tag) {
|
|
|
11907
12145
|
return normalized;
|
|
11908
12146
|
}
|
|
11909
12147
|
__name(normalizeCacheTag, "normalizeCacheTag");
|
|
12148
|
+
function normalizeCacheNamespace(namespace) {
|
|
12149
|
+
if (typeof namespace !== "string") {
|
|
12150
|
+
throw new TypeError("Cache namespace must be a string.");
|
|
12151
|
+
}
|
|
12152
|
+
const normalized = namespace.trim().replace(/:+$/g, "");
|
|
12153
|
+
if (!normalized) {
|
|
12154
|
+
throw new Error("Cache namespace cannot be empty.");
|
|
12155
|
+
}
|
|
12156
|
+
return normalized;
|
|
12157
|
+
}
|
|
12158
|
+
__name(normalizeCacheNamespace, "normalizeCacheNamespace");
|
|
12159
|
+
function normalizeAdapterVersion(value) {
|
|
12160
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
12161
|
+
}
|
|
12162
|
+
__name(normalizeAdapterVersion, "normalizeAdapterVersion");
|
|
12163
|
+
function normalizePositiveDuration(value, fallback, name) {
|
|
12164
|
+
if (value === void 0) return fallback;
|
|
12165
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
12166
|
+
throw new TypeError(`${name} must be a positive number of milliseconds.`);
|
|
12167
|
+
}
|
|
12168
|
+
return Math.floor(value);
|
|
12169
|
+
}
|
|
12170
|
+
__name(normalizePositiveDuration, "normalizePositiveDuration");
|
|
12171
|
+
function delay(ms) {
|
|
12172
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
12173
|
+
}
|
|
12174
|
+
__name(delay, "delay");
|
|
12175
|
+
function normalizeCacheOptionsTags(options) {
|
|
12176
|
+
const tags = /* @__PURE__ */ new Set();
|
|
12177
|
+
for (const tag of options.tags ?? []) {
|
|
12178
|
+
tags.add(normalizeCacheTag(tag));
|
|
12179
|
+
}
|
|
12180
|
+
for (const routePath of options.paths ?? []) {
|
|
12181
|
+
tags.add(createPathCacheTag(routePath));
|
|
12182
|
+
}
|
|
12183
|
+
return tags;
|
|
12184
|
+
}
|
|
12185
|
+
__name(normalizeCacheOptionsTags, "normalizeCacheOptionsTags");
|
|
12186
|
+
function assertFarmCacheEntry(entry, expectedKey) {
|
|
12187
|
+
if (!entry || typeof entry !== "object" || entry.key !== expectedKey || !Array.isArray(entry.tags) || typeof entry.createdAt !== "number") {
|
|
12188
|
+
throw new TypeError(
|
|
12189
|
+
`Cache adapter returned an invalid entry for ${JSON.stringify(expectedKey)}.`
|
|
12190
|
+
);
|
|
12191
|
+
}
|
|
12192
|
+
}
|
|
12193
|
+
__name(assertFarmCacheEntry, "assertFarmCacheEntry");
|
|
11910
12194
|
function getFunctionCacheIdentity(fn) {
|
|
11911
12195
|
if (fn.name) {
|
|
11912
12196
|
return `name:${fn.name}`;
|
|
@@ -13047,6 +13331,76 @@ function normalizePathname(pathname) {
|
|
|
13047
13331
|
}
|
|
13048
13332
|
__name(normalizePathname, "normalizePathname");
|
|
13049
13333
|
|
|
13334
|
+
// src/routing/route-slots.ts
|
|
13335
|
+
var SLOT_SEGMENT = /^@([A-Za-z][A-Za-z0-9_-]*)$/;
|
|
13336
|
+
function parseRouteSlotFile(filePath) {
|
|
13337
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
13338
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
13339
|
+
const fileName = parts.at(-1) ?? "";
|
|
13340
|
+
const baseName = fileName.replace(/\.(tsx?|jsx?)$/, "");
|
|
13341
|
+
if (baseName !== "page" && baseName !== "default") return null;
|
|
13342
|
+
const slotIndex = parts.findIndex((part) => SLOT_SEGMENT.test(part));
|
|
13343
|
+
if (slotIndex < 0) return null;
|
|
13344
|
+
if (parts.slice(slotIndex + 1, -1).some((part) => SLOT_SEGMENT.test(part))) {
|
|
13345
|
+
throw new Error(`Nested route slots are not supported in "${filePath}"`);
|
|
13346
|
+
}
|
|
13347
|
+
const slotMatch = parts[slotIndex].match(SLOT_SEGMENT);
|
|
13348
|
+
const name = slotMatch?.[1];
|
|
13349
|
+
if (!name) return null;
|
|
13350
|
+
const ownerParts = parts.slice(0, slotIndex);
|
|
13351
|
+
const contentParts = parts.slice(slotIndex + 1, -1);
|
|
13352
|
+
const marker = parseInterceptionMarker(contentParts[0]);
|
|
13353
|
+
let targetBase = ownerParts;
|
|
13354
|
+
let targetParts = contentParts;
|
|
13355
|
+
if (marker) {
|
|
13356
|
+
targetBase = marker.root === true ? [] : ownerParts.slice(0, Math.max(0, ownerParts.length - marker.up));
|
|
13357
|
+
targetParts = [...marker.remainder ? [marker.remainder] : [], ...contentParts.slice(1)];
|
|
13358
|
+
}
|
|
13359
|
+
const ownerFile = [...ownerParts, "layout.tsx"].join("/");
|
|
13360
|
+
const routeFile = [
|
|
13361
|
+
...baseName === "default" ? ownerParts : targetBase,
|
|
13362
|
+
...baseName === "default" ? [] : targetParts,
|
|
13363
|
+
"page.tsx"
|
|
13364
|
+
].join("/");
|
|
13365
|
+
return {
|
|
13366
|
+
name,
|
|
13367
|
+
ownerRoute: parseRoutePath(ownerFile || "layout.tsx"),
|
|
13368
|
+
route: parseRoutePath(routeFile || "page.tsx"),
|
|
13369
|
+
interception: marker !== null,
|
|
13370
|
+
fallback: baseName === "default"
|
|
13371
|
+
};
|
|
13372
|
+
}
|
|
13373
|
+
__name(parseRouteSlotFile, "parseRouteSlotFile");
|
|
13374
|
+
function createRouteSlotContainerId(name, ownerPattern) {
|
|
13375
|
+
const owner = ownerPattern === "/" ? "root" : ownerPattern.replace(/^\//, "").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
13376
|
+
return `__farm_slot_${name}_${owner || "root"}__`;
|
|
13377
|
+
}
|
|
13378
|
+
__name(createRouteSlotContainerId, "createRouteSlotContainerId");
|
|
13379
|
+
function parseInterceptionMarker(segment) {
|
|
13380
|
+
if (!segment) return null;
|
|
13381
|
+
if (segment.startsWith("(...)")) {
|
|
13382
|
+
return {
|
|
13383
|
+
up: 0,
|
|
13384
|
+
root: true,
|
|
13385
|
+
remainder: segment.slice(5)
|
|
13386
|
+
};
|
|
13387
|
+
}
|
|
13388
|
+
if (segment.startsWith("(.)")) {
|
|
13389
|
+
return {
|
|
13390
|
+
up: 0,
|
|
13391
|
+
remainder: segment.slice(3)
|
|
13392
|
+
};
|
|
13393
|
+
}
|
|
13394
|
+
let remainder = segment;
|
|
13395
|
+
let up = 0;
|
|
13396
|
+
while (remainder.startsWith("(..)")) {
|
|
13397
|
+
up += 1;
|
|
13398
|
+
remainder = remainder.slice(4);
|
|
13399
|
+
}
|
|
13400
|
+
return up > 0 ? { up, remainder } : null;
|
|
13401
|
+
}
|
|
13402
|
+
__name(parseInterceptionMarker, "parseInterceptionMarker");
|
|
13403
|
+
|
|
13050
13404
|
// src/routing/route-manager.ts
|
|
13051
13405
|
function routeSpecificity(entry) {
|
|
13052
13406
|
return entry.route.segments.reduce((score, segment) => {
|
|
@@ -13060,6 +13414,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13060
13414
|
constructor(config, viteServer) {
|
|
13061
13415
|
this.routes = /* @__PURE__ */ new Map();
|
|
13062
13416
|
this.layouts = /* @__PURE__ */ new Map();
|
|
13417
|
+
this.routeSlots = /* @__PURE__ */ new Map();
|
|
13063
13418
|
this.loadings = /* @__PURE__ */ new Map();
|
|
13064
13419
|
this.errors = /* @__PURE__ */ new Map();
|
|
13065
13420
|
this.metadataImages = /* @__PURE__ */ new Map();
|
|
@@ -13075,6 +13430,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13075
13430
|
async discoverRoutes() {
|
|
13076
13431
|
this.routes.clear();
|
|
13077
13432
|
this.layouts.clear();
|
|
13433
|
+
this.routeSlots.clear();
|
|
13078
13434
|
this.loadings.clear();
|
|
13079
13435
|
this.errors.clear();
|
|
13080
13436
|
this.metadataImages.clear();
|
|
@@ -13085,6 +13441,13 @@ var _RouteManager = class _RouteManager {
|
|
|
13085
13441
|
await this.discoverFileRoutes(source);
|
|
13086
13442
|
await this.discoverProgrammaticRoutes(source);
|
|
13087
13443
|
}
|
|
13444
|
+
for (const slot of this.routeSlots.values()) {
|
|
13445
|
+
if (slot.interception && !this.routes.has(slot.pattern)) {
|
|
13446
|
+
throw new Error(
|
|
13447
|
+
`Intercepting route slot "${slot.name}" targets "${slot.pattern}", but no canonical page exists for that URL`
|
|
13448
|
+
);
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13088
13451
|
this.routes = new Map(
|
|
13089
13452
|
Array.from(this.routes.entries()).sort(
|
|
13090
13453
|
([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
|
|
@@ -13100,7 +13463,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13100
13463
|
/**
|
|
13101
13464
|
* Find matching route for a given URL path
|
|
13102
13465
|
*/
|
|
13103
|
-
matchRoute(pathname) {
|
|
13466
|
+
matchRoute(pathname, options = {}) {
|
|
13104
13467
|
const routePathname = this.toRoutePathname(pathname);
|
|
13105
13468
|
const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
|
|
13106
13469
|
let matchedRoute = null;
|
|
@@ -13114,10 +13477,12 @@ var _RouteManager = class _RouteManager {
|
|
|
13114
13477
|
}
|
|
13115
13478
|
}
|
|
13116
13479
|
const layouts = this.findMatchingLayouts(normalizedPath);
|
|
13480
|
+
const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
|
|
13117
13481
|
return {
|
|
13118
13482
|
route: matchedRoute,
|
|
13119
13483
|
params,
|
|
13120
|
-
layouts
|
|
13484
|
+
layouts,
|
|
13485
|
+
slots
|
|
13121
13486
|
};
|
|
13122
13487
|
}
|
|
13123
13488
|
/**
|
|
@@ -13132,6 +13497,9 @@ var _RouteManager = class _RouteManager {
|
|
|
13132
13497
|
getLayouts() {
|
|
13133
13498
|
return new Map(this.layouts);
|
|
13134
13499
|
}
|
|
13500
|
+
getRouteSlots() {
|
|
13501
|
+
return new Map(this.routeSlots);
|
|
13502
|
+
}
|
|
13135
13503
|
/** Resolve route rules, inherited layouts, and the page export in precedence order. */
|
|
13136
13504
|
async resolveRouteRuntimeConfig(pattern) {
|
|
13137
13505
|
const routeEntry = this.routes.get(pattern);
|
|
@@ -13290,7 +13658,22 @@ var _RouteManager = class _RouteManager {
|
|
|
13290
13658
|
pattern: entry.pattern,
|
|
13291
13659
|
modulePath: toUrlPath(entry.modulePath)
|
|
13292
13660
|
}));
|
|
13293
|
-
|
|
13661
|
+
const slots = Array.from(this.routeSlots.values()).map((entry) => {
|
|
13662
|
+
const metadata = getClientModuleMetadata(entry.modulePath, projectRoot);
|
|
13663
|
+
return {
|
|
13664
|
+
name: entry.name,
|
|
13665
|
+
ownerPattern: entry.ownerPattern,
|
|
13666
|
+
pattern: entry.pattern,
|
|
13667
|
+
modulePath: toUrlPath(entry.modulePath),
|
|
13668
|
+
containerId: entry.containerId,
|
|
13669
|
+
interception: entry.interception,
|
|
13670
|
+
fallback: entry.fallback,
|
|
13671
|
+
shouldHydrate: metadata.shouldHydrate,
|
|
13672
|
+
isClientComponent: metadata.isClientComponent,
|
|
13673
|
+
segments: entry.route.segments
|
|
13674
|
+
};
|
|
13675
|
+
});
|
|
13676
|
+
return { routes, layouts, slots };
|
|
13294
13677
|
}
|
|
13295
13678
|
/**
|
|
13296
13679
|
* Load a route module dynamically
|
|
@@ -13367,6 +13750,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13367
13750
|
async discoverFileRoutes(source) {
|
|
13368
13751
|
const appDir = resolveAppPath(source.root, source.srcDir, "app");
|
|
13369
13752
|
const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
|
|
13753
|
+
const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
|
|
13370
13754
|
const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
|
|
13371
13755
|
const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
|
|
13372
13756
|
const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
|
|
@@ -13375,7 +13759,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13375
13759
|
appDir
|
|
13376
13760
|
);
|
|
13377
13761
|
for (const [kind, files, target] of [
|
|
13378
|
-
["page", pageFiles, this.routes],
|
|
13762
|
+
["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
|
|
13379
13763
|
["layout", layoutFiles, this.layouts],
|
|
13380
13764
|
["loading", loadingFiles, this.loadings],
|
|
13381
13765
|
["error", errorFiles, this.errors]
|
|
@@ -13399,6 +13783,32 @@ var _RouteManager = class _RouteManager {
|
|
|
13399
13783
|
});
|
|
13400
13784
|
}
|
|
13401
13785
|
}
|
|
13786
|
+
for (const file of [...pageFiles, ...slotDefaultFiles]) {
|
|
13787
|
+
const slot = parseRouteSlotFile(file);
|
|
13788
|
+
if (!slot) continue;
|
|
13789
|
+
const modulePath = import_path5.default.join(appDir, file);
|
|
13790
|
+
const pattern = this.createRoutePattern(slot.route);
|
|
13791
|
+
const ownerPattern = this.createRoutePattern(slot.ownerRoute);
|
|
13792
|
+
const key = `${ownerPattern}:${slot.name}:${slot.interception ? "intercept" : "slot"}:${slot.fallback ? "default" : pattern}`;
|
|
13793
|
+
const existing = this.routeSlots.get(key);
|
|
13794
|
+
if (existing?.sourceRoot === source.root) {
|
|
13795
|
+
throw new Error(
|
|
13796
|
+
`Duplicate route slot "${slot.name}" for "${pattern}". Found both ${existing.modulePath} and ${modulePath}.`
|
|
13797
|
+
);
|
|
13798
|
+
}
|
|
13799
|
+
this.routeSlots.set(key, {
|
|
13800
|
+
route: slot.route,
|
|
13801
|
+
modulePath,
|
|
13802
|
+
pattern,
|
|
13803
|
+
source: "file",
|
|
13804
|
+
sourceRoot: source.root,
|
|
13805
|
+
name: slot.name,
|
|
13806
|
+
ownerPattern,
|
|
13807
|
+
interception: slot.interception,
|
|
13808
|
+
fallback: slot.fallback,
|
|
13809
|
+
containerId: createRouteSlotContainerId(slot.name, ownerPattern)
|
|
13810
|
+
});
|
|
13811
|
+
}
|
|
13402
13812
|
for (const file of metadataImageFiles) {
|
|
13403
13813
|
const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
|
|
13404
13814
|
const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
|
|
@@ -13524,6 +13934,71 @@ var _RouteManager = class _RouteManager {
|
|
|
13524
13934
|
}
|
|
13525
13935
|
return matchingLayouts;
|
|
13526
13936
|
}
|
|
13937
|
+
findMatchingRouteSlots(pathname, interceptFrom) {
|
|
13938
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13939
|
+
for (const entry of this.routeSlots.values()) {
|
|
13940
|
+
if (!this.matchesRoutePrefix(pathname, entry.ownerPattern)) continue;
|
|
13941
|
+
const key = `${entry.ownerPattern}:${entry.name}`;
|
|
13942
|
+
const entries = groups.get(key) ?? [];
|
|
13943
|
+
entries.push(entry);
|
|
13944
|
+
groups.set(key, entries);
|
|
13945
|
+
}
|
|
13946
|
+
const normalizedFrom = interceptFrom ? this.toRoutePathname(new URL(interceptFrom, "http://farm.local").pathname) : void 0;
|
|
13947
|
+
const matches = [];
|
|
13948
|
+
for (const entries of groups.values()) {
|
|
13949
|
+
const candidates = entries.filter((entry) => !entry.fallback).filter(
|
|
13950
|
+
(entry) => !entry.interception || normalizedFrom !== void 0 && this.matchesRoutePrefix(normalizedFrom, entry.ownerPattern)
|
|
13951
|
+
).map((entry) => ({
|
|
13952
|
+
entry,
|
|
13953
|
+
match: matchRoute(pathname, entry.route.segments)
|
|
13954
|
+
})).filter((candidate) => candidate.match.matches).sort((left, right) => {
|
|
13955
|
+
if (left.entry.interception !== right.entry.interception) {
|
|
13956
|
+
return left.entry.interception ? -1 : 1;
|
|
13957
|
+
}
|
|
13958
|
+
return routeSpecificity(right.entry) - routeSpecificity(left.entry);
|
|
13959
|
+
});
|
|
13960
|
+
const selected = candidates[0];
|
|
13961
|
+
if (selected) {
|
|
13962
|
+
matches.push({
|
|
13963
|
+
name: selected.entry.name,
|
|
13964
|
+
ownerPattern: selected.entry.ownerPattern,
|
|
13965
|
+
containerId: selected.entry.containerId,
|
|
13966
|
+
interception: selected.entry.interception,
|
|
13967
|
+
fallback: false,
|
|
13968
|
+
route: selected.entry,
|
|
13969
|
+
params: selected.match.params
|
|
13970
|
+
});
|
|
13971
|
+
continue;
|
|
13972
|
+
}
|
|
13973
|
+
const fallback = entries.find((entry) => entry.fallback);
|
|
13974
|
+
if (fallback) {
|
|
13975
|
+
matches.push({
|
|
13976
|
+
name: fallback.name,
|
|
13977
|
+
ownerPattern: fallback.ownerPattern,
|
|
13978
|
+
containerId: fallback.containerId,
|
|
13979
|
+
interception: false,
|
|
13980
|
+
fallback: true,
|
|
13981
|
+
route: fallback,
|
|
13982
|
+
params: {}
|
|
13983
|
+
});
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
return matches.sort((left, right) => {
|
|
13987
|
+
const ownerDifference = left.route.route.segments.length - right.route.route.segments.length;
|
|
13988
|
+
return ownerDifference || left.name.localeCompare(right.name);
|
|
13989
|
+
});
|
|
13990
|
+
}
|
|
13991
|
+
matchesRoutePrefix(pathname, pattern) {
|
|
13992
|
+
if (pattern === "/") return true;
|
|
13993
|
+
const patternSegments = parseRoutePath(`${pattern}/page.tsx`).segments;
|
|
13994
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
13995
|
+
if (patternSegments.length > pathSegments.length) return false;
|
|
13996
|
+
for (let index = 0; index < patternSegments.length; index++) {
|
|
13997
|
+
const segment = patternSegments[index];
|
|
13998
|
+
if (!segment.isDynamic && segment.segment !== pathSegments[index]) return false;
|
|
13999
|
+
}
|
|
14000
|
+
return true;
|
|
14001
|
+
}
|
|
13527
14002
|
findNearestBoundary(pathname, boundaries) {
|
|
13528
14003
|
const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
|
|
13529
14004
|
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
@@ -15052,7 +15527,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15052
15527
|
async runWithRequestContext(request, fn) {
|
|
15053
15528
|
return _runWithCurrentRequest(
|
|
15054
15529
|
request,
|
|
15055
|
-
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15530
|
+
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15531
|
+
redirect: false
|
|
15532
|
+
}) : fn()
|
|
15056
15533
|
);
|
|
15057
15534
|
}
|
|
15058
15535
|
async resolveRouteContext(input) {
|
|
@@ -15075,11 +15552,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15075
15552
|
/**
|
|
15076
15553
|
* Check if a path should be served from SSG cache
|
|
15077
15554
|
*/
|
|
15078
|
-
shouldServeSSG(pathname) {
|
|
15555
|
+
async shouldServeSSG(pathname) {
|
|
15079
15556
|
const ssgPage = matchSSGPage(pathname, this.ssgManifest);
|
|
15080
15557
|
if (!ssgPage) return null;
|
|
15081
|
-
const cached = this.getCachedSSGPage(pathname);
|
|
15082
|
-
if (cached && this.dataCache.
|
|
15558
|
+
const cached = await this.getCachedSSGPage(pathname);
|
|
15559
|
+
if (cached && await this.dataCache.isStaleAsync(cached)) {
|
|
15083
15560
|
this.regenerateSSGPage(ssgPage);
|
|
15084
15561
|
}
|
|
15085
15562
|
return ssgPage;
|
|
@@ -15091,12 +15568,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15091
15568
|
return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
|
|
15092
15569
|
}
|
|
15093
15570
|
getCachedSSGPage(urlPath) {
|
|
15094
|
-
return this.dataCache.
|
|
15571
|
+
return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
|
|
15095
15572
|
allowStale: true
|
|
15096
15573
|
});
|
|
15097
15574
|
}
|
|
15098
|
-
cacheSSGPage(page2, html, options) {
|
|
15099
|
-
this.dataCache.
|
|
15575
|
+
async cacheSSGPage(page2, html, options) {
|
|
15576
|
+
await this.dataCache.setAsync(
|
|
15100
15577
|
this.getSSGCacheKey(page2.urlPath),
|
|
15101
15578
|
{ html, document: options.document },
|
|
15102
15579
|
{
|
|
@@ -15108,11 +15585,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15108
15585
|
);
|
|
15109
15586
|
}
|
|
15110
15587
|
getCachedPPRShell(pathname, search) {
|
|
15111
|
-
return this.dataCache.
|
|
15588
|
+
return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
|
|
15112
15589
|
}
|
|
15113
|
-
cachePPRShell(options, html) {
|
|
15590
|
+
async cachePPRShell(options, html) {
|
|
15114
15591
|
const key = this.getPPRCacheKey(options.pathname, options.search);
|
|
15115
|
-
this.dataCache.
|
|
15592
|
+
await this.dataCache.setAsync(
|
|
15116
15593
|
key,
|
|
15117
15594
|
{ html },
|
|
15118
15595
|
{
|
|
@@ -15210,7 +15687,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15210
15687
|
}
|
|
15211
15688
|
const { renderToString } = await import("react-dom/server");
|
|
15212
15689
|
const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
|
|
15213
|
-
this.cacheSSGPage(page2, html, { document: false });
|
|
15690
|
+
await this.cacheSSGPage(page2, html, { document: false });
|
|
15214
15691
|
logger.info(`ISR: Regenerated ${page2.urlPath}`);
|
|
15215
15692
|
} catch (error) {
|
|
15216
15693
|
logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
|
|
@@ -15224,7 +15701,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15224
15701
|
* Serve a pre-rendered SSG page
|
|
15225
15702
|
*/
|
|
15226
15703
|
async serveSSGPage(req, res, page2) {
|
|
15227
|
-
const cached = this.getCachedSSGPage(page2.urlPath);
|
|
15704
|
+
const cached = await this.getCachedSSGPage(page2.urlPath);
|
|
15228
15705
|
if (cached) {
|
|
15229
15706
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15230
15707
|
res.setHeader("X-Farm-SSG", "cached");
|
|
@@ -15242,9 +15719,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15242
15719
|
if (fs2.existsSync(htmlPath)) {
|
|
15243
15720
|
const stat = fs2.statSync(htmlPath);
|
|
15244
15721
|
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
15245
|
-
this.cacheSSGPage(page2, html, {
|
|
15246
|
-
|
|
15247
|
-
|
|
15722
|
+
await this.cacheSSGPage(page2, html, {
|
|
15723
|
+
document: true,
|
|
15724
|
+
createdAt: stat.mtimeMs
|
|
15725
|
+
});
|
|
15726
|
+
const fileCacheEntry = await this.getCachedSSGPage(page2.urlPath);
|
|
15727
|
+
if (fileCacheEntry && await this.dataCache.isStaleAsync(fileCacheEntry)) {
|
|
15248
15728
|
this.regenerateSSGPage(page2);
|
|
15249
15729
|
}
|
|
15250
15730
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -15290,6 +15770,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15290
15770
|
let pathname = "/";
|
|
15291
15771
|
let params = {};
|
|
15292
15772
|
let layouts = [];
|
|
15773
|
+
let routeSlots = [];
|
|
15293
15774
|
let searchParamsObject = {};
|
|
15294
15775
|
let middlewareMap = /* @__PURE__ */ new Map();
|
|
15295
15776
|
let middlewareContext = /* @__PURE__ */ new Map();
|
|
@@ -15322,7 +15803,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15322
15803
|
}
|
|
15323
15804
|
this.applyDeploymentHeaders(req, res);
|
|
15324
15805
|
if (process.env.NODE_ENV === "production") {
|
|
15325
|
-
const ssgPage = this.shouldServeSSG(pathname);
|
|
15806
|
+
const ssgPage = await this.shouldServeSSG(pathname);
|
|
15326
15807
|
if (ssgPage) {
|
|
15327
15808
|
const served = await this.serveSSGPage(req, res, ssgPage);
|
|
15328
15809
|
if (served) {
|
|
@@ -15335,6 +15816,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15335
15816
|
const route = match.route;
|
|
15336
15817
|
params = match.params;
|
|
15337
15818
|
layouts = match.layouts;
|
|
15819
|
+
routeSlots = match.slots ?? [];
|
|
15338
15820
|
if (!route) {
|
|
15339
15821
|
emitFarmEvent({ type: "route.notFound", pathname });
|
|
15340
15822
|
await this.render404(req, res);
|
|
@@ -15351,7 +15833,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15351
15833
|
errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
|
|
15352
15834
|
middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
|
|
15353
15835
|
middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
|
|
15354
|
-
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
15836
|
+
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
15837
|
+
exposedOnly: true
|
|
15838
|
+
});
|
|
15355
15839
|
const currentRequest = createWebRequestFromFarmRequest(req);
|
|
15356
15840
|
const routeContext = await this.resolveRouteContext({
|
|
15357
15841
|
request: currentRequest,
|
|
@@ -15415,8 +15899,16 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15415
15899
|
revalidate: renderingConfig.revalidate
|
|
15416
15900
|
} : void 0;
|
|
15417
15901
|
if (renderingConfig.ppr && pprBypassReason) {
|
|
15418
|
-
emitFarmEvent({
|
|
15419
|
-
|
|
15902
|
+
emitFarmEvent({
|
|
15903
|
+
type: "ppr.shell.bypass",
|
|
15904
|
+
route: pathname,
|
|
15905
|
+
reason: pprBypassReason
|
|
15906
|
+
});
|
|
15907
|
+
emitFarmEvent({
|
|
15908
|
+
type: "cache.bypass",
|
|
15909
|
+
route: pathname,
|
|
15910
|
+
reason: pprBypassReason
|
|
15911
|
+
});
|
|
15420
15912
|
if (pprBypassReason === "refresh") {
|
|
15421
15913
|
pprRefreshRoute = pathname;
|
|
15422
15914
|
emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
|
|
@@ -15424,14 +15916,22 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15424
15916
|
}
|
|
15425
15917
|
if (pprShellOptions) {
|
|
15426
15918
|
const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
|
|
15427
|
-
const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
|
|
15919
|
+
const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
|
|
15428
15920
|
if (cachedPPRShell) {
|
|
15429
|
-
emitFarmEvent({
|
|
15921
|
+
emitFarmEvent({
|
|
15922
|
+
type: "ppr.shell.hit",
|
|
15923
|
+
route: pathname,
|
|
15924
|
+
key: pprCacheKey
|
|
15925
|
+
});
|
|
15430
15926
|
this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
|
|
15431
15927
|
completeRender(res.statusCode || 200, pathname);
|
|
15432
15928
|
return;
|
|
15433
15929
|
}
|
|
15434
|
-
emitFarmEvent({
|
|
15930
|
+
emitFarmEvent({
|
|
15931
|
+
type: "ppr.shell.miss",
|
|
15932
|
+
route: pathname,
|
|
15933
|
+
key: pprCacheKey
|
|
15934
|
+
});
|
|
15435
15935
|
}
|
|
15436
15936
|
let LoadingFallbackComponent = null;
|
|
15437
15937
|
if (loadingBoundaryEntry) {
|
|
@@ -15455,14 +15955,77 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15455
15955
|
);
|
|
15456
15956
|
const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
|
|
15457
15957
|
const isClientComponent = moduleMetadata.isClientComponent;
|
|
15958
|
+
const renderedRouteSlots = await Promise.all(
|
|
15959
|
+
routeSlots.map(async (slot) => {
|
|
15960
|
+
const slotModule = await this.routeManager.loadRouteModule(slot.route.modulePath);
|
|
15961
|
+
if (!slotModule.default) {
|
|
15962
|
+
throw new Error(
|
|
15963
|
+
`Route slot "${slot.name}" module ${slot.route.modulePath} does not export a default component`
|
|
15964
|
+
);
|
|
15965
|
+
}
|
|
15966
|
+
const slotContext = await this.resolveRouteContext({
|
|
15967
|
+
request: currentRequest,
|
|
15968
|
+
rawRequest: req,
|
|
15969
|
+
params: slot.params,
|
|
15970
|
+
search: searchParamsObject,
|
|
15971
|
+
path: pathname
|
|
15972
|
+
});
|
|
15973
|
+
const rawSlotProps = withFarmRouteContext(
|
|
15974
|
+
{
|
|
15975
|
+
params: slot.params,
|
|
15976
|
+
searchParams: Promise.resolve(searchParamsObject),
|
|
15977
|
+
path: pathname,
|
|
15978
|
+
middleware: middlewareMap.size > 0 ? { data: middlewareMap } : void 0,
|
|
15979
|
+
context: pluginExposedContext.size > 0 ? { data: pluginExposedContext } : void 0
|
|
15980
|
+
},
|
|
15981
|
+
slotContext
|
|
15982
|
+
);
|
|
15983
|
+
const slotProps = await parseRouteModuleProps(slotModule, {
|
|
15984
|
+
props: rawSlotProps,
|
|
15985
|
+
search: searchParamsObject,
|
|
15986
|
+
routePath: slot.route.pattern
|
|
15987
|
+
});
|
|
15988
|
+
const metadata = getClientModuleMetadata(slot.route.modulePath, this.config.root);
|
|
15989
|
+
return {
|
|
15990
|
+
...slot,
|
|
15991
|
+
module: slotModule,
|
|
15992
|
+
props: slotProps,
|
|
15993
|
+
isClientComponent: metadata.isClientComponent,
|
|
15994
|
+
shouldHydrate: metadata.shouldHydrate
|
|
15995
|
+
};
|
|
15996
|
+
})
|
|
15997
|
+
);
|
|
15458
15998
|
const shouldHydrate = moduleMetadata.shouldHydrate;
|
|
15999
|
+
const hasHydratableRouteSlots = renderedRouteSlots.some(
|
|
16000
|
+
(slot) => slot.isClientComponent || slot.shouldHydrate
|
|
16001
|
+
);
|
|
15459
16002
|
req.__FARM_PAGE_PATH__ = route.modulePath;
|
|
15460
16003
|
req.__FARM_ROUTE__ = pathname;
|
|
15461
16004
|
req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
|
|
15462
16005
|
req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
|
|
16006
|
+
req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
|
|
15463
16007
|
req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
|
|
15464
16008
|
loadingBoundaryEntry.modulePath.indexOf("/src/app/")
|
|
15465
16009
|
) : null;
|
|
16010
|
+
req.__FARM_ROUTE_SLOTS__ = renderedRouteSlots.map((slot) => ({
|
|
16011
|
+
name: slot.name,
|
|
16012
|
+
ownerPattern: slot.ownerPattern,
|
|
16013
|
+
containerId: slot.containerId,
|
|
16014
|
+
interception: slot.interception,
|
|
16015
|
+
fallback: slot.fallback,
|
|
16016
|
+
modulePath: slot.route.modulePath,
|
|
16017
|
+
isClientComponent: slot.isClientComponent,
|
|
16018
|
+
shouldHydrate: slot.shouldHydrate,
|
|
16019
|
+
props: {
|
|
16020
|
+
params: slot.props.params,
|
|
16021
|
+
search: slot.props.search,
|
|
16022
|
+
searchParams: slot.props.search,
|
|
16023
|
+
..."data" in slot.props ? { data: slot.props.data } : {},
|
|
16024
|
+
...slot.props.__farmCanonicalPath ? { __farmCanonicalPath: slot.props.__farmCanonicalPath } : {},
|
|
16025
|
+
...slot.props.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
16026
|
+
path: pathname
|
|
16027
|
+
}
|
|
16028
|
+
}));
|
|
15466
16029
|
req.__FARM_PROPS__ = {
|
|
15467
16030
|
params: pageProps.params,
|
|
15468
16031
|
search: pageProps.search,
|
|
@@ -15522,12 +16085,32 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15522
16085
|
let wrappedElement = pageElement;
|
|
15523
16086
|
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
15524
16087
|
const layoutModule = layoutModules[i];
|
|
16088
|
+
const layoutEntry = layouts[i];
|
|
15525
16089
|
const LayoutComponent = layoutModule.default;
|
|
16090
|
+
const slotProps = {};
|
|
16091
|
+
for (const slot of renderedRouteSlots) {
|
|
16092
|
+
if (slot.ownerPattern !== layoutEntry.pattern) continue;
|
|
16093
|
+
let slotElement = import_react4.default.createElement(
|
|
16094
|
+
slot.module.default,
|
|
16095
|
+
slot.props
|
|
16096
|
+
);
|
|
16097
|
+
slotElement = import_react4.default.createElement(
|
|
16098
|
+
"div",
|
|
16099
|
+
{
|
|
16100
|
+
id: slot.containerId,
|
|
16101
|
+
"data-farm-route-slot": slot.name,
|
|
16102
|
+
"data-farm-slot-owner": slot.ownerPattern
|
|
16103
|
+
},
|
|
16104
|
+
slotElement
|
|
16105
|
+
);
|
|
16106
|
+
slotProps[slot.name] = slotElement;
|
|
16107
|
+
}
|
|
15526
16108
|
wrappedElement = import_react4.default.createElement(
|
|
15527
16109
|
LayoutComponent,
|
|
15528
16110
|
{
|
|
15529
16111
|
children: wrappedElement,
|
|
15530
|
-
params
|
|
16112
|
+
params,
|
|
16113
|
+
...slotProps
|
|
15531
16114
|
}
|
|
15532
16115
|
);
|
|
15533
16116
|
}
|
|
@@ -15564,7 +16147,10 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15564
16147
|
routeManifest,
|
|
15565
16148
|
captureStaticShell: Boolean(pprShellOptions),
|
|
15566
16149
|
observabilityRoute: pathname,
|
|
15567
|
-
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16150
|
+
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16151
|
+
type: "ppr.suspense.holeDetected",
|
|
16152
|
+
route: pathname
|
|
16153
|
+
}) : void 0,
|
|
15568
16154
|
onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
|
|
15569
16155
|
}
|
|
15570
16156
|
);
|
|
@@ -15612,7 +16198,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15612
16198
|
}
|
|
15613
16199
|
emitFarmEvent({ type: "render.error", route: pathname, error });
|
|
15614
16200
|
if (pprRefreshRoute) {
|
|
15615
|
-
emitFarmEvent({
|
|
16201
|
+
emitFarmEvent({
|
|
16202
|
+
type: "ppr.refresh.error",
|
|
16203
|
+
route: pprRefreshRoute,
|
|
16204
|
+
error
|
|
16205
|
+
});
|
|
15616
16206
|
}
|
|
15617
16207
|
logger.error(`Error rendering page: ${error}`);
|
|
15618
16208
|
if (res.headersSent || res.writableEnded) {
|
|
@@ -15665,7 +16255,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15665
16255
|
if (typeof layoutModule.generateMetadata === "function") {
|
|
15666
16256
|
metadata = mergeMetadata(
|
|
15667
16257
|
metadata,
|
|
15668
|
-
await layoutModule.generateMetadata({
|
|
16258
|
+
await layoutModule.generateMetadata({
|
|
16259
|
+
params: options.pageProps.params
|
|
16260
|
+
})
|
|
15669
16261
|
);
|
|
15670
16262
|
}
|
|
15671
16263
|
}
|
|
@@ -15896,7 +16488,13 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15896
16488
|
clientEntry: "/@farm/client.js",
|
|
15897
16489
|
routes: {},
|
|
15898
16490
|
layouts: {},
|
|
15899
|
-
|
|
16491
|
+
slots: [],
|
|
16492
|
+
sharedAssets: [
|
|
16493
|
+
{
|
|
16494
|
+
tag: "link",
|
|
16495
|
+
attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
|
|
16496
|
+
}
|
|
16497
|
+
]
|
|
15900
16498
|
};
|
|
15901
16499
|
for (const routeEntry of manifest.routes) {
|
|
15902
16500
|
clientManifest.routes[routeEntry.pattern] = {
|
|
@@ -15918,9 +16516,26 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15918
16516
|
assets: []
|
|
15919
16517
|
};
|
|
15920
16518
|
}
|
|
15921
|
-
const
|
|
16519
|
+
for (const slotEntry of manifest.slots ?? []) {
|
|
16520
|
+
clientManifest.slots.push({
|
|
16521
|
+
...slotEntry,
|
|
16522
|
+
preloads: [slotEntry.modulePath],
|
|
16523
|
+
assets: []
|
|
16524
|
+
});
|
|
16525
|
+
}
|
|
16526
|
+
const routeSlotPayload = (req.__FARM_ROUTE_SLOTS__ || []).map(
|
|
16527
|
+
(slot) => ({
|
|
16528
|
+
...slot,
|
|
16529
|
+
modulePath: typeof slot.modulePath === "string" && slot.modulePath.startsWith(this.config.root) ? slot.modulePath.slice(this.config.root.length) : slot.modulePath
|
|
16530
|
+
})
|
|
16531
|
+
);
|
|
16532
|
+
const deferredProps = prepareDeferredData({
|
|
16533
|
+
page: req.__FARM_PROPS__ || {},
|
|
16534
|
+
slots: routeSlotPayload
|
|
16535
|
+
});
|
|
15922
16536
|
const propsScript = `<script>
|
|
15923
|
-
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
|
|
16537
|
+
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
|
|
16538
|
+
window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
|
|
15924
16539
|
window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
|
|
15925
16540
|
window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
|
|
15926
16541
|
window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
|
|
@@ -15933,7 +16548,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
|
|
|
15933
16548
|
window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
|
|
15934
16549
|
${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
|
|
15935
16550
|
</script>`;
|
|
15936
|
-
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true ? createPreHydrationClickQueueScript() : "";
|
|
16551
|
+
const hydrationClickQueueScript = isClientComponent || req.__FARM_SHOULD_HYDRATE__ === true || req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ === true ? createPreHydrationClickQueueScript() : "";
|
|
15937
16552
|
const {
|
|
15938
16553
|
title,
|
|
15939
16554
|
tags: metaTags,
|
|
@@ -16044,7 +16659,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16044
16659
|
didError = true;
|
|
16045
16660
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16046
16661
|
logger.error(`SSR shell error: ${error}`);
|
|
16047
|
-
emitFarmEvent({
|
|
16662
|
+
emitFarmEvent({
|
|
16663
|
+
type: "render.error",
|
|
16664
|
+
route: observabilityRoute,
|
|
16665
|
+
error
|
|
16666
|
+
});
|
|
16048
16667
|
}
|
|
16049
16668
|
if (clearMiddlewareData) {
|
|
16050
16669
|
clearMiddlewareData();
|
|
@@ -16055,7 +16674,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16055
16674
|
didError = true;
|
|
16056
16675
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16057
16676
|
logger.error(`SSR streaming error: ${error}`);
|
|
16058
|
-
emitFarmEvent({
|
|
16677
|
+
emitFarmEvent({
|
|
16678
|
+
type: "render.error",
|
|
16679
|
+
route: observabilityRoute,
|
|
16680
|
+
error
|
|
16681
|
+
});
|
|
16059
16682
|
}
|
|
16060
16683
|
}
|
|
16061
16684
|
});
|
|
@@ -16231,6 +16854,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16231
16854
|
logger.info("Initializing Farm.js application...");
|
|
16232
16855
|
}
|
|
16233
16856
|
await initStorage(this.config.storage);
|
|
16857
|
+
await configureFarmCache(this.config.cache);
|
|
16234
16858
|
await this.i18nRuntime.initialize();
|
|
16235
16859
|
await this.verifyAppStructure();
|
|
16236
16860
|
await this.routeManager.discoverRoutes();
|
|
@@ -16262,6 +16886,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16262
16886
|
preset: config.preset ?? "node-server",
|
|
16263
16887
|
deploy: config.deploy || {},
|
|
16264
16888
|
storage: config.storage || {},
|
|
16889
|
+
cache: config.cache || {},
|
|
16265
16890
|
integrations: config.integrations || {},
|
|
16266
16891
|
plugins: config.plugins || [],
|
|
16267
16892
|
migrations: config.migrations || { commands: [] },
|
|
@@ -16736,7 +17361,7 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
16736
17361
|
});
|
|
16737
17362
|
let body = void 0;
|
|
16738
17363
|
if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
|
|
16739
|
-
body = await
|
|
17364
|
+
body = await readRequestBody(request);
|
|
16740
17365
|
}
|
|
16741
17366
|
const headers = Object.fromEntries(request.headers.entries());
|
|
16742
17367
|
const types = endpoint.__types || {};
|
|
@@ -16840,17 +17465,50 @@ function isFarmContextHandler(endpoint) {
|
|
|
16840
17465
|
return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
|
|
16841
17466
|
}
|
|
16842
17467
|
__name(isFarmContextHandler, "isFarmContextHandler");
|
|
16843
|
-
async function
|
|
17468
|
+
async function readRequestBody(request) {
|
|
17469
|
+
const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
16844
17470
|
try {
|
|
17471
|
+
if (contentType === "multipart/form-data") {
|
|
17472
|
+
return formDataToObject(await request.clone().formData());
|
|
17473
|
+
}
|
|
16845
17474
|
const text2 = await request.clone().text();
|
|
16846
|
-
if (text2)
|
|
17475
|
+
if (!text2) return void 0;
|
|
17476
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
17477
|
+
return searchParamsToObject2(new URLSearchParams(text2));
|
|
17478
|
+
}
|
|
17479
|
+
if (contentType === "application/json" || contentType?.endsWith("+json")) {
|
|
16847
17480
|
return JSON.parse(text2);
|
|
16848
17481
|
}
|
|
17482
|
+
return JSON.parse(text2);
|
|
16849
17483
|
} catch {
|
|
16850
17484
|
}
|
|
16851
17485
|
return void 0;
|
|
16852
17486
|
}
|
|
16853
|
-
__name(
|
|
17487
|
+
__name(readRequestBody, "readRequestBody");
|
|
17488
|
+
function formDataToObject(formData) {
|
|
17489
|
+
return entriesToObject(formData.entries());
|
|
17490
|
+
}
|
|
17491
|
+
__name(formDataToObject, "formDataToObject");
|
|
17492
|
+
function searchParamsToObject2(searchParams) {
|
|
17493
|
+
return entriesToObject(searchParams.entries());
|
|
17494
|
+
}
|
|
17495
|
+
__name(searchParamsToObject2, "searchParamsToObject");
|
|
17496
|
+
function entriesToObject(entries) {
|
|
17497
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
17498
|
+
for (const [key, value] of entries) {
|
|
17499
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
17500
|
+
const current = output[key];
|
|
17501
|
+
if (current === void 0) {
|
|
17502
|
+
output[key] = value;
|
|
17503
|
+
} else if (Array.isArray(current)) {
|
|
17504
|
+
current.push(value);
|
|
17505
|
+
} else {
|
|
17506
|
+
output[key] = [current, value];
|
|
17507
|
+
}
|
|
17508
|
+
}
|
|
17509
|
+
return output;
|
|
17510
|
+
}
|
|
17511
|
+
__name(entriesToObject, "entriesToObject");
|
|
16854
17512
|
function validateInput(schema, value, error) {
|
|
16855
17513
|
if (!schema || typeof schema.parse !== "function") {
|
|
16856
17514
|
return value;
|
|
@@ -18005,6 +18663,7 @@ async function generateRouteTypes(options) {
|
|
|
18005
18663
|
absolute: false
|
|
18006
18664
|
});
|
|
18007
18665
|
for (const file of pageFiles) {
|
|
18666
|
+
if (parseRouteSlotFile(file)) continue;
|
|
18008
18667
|
const route = parseRoutePath(file);
|
|
18009
18668
|
if (route.type === "page") {
|
|
18010
18669
|
const pattern = createRoutePattern(route);
|
|
@@ -19001,7 +19660,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19001
19660
|
}, "isProgrammaticRouteSourceFile");
|
|
19002
19661
|
const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
|
|
19003
19662
|
const normalized = file.replace(/\\/g, "/");
|
|
19004
|
-
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
19663
|
+
return appDirSlugs.some((appDir) => normalized.startsWith(`${appDir}/`)) && /\/(?:page|default|layout|loading|error|middleware|route)\.(?:ts|tsx|js|jsx|md|mdx)$|\/(?:opengraph-image|twitter-image)(?:\.(?:ts|tsx|js|jsx|png|jpg|jpeg|gif|webp)|\.alt\.txt)$/.test(
|
|
19005
19664
|
normalized
|
|
19006
19665
|
);
|
|
19007
19666
|
}, "isAppRuntimeFile");
|
|
@@ -19692,7 +20351,10 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19692
20351
|
method: req.method || "GET"
|
|
19693
20352
|
});
|
|
19694
20353
|
}
|
|
19695
|
-
const
|
|
20354
|
+
const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
|
|
20355
|
+
const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
|
|
20356
|
+
interceptFrom: interceptFromHeader
|
|
20357
|
+
});
|
|
19696
20358
|
if (pm) {
|
|
19697
20359
|
await pm.runHookParallel("afterRouteMatch", {
|
|
19698
20360
|
pathname: targetPath,
|
|
@@ -19708,7 +20370,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19708
20370
|
res.end(JSON.stringify({ error: "Route not found" }));
|
|
19709
20371
|
return;
|
|
19710
20372
|
}
|
|
19711
|
-
const { route, params, layouts } = match;
|
|
20373
|
+
const { route, params, layouts, slots } = match;
|
|
19712
20374
|
if (!route) {
|
|
19713
20375
|
res.statusCode = 404;
|
|
19714
20376
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -19763,6 +20425,54 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19763
20425
|
search: searchParams,
|
|
19764
20426
|
routePath: route.pattern
|
|
19765
20427
|
});
|
|
20428
|
+
const routeSlots = await Promise.all(
|
|
20429
|
+
slots.map(async (slot) => {
|
|
20430
|
+
const slotModule = await routeManager3.loadRouteModule(slot.route.modulePath);
|
|
20431
|
+
const slotMetadata = getClientModuleMetadata(
|
|
20432
|
+
slot.route.modulePath,
|
|
20433
|
+
server.config.root
|
|
20434
|
+
);
|
|
20435
|
+
const slotContext = await resolveFarmRouteContext(farmApp.getConfig(), {
|
|
20436
|
+
request,
|
|
20437
|
+
params: slot.params,
|
|
20438
|
+
search: searchParams,
|
|
20439
|
+
path: targetUrl.pathname
|
|
20440
|
+
});
|
|
20441
|
+
const slotProps = await parseRouteModuleProps2(slotModule, {
|
|
20442
|
+
props: withFarmRouteContext(
|
|
20443
|
+
{
|
|
20444
|
+
params: slot.params,
|
|
20445
|
+
searchParams: Promise.resolve(searchParams),
|
|
20446
|
+
path: targetUrl.pathname
|
|
20447
|
+
},
|
|
20448
|
+
slotContext
|
|
20449
|
+
),
|
|
20450
|
+
search: searchParams,
|
|
20451
|
+
routePath: slot.route.pattern
|
|
20452
|
+
});
|
|
20453
|
+
return {
|
|
20454
|
+
name: slot.name,
|
|
20455
|
+
ownerPattern: slot.ownerPattern,
|
|
20456
|
+
containerId: slot.containerId,
|
|
20457
|
+
interception: slot.interception,
|
|
20458
|
+
fallback: slot.fallback,
|
|
20459
|
+
modulePath: slot.route.modulePath,
|
|
20460
|
+
isClientComponent: slotMetadata.isClientComponent,
|
|
20461
|
+
shouldHydrate: slotMetadata.shouldHydrate,
|
|
20462
|
+
props: {
|
|
20463
|
+
params: slotProps.params,
|
|
20464
|
+
search: slotProps.search,
|
|
20465
|
+
searchParams: slotProps.search,
|
|
20466
|
+
..."data" in slotProps ? { data: slotProps.data } : {},
|
|
20467
|
+
...slotProps.__farmCanonicalPath ? {
|
|
20468
|
+
__farmCanonicalPath: slotProps.__farmCanonicalPath
|
|
20469
|
+
} : {},
|
|
20470
|
+
...slotProps.__farmRoutePropsResolved ? { __farmRoutePropsResolved: true } : {},
|
|
20471
|
+
path: targetUrl.pathname
|
|
20472
|
+
}
|
|
20473
|
+
};
|
|
20474
|
+
})
|
|
20475
|
+
);
|
|
19766
20476
|
const projectRoot = server.config.root;
|
|
19767
20477
|
const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
|
|
19768
20478
|
if (absolutePath.startsWith(projectRoot)) {
|
|
@@ -19783,13 +20493,21 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19783
20493
|
},
|
|
19784
20494
|
canonicalPath: routeProps.__farmCanonicalPath,
|
|
19785
20495
|
modulePath: toUrlPath(route.modulePath),
|
|
19786
|
-
isClientComponent,
|
|
19787
|
-
shouldHydrate,
|
|
20496
|
+
isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
|
|
20497
|
+
shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
|
|
19788
20498
|
metadata: {
|
|
19789
20499
|
title: mergedMetadata.title,
|
|
19790
20500
|
description: mergedMetadata.description
|
|
19791
20501
|
},
|
|
19792
20502
|
layoutModules: layouts.map((l) => toUrlPath(l.modulePath)),
|
|
20503
|
+
routeSlots: routeSlots.map((slot) => ({
|
|
20504
|
+
...slot,
|
|
20505
|
+
modulePath: toUrlPath(slot.modulePath)
|
|
20506
|
+
})),
|
|
20507
|
+
interception: routeSlots.some((slot) => slot.interception) ? {
|
|
20508
|
+
from: interceptFromHeader,
|
|
20509
|
+
slots: routeSlots.filter((slot) => slot.interception).map((slot) => slot.name)
|
|
20510
|
+
} : void 0,
|
|
19793
20511
|
i18n: getFarmI18nClientSnapshot()
|
|
19794
20512
|
};
|
|
19795
20513
|
await sendWebResponse(
|
|
@@ -20125,6 +20843,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20125
20843
|
export const getManifest = () => ({
|
|
20126
20844
|
routes: {},
|
|
20127
20845
|
layouts: {},
|
|
20846
|
+
slots: [],
|
|
20128
20847
|
clientEntry: "/@farm/client.js",
|
|
20129
20848
|
sharedAssets: []
|
|
20130
20849
|
});
|
|
@@ -20135,6 +20854,7 @@ export const getManifest = () => ({
|
|
|
20135
20854
|
clientEntry: "/@farm/client.js",
|
|
20136
20855
|
routes: {},
|
|
20137
20856
|
layouts: {},
|
|
20857
|
+
slots: [],
|
|
20138
20858
|
sharedAssets: [
|
|
20139
20859
|
{
|
|
20140
20860
|
tag: "link",
|
|
@@ -20164,6 +20884,13 @@ export const getManifest = () => ({
|
|
|
20164
20884
|
assets: []
|
|
20165
20885
|
};
|
|
20166
20886
|
}
|
|
20887
|
+
for (const slot of manifest.slots) {
|
|
20888
|
+
fullManifest.slots.push({
|
|
20889
|
+
...slot,
|
|
20890
|
+
preloads: [slot.modulePath],
|
|
20891
|
+
assets: []
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20167
20894
|
return `
|
|
20168
20895
|
// Auto-generated manifest for SPA navigation (TanStack Start pattern)
|
|
20169
20896
|
// This manifest is inlined in the server bundle - no file on disk
|
|
@@ -20806,7 +21533,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
|
|
|
20806
21533
|
|
|
20807
21534
|
// Get manifest from window (inlined by server in HTML)
|
|
20808
21535
|
// Fallback to empty manifest if not available yet
|
|
20809
|
-
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
|
|
21536
|
+
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
|
|
20810
21537
|
|
|
20811
21538
|
// ====== CLIENT-SIDE ROUTE MATCHING ======
|
|
20812
21539
|
// Matches URL to route using manifest (no server request!)
|
|
@@ -21145,6 +21872,9 @@ let LayoutComponent = null;
|
|
|
21145
21872
|
|
|
21146
21873
|
// Track if we've taken over rendering from SSR
|
|
21147
21874
|
let hasClientTakenOver = false;
|
|
21875
|
+
const routeSlotRoots = new Map();
|
|
21876
|
+
const routeSlotDefinitions = new Map();
|
|
21877
|
+
let activeRouteInterception = null;
|
|
21148
21878
|
|
|
21149
21879
|
function normalizeServerProps(rawProps) {
|
|
21150
21880
|
const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
|
|
@@ -21157,6 +21887,123 @@ function normalizeServerProps(rawProps) {
|
|
|
21157
21887
|
return props;
|
|
21158
21888
|
}
|
|
21159
21889
|
|
|
21890
|
+
function getRouteSlotKey(slot) {
|
|
21891
|
+
return slot.ownerPattern + ':' + slot.name;
|
|
21892
|
+
}
|
|
21893
|
+
|
|
21894
|
+
async function renderRouteSlot(slot, mode = 'render') {
|
|
21895
|
+
const container = document.getElementById(slot.containerId);
|
|
21896
|
+
if (!container || !slot.modulePath) return false;
|
|
21897
|
+
if (mode === 'intercept' && !slot.isClientComponent && !slot.shouldHydrate) {
|
|
21898
|
+
return false;
|
|
21899
|
+
}
|
|
21900
|
+
|
|
21901
|
+
let slotModule = pageModuleCache.get(slot.modulePath);
|
|
21902
|
+
if (!slotModule) {
|
|
21903
|
+
slotModule = await import(/* @vite-ignore */ slot.modulePath);
|
|
21904
|
+
pageModuleCache.set(slot.modulePath, slotModule);
|
|
21905
|
+
}
|
|
21906
|
+
const SlotComponent = slotModule?.default;
|
|
21907
|
+
if (!SlotComponent) return false;
|
|
21908
|
+
|
|
21909
|
+
const props = reviveDeferredData(
|
|
21910
|
+
normalizeServerProps(slot.props || {}),
|
|
21911
|
+
window.__FARM_DEFERRED_DATA__ || {},
|
|
21912
|
+
);
|
|
21913
|
+
const element = wrapWithIntegrationProviders(
|
|
21914
|
+
React.createElement(SlotComponent, props),
|
|
21915
|
+
);
|
|
21916
|
+
const key = getRouteSlotKey(slot);
|
|
21917
|
+
const existingRoot = routeSlotRoots.get(key);
|
|
21918
|
+
|
|
21919
|
+
if (mode === 'hydrate') {
|
|
21920
|
+
if (existingRoot) return true;
|
|
21921
|
+
const root = hydrateRoot(container, element);
|
|
21922
|
+
routeSlotRoots.set(key, root);
|
|
21923
|
+
} else {
|
|
21924
|
+
if (existingRoot) {
|
|
21925
|
+
try { existingRoot.unmount(); } catch (error) {}
|
|
21926
|
+
}
|
|
21927
|
+
const root = createRoot(container);
|
|
21928
|
+
root.render(element);
|
|
21929
|
+
routeSlotRoots.set(key, root);
|
|
21930
|
+
}
|
|
21931
|
+
|
|
21932
|
+
routeSlotDefinitions.set(key, slot);
|
|
21933
|
+
return true;
|
|
21934
|
+
}
|
|
21935
|
+
|
|
21936
|
+
async function hydrateInitialRouteSlots() {
|
|
21937
|
+
const slots = Array.isArray(window.__FARM_ROUTE_SLOTS__)
|
|
21938
|
+
? window.__FARM_ROUTE_SLOTS__
|
|
21939
|
+
: [];
|
|
21940
|
+
let hydrated = false;
|
|
21941
|
+
|
|
21942
|
+
for (const slot of slots) {
|
|
21943
|
+
routeSlotDefinitions.set(getRouteSlotKey(slot), slot);
|
|
21944
|
+
if (!slot.isClientComponent && !slot.shouldHydrate) continue;
|
|
21945
|
+
try {
|
|
21946
|
+
hydrated = (await renderRouteSlot(slot, 'hydrate')) || hydrated;
|
|
21947
|
+
} catch (error) {
|
|
21948
|
+
console.warn('[Farm.js] Could not hydrate route slot:', slot.name, error);
|
|
21949
|
+
}
|
|
21950
|
+
}
|
|
21951
|
+
|
|
21952
|
+
return hydrated;
|
|
21953
|
+
}
|
|
21954
|
+
|
|
21955
|
+
async function renderRouteInterception(pageData) {
|
|
21956
|
+
const slots = Array.isArray(pageData.routeSlots)
|
|
21957
|
+
? pageData.routeSlots.filter((slot) => slot.interception)
|
|
21958
|
+
: [];
|
|
21959
|
+
if (!pageData.interception || slots.length === 0) return false;
|
|
21960
|
+
|
|
21961
|
+
const previous = new Map();
|
|
21962
|
+
for (const slot of slots) {
|
|
21963
|
+
const key = getRouteSlotKey(slot);
|
|
21964
|
+
previous.set(key, routeSlotDefinitions.get(key) || null);
|
|
21965
|
+
if (!(await renderRouteSlot(slot, 'intercept'))) {
|
|
21966
|
+
return false;
|
|
21967
|
+
}
|
|
21968
|
+
}
|
|
21969
|
+
|
|
21970
|
+
activeRouteInterception = {
|
|
21971
|
+
from: pageData.interception.from,
|
|
21972
|
+
slots,
|
|
21973
|
+
previous,
|
|
21974
|
+
};
|
|
21975
|
+
return true;
|
|
21976
|
+
}
|
|
21977
|
+
|
|
21978
|
+
async function clearRouteInterception(destination) {
|
|
21979
|
+
if (!activeRouteInterception) return false;
|
|
21980
|
+
const active = activeRouteInterception;
|
|
21981
|
+
activeRouteInterception = null;
|
|
21982
|
+
|
|
21983
|
+
for (const slot of active.slots) {
|
|
21984
|
+
const key = getRouteSlotKey(slot);
|
|
21985
|
+
const root = routeSlotRoots.get(key);
|
|
21986
|
+
if (root) {
|
|
21987
|
+
try { root.unmount(); } catch (error) {}
|
|
21988
|
+
routeSlotRoots.delete(key);
|
|
21989
|
+
}
|
|
21990
|
+
|
|
21991
|
+
const previous = active.previous.get(key);
|
|
21992
|
+
if (previous && (previous.isClientComponent || previous.shouldHydrate)) {
|
|
21993
|
+
await renderRouteSlot(previous, 'render');
|
|
21994
|
+
} else {
|
|
21995
|
+
const container = document.getElementById(slot.containerId);
|
|
21996
|
+
if (container) container.replaceChildren();
|
|
21997
|
+
if (previous) routeSlotDefinitions.set(key, previous);
|
|
21998
|
+
else routeSlotDefinitions.delete(key);
|
|
21999
|
+
}
|
|
22000
|
+
}
|
|
22001
|
+
|
|
22002
|
+
if (!active.from) return false;
|
|
22003
|
+
const background = new URL(active.from, window.location.origin);
|
|
22004
|
+
return destination === background.pathname + background.search;
|
|
22005
|
+
}
|
|
22006
|
+
|
|
21160
22007
|
function applyCanonicalPathFromProps(props) {
|
|
21161
22008
|
const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
|
|
21162
22009
|
? props.__farmCanonicalPath
|
|
@@ -21391,6 +22238,17 @@ async function tryHydrateImportedPage(
|
|
|
21391
22238
|
async function renderPage(pageData) {
|
|
21392
22239
|
const container = document.getElementById('root');
|
|
21393
22240
|
if (!container) return;
|
|
22241
|
+
const destination = window.location.pathname + window.location.search;
|
|
22242
|
+
|
|
22243
|
+
if (pageData.interception) {
|
|
22244
|
+
if (await renderRouteInterception(pageData)) return;
|
|
22245
|
+
window.location.assign(destination);
|
|
22246
|
+
return;
|
|
22247
|
+
}
|
|
22248
|
+
|
|
22249
|
+
if (await clearRouteInterception(destination)) {
|
|
22250
|
+
return;
|
|
22251
|
+
}
|
|
21394
22252
|
|
|
21395
22253
|
const route = {
|
|
21396
22254
|
modulePath: pageData.modulePath,
|
|
@@ -21619,7 +22477,9 @@ async function hydrate() {
|
|
|
21619
22477
|
window.__FARM_SHOULD_HYDRATE__ === true ||
|
|
21620
22478
|
isClientComponent ||
|
|
21621
22479
|
await moduleLooksClient(modulePath);
|
|
22480
|
+
const hydratedSlots = await hydrateInitialRouteSlots();
|
|
21622
22481
|
if (!shouldHydrate) {
|
|
22482
|
+
if (hydratedSlots) replayPreHydrationClicks();
|
|
21623
22483
|
console.log('[Farm.js] Server component - SPA router ready')
|
|
21624
22484
|
return
|
|
21625
22485
|
}
|