@farm.js/core 0.1.0-beta.3 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-5QH4IKY3.mjs → chunk-3U3ZUQAQ.mjs} +2 -2
- 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-OHC6VCDI.mjs → chunk-AJWRO5WE.mjs} +521 -42
- 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-XJSHJN4M.mjs → chunk-AOBXKNS5.mjs} +593 -49
- package/dist/chunk-AOBXKNS5.mjs.map +1 -0
- package/dist/{chunk-CSU4KJJF.mjs → chunk-C2ROET2V.mjs} +2 -2
- package/dist/{chunk-BIOIOWXZ.mjs → chunk-HNIQFZKB.mjs} +2 -2
- 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-SHRJG6OG.mjs → chunk-RBRLLZL5.mjs} +18 -3
- package/dist/chunk-RBRLLZL5.mjs.map +1 -0
- package/dist/{chunk-MH6FKW2I.mjs → chunk-SADGIRS2.mjs} +3 -3
- 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-5FW6PQ3J.mjs → chunk-VVKWFZAH.mjs} +41 -16
- package/dist/chunk-VVKWFZAH.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-JNYVN7YP.mjs → chunk-W4UIVMVI.mjs} +2 -2
- package/dist/{chunk-JNYVN7YP.mjs.map → chunk-W4UIVMVI.mjs.map} +1 -1
- 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 +70 -4
- package/dist/client.d.ts +70 -4
- 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 +2112 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +12 -11
- package/dist/index.d.ts +12 -11
- 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 +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 +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-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-3U3ZUQAQ.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-MH6FKW2I.mjs.map → chunk-SADGIRS2.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/vite.cjs
CHANGED
|
@@ -1767,7 +1767,8 @@ var init_route_rules = __esm({
|
|
|
1767
1767
|
// src/cache-invalidation.ts
|
|
1768
1768
|
function getFarmCacheInvalidationState() {
|
|
1769
1769
|
return globalState[FARM_CACHE_INVALIDATION_STATE] ?? (globalState[FARM_CACHE_INVALIDATION_STATE] = {
|
|
1770
|
-
listeners: /* @__PURE__ */ new Set()
|
|
1770
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1771
|
+
taskListeners: /* @__PURE__ */ new Set()
|
|
1771
1772
|
});
|
|
1772
1773
|
}
|
|
1773
1774
|
function encodeFarmCacheInvalidations(keys) {
|
|
@@ -1793,6 +1794,11 @@ function subscribeFarmCacheInvalidation(listener) {
|
|
|
1793
1794
|
state.listeners.add(listener);
|
|
1794
1795
|
return () => state.listeners.delete(listener);
|
|
1795
1796
|
}
|
|
1797
|
+
function subscribeFarmCacheTask(listener) {
|
|
1798
|
+
const state = getFarmCacheInvalidationState();
|
|
1799
|
+
state.taskListeners.add(listener);
|
|
1800
|
+
return () => state.taskListeners.delete(listener);
|
|
1801
|
+
}
|
|
1796
1802
|
var FARM_CACHE_INVALIDATION_HEADER, FARM_CACHE_INVALIDATION_STATE, globalState;
|
|
1797
1803
|
var init_cache_invalidation = __esm({
|
|
1798
1804
|
"src/cache-invalidation.ts"() {
|
|
@@ -1804,6 +1810,7 @@ var init_cache_invalidation = __esm({
|
|
|
1804
1810
|
__name(encodeFarmCacheInvalidations, "encodeFarmCacheInvalidations");
|
|
1805
1811
|
__name(decodeFarmCacheInvalidations, "decodeFarmCacheInvalidations");
|
|
1806
1812
|
__name(subscribeFarmCacheInvalidation, "subscribeFarmCacheInvalidation");
|
|
1813
|
+
__name(subscribeFarmCacheTask, "subscribeFarmCacheTask");
|
|
1807
1814
|
}
|
|
1808
1815
|
});
|
|
1809
1816
|
|
|
@@ -1907,6 +1914,9 @@ var init_server_action_security = __esm({
|
|
|
1907
1914
|
subscribeFarmCacheInvalidation((key) => {
|
|
1908
1915
|
getServerActionExecutionContext()?.invalidations.add(key);
|
|
1909
1916
|
});
|
|
1917
|
+
subscribeFarmCacheTask((task) => {
|
|
1918
|
+
getServerActionExecutionContext()?.cacheTasks.add(task);
|
|
1919
|
+
});
|
|
1910
1920
|
__name(getServerActionStorage, "getServerActionStorage");
|
|
1911
1921
|
__name(parseBodySizeLimit, "parseBodySizeLimit");
|
|
1912
1922
|
__name(normalizeAllowedOriginPattern, "normalizeAllowedOriginPattern");
|
|
@@ -12075,11 +12085,51 @@ __name(getActiveFarmI18nSnapshot, "getActiveFarmI18nSnapshot");
|
|
|
12075
12085
|
// src/cache.ts
|
|
12076
12086
|
init_cache_invalidation();
|
|
12077
12087
|
var _FarmDataCache = class _FarmDataCache {
|
|
12078
|
-
constructor() {
|
|
12088
|
+
constructor(config = {}) {
|
|
12079
12089
|
this.entries = /* @__PURE__ */ new Map();
|
|
12080
12090
|
this.inflight = /* @__PURE__ */ new Map();
|
|
12081
12091
|
this.invalidatedTagVersions = /* @__PURE__ */ new Map();
|
|
12082
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;
|
|
12083
12133
|
}
|
|
12084
12134
|
get size() {
|
|
12085
12135
|
return this.entries.size;
|
|
@@ -12115,6 +12165,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12115
12165
|
});
|
|
12116
12166
|
return this.toPublicEntry(entry);
|
|
12117
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
|
+
}
|
|
12118
12207
|
set(key, value, options = {}) {
|
|
12119
12208
|
const tags = /* @__PURE__ */ new Set();
|
|
12120
12209
|
for (const tag of options.tags ?? []) {
|
|
@@ -12127,6 +12216,7 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12127
12216
|
key,
|
|
12128
12217
|
value,
|
|
12129
12218
|
tags,
|
|
12219
|
+
tagVersions: void 0,
|
|
12130
12220
|
createdAt: options.createdAt ?? Date.now(),
|
|
12131
12221
|
createdVersion: ++this.version,
|
|
12132
12222
|
revalidate: normalizeRevalidate(options.revalidate)
|
|
@@ -12140,11 +12230,45 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12140
12230
|
});
|
|
12141
12231
|
return this.toPublicEntry(entry);
|
|
12142
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
|
+
}
|
|
12143
12259
|
delete(key) {
|
|
12144
12260
|
const deleted = this.entries.delete(key);
|
|
12145
12261
|
emitFarmEvent({ type: "cache.delete", key, deleted });
|
|
12146
12262
|
return deleted;
|
|
12147
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
|
+
}
|
|
12148
12272
|
clear() {
|
|
12149
12273
|
const count = this.entries.size;
|
|
12150
12274
|
this.entries.clear();
|
|
@@ -12153,6 +12277,10 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12153
12277
|
this.version = 0;
|
|
12154
12278
|
emitFarmEvent({ type: "cache.clear", count });
|
|
12155
12279
|
}
|
|
12280
|
+
async clearAsync() {
|
|
12281
|
+
this.clear();
|
|
12282
|
+
await this.adapter?.clear?.();
|
|
12283
|
+
}
|
|
12156
12284
|
isStale(entry, now = Date.now()) {
|
|
12157
12285
|
if (typeof entry.revalidate === "number" && entry.revalidate > 0 && now - entry.createdAt >= entry.revalidate * 1e3) {
|
|
12158
12286
|
return true;
|
|
@@ -12165,6 +12293,12 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12165
12293
|
}
|
|
12166
12294
|
return false;
|
|
12167
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
|
+
}
|
|
12168
12302
|
revalidateTag(tag, options = {}) {
|
|
12169
12303
|
const normalized = normalizeCacheTag(tag);
|
|
12170
12304
|
const count = this.invalidateTag(normalized);
|
|
@@ -12173,6 +12307,15 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12173
12307
|
);
|
|
12174
12308
|
return count;
|
|
12175
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
|
+
}
|
|
12176
12319
|
revalidatePath(routePath) {
|
|
12177
12320
|
const normalizedPath = normalizeRevalidatePath(routePath);
|
|
12178
12321
|
const pathTag = createPathCacheTag(normalizedPath);
|
|
@@ -12189,8 +12332,25 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12189
12332
|
}
|
|
12190
12333
|
return count;
|
|
12191
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
|
+
}
|
|
12192
12352
|
async getOrSet(key, producer, options = {}) {
|
|
12193
|
-
const cached = this.
|
|
12353
|
+
const cached = await this.getEntryAsync(key);
|
|
12194
12354
|
if (cached) {
|
|
12195
12355
|
return cached.value;
|
|
12196
12356
|
}
|
|
@@ -12199,10 +12359,8 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12199
12359
|
emitFarmEvent({ type: "cache.dedupe", key });
|
|
12200
12360
|
return inflight;
|
|
12201
12361
|
}
|
|
12202
|
-
const
|
|
12203
|
-
|
|
12204
|
-
return value;
|
|
12205
|
-
}).catch((error) => {
|
|
12362
|
+
const tags = Array.from(normalizeCacheOptionsTags(options));
|
|
12363
|
+
const promise = this.fillCacheEntry(key, producer, options, tags).catch((error) => {
|
|
12206
12364
|
emitFarmEvent({ type: "cache.error", key, operation: "set", error });
|
|
12207
12365
|
throw error;
|
|
12208
12366
|
}).finally(() => {
|
|
@@ -12211,6 +12369,40 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12211
12369
|
this.inflight.set(key, promise);
|
|
12212
12370
|
return promise;
|
|
12213
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
|
+
}
|
|
12214
12406
|
countEntriesForTag(tag) {
|
|
12215
12407
|
let count = 0;
|
|
12216
12408
|
for (const entry of this.entries.values()) {
|
|
@@ -12238,11 +12430,53 @@ var _FarmDataCache = class _FarmDataCache {
|
|
|
12238
12430
|
key: entry.key,
|
|
12239
12431
|
value: entry.value,
|
|
12240
12432
|
tags: Array.from(entry.tags),
|
|
12433
|
+
tagVersions: entry.tagVersions,
|
|
12241
12434
|
createdAt: entry.createdAt,
|
|
12242
12435
|
createdVersion: entry.createdVersion,
|
|
12243
12436
|
revalidate: entry.revalidate
|
|
12244
12437
|
};
|
|
12245
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
|
+
}
|
|
12246
12480
|
};
|
|
12247
12481
|
__name(_FarmDataCache, "FarmDataCache");
|
|
12248
12482
|
var FarmDataCache = _FarmDataCache;
|
|
@@ -12255,6 +12489,10 @@ function getFarmDataCache() {
|
|
|
12255
12489
|
return sharedFarmDataCache;
|
|
12256
12490
|
}
|
|
12257
12491
|
__name(getFarmDataCache, "getFarmDataCache");
|
|
12492
|
+
function configureFarmCache(config) {
|
|
12493
|
+
sharedFarmDataCache.configure(config);
|
|
12494
|
+
}
|
|
12495
|
+
__name(configureFarmCache, "configureFarmCache");
|
|
12258
12496
|
function createPathCacheTag(routePath) {
|
|
12259
12497
|
return `path:${normalizeRevalidatePath(routePath)}`;
|
|
12260
12498
|
}
|
|
@@ -12315,6 +12553,52 @@ function normalizeCacheTag(tag) {
|
|
|
12315
12553
|
return normalized;
|
|
12316
12554
|
}
|
|
12317
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");
|
|
12318
12602
|
function getFunctionCacheIdentity(fn) {
|
|
12319
12603
|
if (fn.name) {
|
|
12320
12604
|
return `name:${fn.name}`;
|
|
@@ -13455,6 +13739,76 @@ function normalizePathname(pathname) {
|
|
|
13455
13739
|
}
|
|
13456
13740
|
__name(normalizePathname, "normalizePathname");
|
|
13457
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
|
+
|
|
13458
13812
|
// src/routing/route-manager.ts
|
|
13459
13813
|
function routeSpecificity(entry) {
|
|
13460
13814
|
return entry.route.segments.reduce((score, segment) => {
|
|
@@ -13468,6 +13822,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13468
13822
|
constructor(config, viteServer) {
|
|
13469
13823
|
this.routes = /* @__PURE__ */ new Map();
|
|
13470
13824
|
this.layouts = /* @__PURE__ */ new Map();
|
|
13825
|
+
this.routeSlots = /* @__PURE__ */ new Map();
|
|
13471
13826
|
this.loadings = /* @__PURE__ */ new Map();
|
|
13472
13827
|
this.errors = /* @__PURE__ */ new Map();
|
|
13473
13828
|
this.metadataImages = /* @__PURE__ */ new Map();
|
|
@@ -13483,6 +13838,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13483
13838
|
async discoverRoutes() {
|
|
13484
13839
|
this.routes.clear();
|
|
13485
13840
|
this.layouts.clear();
|
|
13841
|
+
this.routeSlots.clear();
|
|
13486
13842
|
this.loadings.clear();
|
|
13487
13843
|
this.errors.clear();
|
|
13488
13844
|
this.metadataImages.clear();
|
|
@@ -13493,6 +13849,13 @@ var _RouteManager = class _RouteManager {
|
|
|
13493
13849
|
await this.discoverFileRoutes(source);
|
|
13494
13850
|
await this.discoverProgrammaticRoutes(source);
|
|
13495
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
|
+
}
|
|
13496
13859
|
this.routes = new Map(
|
|
13497
13860
|
Array.from(this.routes.entries()).sort(
|
|
13498
13861
|
([, left], [, right]) => routeSpecificity(right) - routeSpecificity(left)
|
|
@@ -13508,7 +13871,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13508
13871
|
/**
|
|
13509
13872
|
* Find matching route for a given URL path
|
|
13510
13873
|
*/
|
|
13511
|
-
matchRoute(pathname) {
|
|
13874
|
+
matchRoute(pathname, options = {}) {
|
|
13512
13875
|
const routePathname = this.toRoutePathname(pathname);
|
|
13513
13876
|
const normalizedPath = routePathname === "/" ? "/" : routePathname.replace(/\/$/, "");
|
|
13514
13877
|
let matchedRoute = null;
|
|
@@ -13522,10 +13885,12 @@ var _RouteManager = class _RouteManager {
|
|
|
13522
13885
|
}
|
|
13523
13886
|
}
|
|
13524
13887
|
const layouts = this.findMatchingLayouts(normalizedPath);
|
|
13888
|
+
const slots = this.findMatchingRouteSlots(normalizedPath, options.interceptFrom);
|
|
13525
13889
|
return {
|
|
13526
13890
|
route: matchedRoute,
|
|
13527
13891
|
params,
|
|
13528
|
-
layouts
|
|
13892
|
+
layouts,
|
|
13893
|
+
slots
|
|
13529
13894
|
};
|
|
13530
13895
|
}
|
|
13531
13896
|
/**
|
|
@@ -13540,6 +13905,9 @@ var _RouteManager = class _RouteManager {
|
|
|
13540
13905
|
getLayouts() {
|
|
13541
13906
|
return new Map(this.layouts);
|
|
13542
13907
|
}
|
|
13908
|
+
getRouteSlots() {
|
|
13909
|
+
return new Map(this.routeSlots);
|
|
13910
|
+
}
|
|
13543
13911
|
/** Resolve route rules, inherited layouts, and the page export in precedence order. */
|
|
13544
13912
|
async resolveRouteRuntimeConfig(pattern) {
|
|
13545
13913
|
const routeEntry = this.routes.get(pattern);
|
|
@@ -13698,7 +14066,22 @@ var _RouteManager = class _RouteManager {
|
|
|
13698
14066
|
pattern: entry.pattern,
|
|
13699
14067
|
modulePath: toUrlPath(entry.modulePath)
|
|
13700
14068
|
}));
|
|
13701
|
-
|
|
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 };
|
|
13702
14085
|
}
|
|
13703
14086
|
/**
|
|
13704
14087
|
* Load a route module dynamically
|
|
@@ -13775,6 +14158,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13775
14158
|
async discoverFileRoutes(source) {
|
|
13776
14159
|
const appDir = resolveAppPath(source.root, source.srcDir, "app");
|
|
13777
14160
|
const pageFiles = await safeGlobFiles("**/page.{ts,tsx,js,jsx,md,mdx}", appDir);
|
|
14161
|
+
const slotDefaultFiles = await safeGlobFiles("**/@*/**/default.{ts,tsx,js,jsx}", appDir);
|
|
13778
14162
|
const layoutFiles = await safeGlobFiles("**/layout.{ts,tsx,js,jsx}", appDir);
|
|
13779
14163
|
const loadingFiles = await safeGlobFiles("**/loading.{ts,tsx,js,jsx}", appDir);
|
|
13780
14164
|
const errorFiles = await safeGlobFiles("**/error.{ts,tsx,js,jsx}", appDir);
|
|
@@ -13783,7 +14167,7 @@ var _RouteManager = class _RouteManager {
|
|
|
13783
14167
|
appDir
|
|
13784
14168
|
);
|
|
13785
14169
|
for (const [kind, files, target] of [
|
|
13786
|
-
["page", pageFiles, this.routes],
|
|
14170
|
+
["page", pageFiles.filter((file) => parseRouteSlotFile(file) === null), this.routes],
|
|
13787
14171
|
["layout", layoutFiles, this.layouts],
|
|
13788
14172
|
["loading", loadingFiles, this.loadings],
|
|
13789
14173
|
["error", errorFiles, this.errors]
|
|
@@ -13807,6 +14191,32 @@ var _RouteManager = class _RouteManager {
|
|
|
13807
14191
|
});
|
|
13808
14192
|
}
|
|
13809
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
|
+
}
|
|
13810
14220
|
for (const file of metadataImageFiles) {
|
|
13811
14221
|
const fileBase = import_path5.default.basename(file, import_path5.default.extname(file));
|
|
13812
14222
|
const kind = fileBase === "twitter-image" ? "twitter" : "opengraph";
|
|
@@ -13932,6 +14342,71 @@ var _RouteManager = class _RouteManager {
|
|
|
13932
14342
|
}
|
|
13933
14343
|
return matchingLayouts;
|
|
13934
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
|
+
}
|
|
13935
14410
|
findNearestBoundary(pathname, boundaries) {
|
|
13936
14411
|
const normalizedPath = pathname === "/" ? "/" : pathname.replace(/\/$/, "");
|
|
13937
14412
|
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
@@ -15460,7 +15935,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15460
15935
|
async runWithRequestContext(request, fn) {
|
|
15461
15936
|
return _runWithCurrentRequest(
|
|
15462
15937
|
request,
|
|
15463
|
-
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15938
|
+
() => this.i18nRuntime?.config.enabled ? _runWithFarmI18nRequest(this.i18nRuntime, request, fn, {
|
|
15939
|
+
redirect: false
|
|
15940
|
+
}) : fn()
|
|
15464
15941
|
);
|
|
15465
15942
|
}
|
|
15466
15943
|
async resolveRouteContext(input) {
|
|
@@ -15483,11 +15960,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15483
15960
|
/**
|
|
15484
15961
|
* Check if a path should be served from SSG cache
|
|
15485
15962
|
*/
|
|
15486
|
-
shouldServeSSG(pathname) {
|
|
15963
|
+
async shouldServeSSG(pathname) {
|
|
15487
15964
|
const ssgPage = matchSSGPage(pathname, this.ssgManifest);
|
|
15488
15965
|
if (!ssgPage) return null;
|
|
15489
|
-
const cached = this.getCachedSSGPage(pathname);
|
|
15490
|
-
if (cached && this.dataCache.
|
|
15966
|
+
const cached = await this.getCachedSSGPage(pathname);
|
|
15967
|
+
if (cached && await this.dataCache.isStaleAsync(cached)) {
|
|
15491
15968
|
this.regenerateSSGPage(ssgPage);
|
|
15492
15969
|
}
|
|
15493
15970
|
return ssgPage;
|
|
@@ -15499,12 +15976,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15499
15976
|
return createFarmCacheKey(["ppr", normalizeRevalidatePath(pathname), search]);
|
|
15500
15977
|
}
|
|
15501
15978
|
getCachedSSGPage(urlPath) {
|
|
15502
|
-
return this.dataCache.
|
|
15979
|
+
return this.dataCache.getEntryAsync(this.getSSGCacheKey(urlPath), {
|
|
15503
15980
|
allowStale: true
|
|
15504
15981
|
});
|
|
15505
15982
|
}
|
|
15506
|
-
cacheSSGPage(page2, html, options) {
|
|
15507
|
-
this.dataCache.
|
|
15983
|
+
async cacheSSGPage(page2, html, options) {
|
|
15984
|
+
await this.dataCache.setAsync(
|
|
15508
15985
|
this.getSSGCacheKey(page2.urlPath),
|
|
15509
15986
|
{ html, document: options.document },
|
|
15510
15987
|
{
|
|
@@ -15516,11 +15993,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15516
15993
|
);
|
|
15517
15994
|
}
|
|
15518
15995
|
getCachedPPRShell(pathname, search) {
|
|
15519
|
-
return this.dataCache.
|
|
15996
|
+
return this.dataCache.getEntryAsync(this.getPPRCacheKey(pathname, search));
|
|
15520
15997
|
}
|
|
15521
|
-
cachePPRShell(options, html) {
|
|
15998
|
+
async cachePPRShell(options, html) {
|
|
15522
15999
|
const key = this.getPPRCacheKey(options.pathname, options.search);
|
|
15523
|
-
this.dataCache.
|
|
16000
|
+
await this.dataCache.setAsync(
|
|
15524
16001
|
key,
|
|
15525
16002
|
{ html },
|
|
15526
16003
|
{
|
|
@@ -15618,7 +16095,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15618
16095
|
}
|
|
15619
16096
|
const { renderToString } = await import("react-dom/server");
|
|
15620
16097
|
const html = renderToString(await this.wrapWithIntegrationProviders(pageElement));
|
|
15621
|
-
this.cacheSSGPage(page2, html, { document: false });
|
|
16098
|
+
await this.cacheSSGPage(page2, html, { document: false });
|
|
15622
16099
|
logger.info(`ISR: Regenerated ${page2.urlPath}`);
|
|
15623
16100
|
} catch (error) {
|
|
15624
16101
|
logger.error(`ISR regeneration failed for ${page2.urlPath}: ${error}`);
|
|
@@ -15632,7 +16109,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15632
16109
|
* Serve a pre-rendered SSG page
|
|
15633
16110
|
*/
|
|
15634
16111
|
async serveSSGPage(req, res, page2) {
|
|
15635
|
-
const cached = this.getCachedSSGPage(page2.urlPath);
|
|
16112
|
+
const cached = await this.getCachedSSGPage(page2.urlPath);
|
|
15636
16113
|
if (cached) {
|
|
15637
16114
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
15638
16115
|
res.setHeader("X-Farm-SSG", "cached");
|
|
@@ -15650,9 +16127,12 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15650
16127
|
if (fs2.existsSync(htmlPath)) {
|
|
15651
16128
|
const stat = fs2.statSync(htmlPath);
|
|
15652
16129
|
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
15653
|
-
this.cacheSSGPage(page2, html, {
|
|
15654
|
-
|
|
15655
|
-
|
|
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)) {
|
|
15656
16136
|
this.regenerateSSGPage(page2);
|
|
15657
16137
|
}
|
|
15658
16138
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -15698,6 +16178,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15698
16178
|
let pathname = "/";
|
|
15699
16179
|
let params = {};
|
|
15700
16180
|
let layouts = [];
|
|
16181
|
+
let routeSlots = [];
|
|
15701
16182
|
let searchParamsObject = {};
|
|
15702
16183
|
let middlewareMap = /* @__PURE__ */ new Map();
|
|
15703
16184
|
let middlewareContext = /* @__PURE__ */ new Map();
|
|
@@ -15730,7 +16211,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15730
16211
|
}
|
|
15731
16212
|
this.applyDeploymentHeaders(req, res);
|
|
15732
16213
|
if (process.env.NODE_ENV === "production") {
|
|
15733
|
-
const ssgPage = this.shouldServeSSG(pathname);
|
|
16214
|
+
const ssgPage = await this.shouldServeSSG(pathname);
|
|
15734
16215
|
if (ssgPage) {
|
|
15735
16216
|
const served = await this.serveSSGPage(req, res, ssgPage);
|
|
15736
16217
|
if (served) {
|
|
@@ -15743,6 +16224,7 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15743
16224
|
const route = match.route;
|
|
15744
16225
|
params = match.params;
|
|
15745
16226
|
layouts = match.layouts;
|
|
16227
|
+
routeSlots = match.slots ?? [];
|
|
15746
16228
|
if (!route) {
|
|
15747
16229
|
emitFarmEvent({ type: "route.notFound", pathname });
|
|
15748
16230
|
await this.render404(req, res);
|
|
@@ -15759,7 +16241,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15759
16241
|
errorBoundaryEntry = this.routeManager.getMatchingError(pathname);
|
|
15760
16242
|
middlewareMap = toMiddlewareMap2(req.__FARM_MIDDLEWARE_DATA__);
|
|
15761
16243
|
middlewareContext = toMiddlewareMap2(req.__FARM_MIDDLEWARE_CONTEXT__);
|
|
15762
|
-
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
16244
|
+
pluginExposedContext = getRequestContextSnapshot(req, {
|
|
16245
|
+
exposedOnly: true
|
|
16246
|
+
});
|
|
15763
16247
|
const currentRequest = createWebRequestFromFarmRequest(req);
|
|
15764
16248
|
const routeContext = await this.resolveRouteContext({
|
|
15765
16249
|
request: currentRequest,
|
|
@@ -15823,8 +16307,16 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15823
16307
|
revalidate: renderingConfig.revalidate
|
|
15824
16308
|
} : void 0;
|
|
15825
16309
|
if (renderingConfig.ppr && pprBypassReason) {
|
|
15826
|
-
emitFarmEvent({
|
|
15827
|
-
|
|
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
|
+
});
|
|
15828
16320
|
if (pprBypassReason === "refresh") {
|
|
15829
16321
|
pprRefreshRoute = pathname;
|
|
15830
16322
|
emitFarmEvent({ type: "ppr.refresh.start", route: pathname });
|
|
@@ -15832,14 +16324,22 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15832
16324
|
}
|
|
15833
16325
|
if (pprShellOptions) {
|
|
15834
16326
|
const pprCacheKey = this.getPPRCacheKey(pathname, url.search);
|
|
15835
|
-
const cachedPPRShell = this.getCachedPPRShell(pathname, url.search);
|
|
16327
|
+
const cachedPPRShell = await this.getCachedPPRShell(pathname, url.search);
|
|
15836
16328
|
if (cachedPPRShell) {
|
|
15837
|
-
emitFarmEvent({
|
|
16329
|
+
emitFarmEvent({
|
|
16330
|
+
type: "ppr.shell.hit",
|
|
16331
|
+
route: pathname,
|
|
16332
|
+
key: pprCacheKey
|
|
16333
|
+
});
|
|
15838
16334
|
this.serveCachedPPRShell(res, cachedPPRShell.value, renderingConfig.revalidate);
|
|
15839
16335
|
completeRender(res.statusCode || 200, pathname);
|
|
15840
16336
|
return;
|
|
15841
16337
|
}
|
|
15842
|
-
emitFarmEvent({
|
|
16338
|
+
emitFarmEvent({
|
|
16339
|
+
type: "ppr.shell.miss",
|
|
16340
|
+
route: pathname,
|
|
16341
|
+
key: pprCacheKey
|
|
16342
|
+
});
|
|
15843
16343
|
}
|
|
15844
16344
|
let LoadingFallbackComponent = null;
|
|
15845
16345
|
if (loadingBoundaryEntry) {
|
|
@@ -15863,14 +16363,77 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15863
16363
|
);
|
|
15864
16364
|
const moduleMetadata = routeManifestEntry || getClientModuleMetadata(route.modulePath, this.config.root);
|
|
15865
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
|
+
);
|
|
15866
16406
|
const shouldHydrate = moduleMetadata.shouldHydrate;
|
|
16407
|
+
const hasHydratableRouteSlots = renderedRouteSlots.some(
|
|
16408
|
+
(slot) => slot.isClientComponent || slot.shouldHydrate
|
|
16409
|
+
);
|
|
15867
16410
|
req.__FARM_PAGE_PATH__ = route.modulePath;
|
|
15868
16411
|
req.__FARM_ROUTE__ = pathname;
|
|
15869
16412
|
req.__FARM_IS_CLIENT_COMPONENT__ = isClientComponent;
|
|
15870
16413
|
req.__FARM_SHOULD_HYDRATE__ = shouldHydrate;
|
|
16414
|
+
req.__FARM_HAS_HYDRATABLE_ROUTE_SLOTS__ = hasHydratableRouteSlots;
|
|
15871
16415
|
req.__FARM_LOADING_MODULE_PATH__ = loadingBoundaryEntry?.modulePath ? loadingBoundaryEntry.modulePath.substring(
|
|
15872
16416
|
loadingBoundaryEntry.modulePath.indexOf("/src/app/")
|
|
15873
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
|
+
}));
|
|
15874
16437
|
req.__FARM_PROPS__ = {
|
|
15875
16438
|
params: pageProps.params,
|
|
15876
16439
|
search: pageProps.search,
|
|
@@ -15930,12 +16493,32 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15930
16493
|
let wrappedElement = pageElement;
|
|
15931
16494
|
for (let i = layoutModules.length - 1; i >= 0; i--) {
|
|
15932
16495
|
const layoutModule = layoutModules[i];
|
|
16496
|
+
const layoutEntry = layouts[i];
|
|
15933
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
|
+
}
|
|
15934
16516
|
wrappedElement = import_react4.default.createElement(
|
|
15935
16517
|
LayoutComponent,
|
|
15936
16518
|
{
|
|
15937
16519
|
children: wrappedElement,
|
|
15938
|
-
params
|
|
16520
|
+
params,
|
|
16521
|
+
...slotProps
|
|
15939
16522
|
}
|
|
15940
16523
|
);
|
|
15941
16524
|
}
|
|
@@ -15972,7 +16555,10 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
15972
16555
|
routeManifest,
|
|
15973
16556
|
captureStaticShell: Boolean(pprShellOptions),
|
|
15974
16557
|
observabilityRoute: pathname,
|
|
15975
|
-
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16558
|
+
onSuspenseHoleDetected: pprShellOptions ? () => emitFarmEvent({
|
|
16559
|
+
type: "ppr.suspense.holeDetected",
|
|
16560
|
+
route: pathname
|
|
16561
|
+
}) : void 0,
|
|
15976
16562
|
onComplete: pprShellOptions && req.method !== "HEAD" ? (html) => this.cachePPRShell(pprShellOptions, html) : void 0
|
|
15977
16563
|
}
|
|
15978
16564
|
);
|
|
@@ -16020,7 +16606,11 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16020
16606
|
}
|
|
16021
16607
|
emitFarmEvent({ type: "render.error", route: pathname, error });
|
|
16022
16608
|
if (pprRefreshRoute) {
|
|
16023
|
-
emitFarmEvent({
|
|
16609
|
+
emitFarmEvent({
|
|
16610
|
+
type: "ppr.refresh.error",
|
|
16611
|
+
route: pprRefreshRoute,
|
|
16612
|
+
error
|
|
16613
|
+
});
|
|
16024
16614
|
}
|
|
16025
16615
|
logger.error(`Error rendering page: ${error}`);
|
|
16026
16616
|
if (res.headersSent || res.writableEnded) {
|
|
@@ -16073,7 +16663,9 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16073
16663
|
if (typeof layoutModule.generateMetadata === "function") {
|
|
16074
16664
|
metadata = mergeMetadata(
|
|
16075
16665
|
metadata,
|
|
16076
|
-
await layoutModule.generateMetadata({
|
|
16666
|
+
await layoutModule.generateMetadata({
|
|
16667
|
+
params: options.pageProps.params
|
|
16668
|
+
})
|
|
16077
16669
|
);
|
|
16078
16670
|
}
|
|
16079
16671
|
}
|
|
@@ -16304,7 +16896,13 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16304
16896
|
clientEntry: "/@farm/client.js",
|
|
16305
16897
|
routes: {},
|
|
16306
16898
|
layouts: {},
|
|
16307
|
-
|
|
16899
|
+
slots: [],
|
|
16900
|
+
sharedAssets: [
|
|
16901
|
+
{
|
|
16902
|
+
tag: "link",
|
|
16903
|
+
attrs: { rel: "stylesheet", href: "/src/app/globals.css" }
|
|
16904
|
+
}
|
|
16905
|
+
]
|
|
16308
16906
|
};
|
|
16309
16907
|
for (const routeEntry of manifest.routes) {
|
|
16310
16908
|
clientManifest.routes[routeEntry.pattern] = {
|
|
@@ -16326,9 +16924,26 @@ var _ServerRenderer = class _ServerRenderer {
|
|
|
16326
16924
|
assets: []
|
|
16327
16925
|
};
|
|
16328
16926
|
}
|
|
16329
|
-
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
|
+
});
|
|
16330
16944
|
const propsScript = `<script>
|
|
16331
|
-
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data)};
|
|
16945
|
+
window.__FARM_PROPS__ = ${serializeInlineValue(deferredProps.data.page)};
|
|
16946
|
+
window.__FARM_ROUTE_SLOTS__ = ${serializeInlineValue(deferredProps.data.slots)};
|
|
16332
16947
|
window.__FARM_DEPLOYMENT_ID__ = ${serializeInlineValue(deploymentId)};
|
|
16333
16948
|
window.__FARM_PATH__ = ${JSON.stringify(req.__FARM_ROUTE__ || req.url || "/")};
|
|
16334
16949
|
window.__FARM_IS_CLIENT__ = ${JSON.stringify(isClientComponent)};
|
|
@@ -16341,7 +16956,7 @@ window.__FARM_MANIFEST__ = ${JSON.stringify(clientManifest)};
|
|
|
16341
16956
|
window.__FARM_INTEGRATION_API_MANIFEST__ = ${JSON.stringify(getRegisteredIntegrationAPIManifest())};
|
|
16342
16957
|
${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(getFarmI18nClientSnapshot())};` : ""}
|
|
16343
16958
|
</script>`;
|
|
16344
|
-
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() : "";
|
|
16345
16960
|
const {
|
|
16346
16961
|
title,
|
|
16347
16962
|
tags: metaTags,
|
|
@@ -16452,7 +17067,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16452
17067
|
didError = true;
|
|
16453
17068
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16454
17069
|
logger.error(`SSR shell error: ${error}`);
|
|
16455
|
-
emitFarmEvent({
|
|
17070
|
+
emitFarmEvent({
|
|
17071
|
+
type: "render.error",
|
|
17072
|
+
route: observabilityRoute,
|
|
17073
|
+
error
|
|
17074
|
+
});
|
|
16456
17075
|
}
|
|
16457
17076
|
if (clearMiddlewareData) {
|
|
16458
17077
|
clearMiddlewareData();
|
|
@@ -16463,7 +17082,11 @@ ${getFarmI18nClientSnapshot() ? `window.__FARM_I18N__ = ${serializeInlineValue(g
|
|
|
16463
17082
|
didError = true;
|
|
16464
17083
|
if (!isFarmRedirectError(error) && !isFarmNotFoundError(error)) {
|
|
16465
17084
|
logger.error(`SSR streaming error: ${error}`);
|
|
16466
|
-
emitFarmEvent({
|
|
17085
|
+
emitFarmEvent({
|
|
17086
|
+
type: "render.error",
|
|
17087
|
+
route: observabilityRoute,
|
|
17088
|
+
error
|
|
17089
|
+
});
|
|
16467
17090
|
}
|
|
16468
17091
|
}
|
|
16469
17092
|
});
|
|
@@ -16639,6 +17262,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16639
17262
|
logger.info("Initializing Farm.js application...");
|
|
16640
17263
|
}
|
|
16641
17264
|
await initStorage(this.config.storage);
|
|
17265
|
+
await configureFarmCache(this.config.cache);
|
|
16642
17266
|
await this.i18nRuntime.initialize();
|
|
16643
17267
|
await this.verifyAppStructure();
|
|
16644
17268
|
await this.routeManager.discoverRoutes();
|
|
@@ -16670,6 +17294,7 @@ var _FarmApp = class _FarmApp {
|
|
|
16670
17294
|
preset: config.preset ?? "node-server",
|
|
16671
17295
|
deploy: config.deploy || {},
|
|
16672
17296
|
storage: config.storage || {},
|
|
17297
|
+
cache: config.cache || {},
|
|
16673
17298
|
integrations: config.integrations || {},
|
|
16674
17299
|
plugins: config.plugins || [],
|
|
16675
17300
|
migrations: config.migrations || { commands: [] },
|
|
@@ -17144,7 +17769,7 @@ async function invokeAPIRouteEndpointInContext(endpoint, request, params) {
|
|
|
17144
17769
|
});
|
|
17145
17770
|
let body = void 0;
|
|
17146
17771
|
if (request.method.toUpperCase() !== "GET" && request.method.toUpperCase() !== "HEAD") {
|
|
17147
|
-
body = await
|
|
17772
|
+
body = await readRequestBody(request);
|
|
17148
17773
|
}
|
|
17149
17774
|
const headers = Object.fromEntries(request.headers.entries());
|
|
17150
17775
|
const types = endpoint.__types || {};
|
|
@@ -17248,17 +17873,50 @@ function isFarmContextHandler(endpoint) {
|
|
|
17248
17873
|
return firstParameter === "ctx" || firstParameter === "context" || firstParameter.startsWith("{");
|
|
17249
17874
|
}
|
|
17250
17875
|
__name(isFarmContextHandler, "isFarmContextHandler");
|
|
17251
|
-
async function
|
|
17876
|
+
async function readRequestBody(request) {
|
|
17877
|
+
const contentType = request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
17252
17878
|
try {
|
|
17879
|
+
if (contentType === "multipart/form-data") {
|
|
17880
|
+
return formDataToObject(await request.clone().formData());
|
|
17881
|
+
}
|
|
17253
17882
|
const text2 = await request.clone().text();
|
|
17254
|
-
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")) {
|
|
17255
17888
|
return JSON.parse(text2);
|
|
17256
17889
|
}
|
|
17890
|
+
return JSON.parse(text2);
|
|
17257
17891
|
} catch {
|
|
17258
17892
|
}
|
|
17259
17893
|
return void 0;
|
|
17260
17894
|
}
|
|
17261
|
-
__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");
|
|
17262
17920
|
function validateInput(schema, value, error) {
|
|
17263
17921
|
if (!schema || typeof schema.parse !== "function") {
|
|
17264
17922
|
return value;
|
|
@@ -18413,6 +19071,7 @@ async function generateRouteTypes(options) {
|
|
|
18413
19071
|
absolute: false
|
|
18414
19072
|
});
|
|
18415
19073
|
for (const file of pageFiles) {
|
|
19074
|
+
if (parseRouteSlotFile(file)) continue;
|
|
18416
19075
|
const route = parseRoutePath(file);
|
|
18417
19076
|
if (route.type === "page") {
|
|
18418
19077
|
const pattern = createRoutePattern(route);
|
|
@@ -19148,7 +19807,7 @@ function transformError(id, message) {
|
|
|
19148
19807
|
__name(transformError, "transformError");
|
|
19149
19808
|
|
|
19150
19809
|
// package.json
|
|
19151
|
-
var version = "0.1.0-beta.
|
|
19810
|
+
var version = "0.1.0-beta.4";
|
|
19152
19811
|
|
|
19153
19812
|
// src/version.ts
|
|
19154
19813
|
var FARM_VERSION = version;
|
|
@@ -19776,7 +20435,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
19776
20435
|
}, "isProgrammaticRouteSourceFile");
|
|
19777
20436
|
const isAppRuntimeFile = /* @__PURE__ */ __name((file) => {
|
|
19778
20437
|
const normalized = file.replace(/\\/g, "/");
|
|
19779
|
-
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(
|
|
19780
20439
|
normalized
|
|
19781
20440
|
);
|
|
19782
20441
|
}, "isAppRuntimeFile");
|
|
@@ -20467,7 +21126,10 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20467
21126
|
method: req.method || "GET"
|
|
20468
21127
|
});
|
|
20469
21128
|
}
|
|
20470
|
-
const
|
|
21129
|
+
const interceptFromHeader = request.headers.get("x-farm-intercept-from") || void 0;
|
|
21130
|
+
const match = routeManager3.matchRoute(targetRequestUrl.pathname, {
|
|
21131
|
+
interceptFrom: interceptFromHeader
|
|
21132
|
+
});
|
|
20471
21133
|
if (pm) {
|
|
20472
21134
|
await pm.runHookParallel("afterRouteMatch", {
|
|
20473
21135
|
pathname: targetPath,
|
|
@@ -20483,7 +21145,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20483
21145
|
res.end(JSON.stringify({ error: "Route not found" }));
|
|
20484
21146
|
return;
|
|
20485
21147
|
}
|
|
20486
|
-
const { route, params, layouts } = match;
|
|
21148
|
+
const { route, params, layouts, slots } = match;
|
|
20487
21149
|
if (!route) {
|
|
20488
21150
|
res.statusCode = 404;
|
|
20489
21151
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -20538,6 +21200,54 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20538
21200
|
search: searchParams,
|
|
20539
21201
|
routePath: route.pattern
|
|
20540
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
|
+
);
|
|
20541
21251
|
const projectRoot = server.config.root;
|
|
20542
21252
|
const toUrlPath = /* @__PURE__ */ __name((absolutePath) => {
|
|
20543
21253
|
if (absolutePath.startsWith(projectRoot)) {
|
|
@@ -20558,13 +21268,21 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20558
21268
|
},
|
|
20559
21269
|
canonicalPath: routeProps.__farmCanonicalPath,
|
|
20560
21270
|
modulePath: toUrlPath(route.modulePath),
|
|
20561
|
-
isClientComponent,
|
|
20562
|
-
shouldHydrate,
|
|
21271
|
+
isClientComponent: routeSlots.length > 0 ? false : isClientComponent,
|
|
21272
|
+
shouldHydrate: shouldHydrate || routeSlots.some((slot) => slot.isClientComponent || slot.shouldHydrate),
|
|
20563
21273
|
metadata: {
|
|
20564
21274
|
title: mergedMetadata.title,
|
|
20565
21275
|
description: mergedMetadata.description
|
|
20566
21276
|
},
|
|
20567
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,
|
|
20568
21286
|
i18n: getFarmI18nClientSnapshot()
|
|
20569
21287
|
};
|
|
20570
21288
|
await sendWebResponse(
|
|
@@ -20900,6 +21618,7 @@ function farmPlugin(options = {}, initialPluginManager) {
|
|
|
20900
21618
|
export const getManifest = () => ({
|
|
20901
21619
|
routes: {},
|
|
20902
21620
|
layouts: {},
|
|
21621
|
+
slots: [],
|
|
20903
21622
|
clientEntry: "/@farm/client.js",
|
|
20904
21623
|
sharedAssets: []
|
|
20905
21624
|
});
|
|
@@ -20910,6 +21629,7 @@ export const getManifest = () => ({
|
|
|
20910
21629
|
clientEntry: "/@farm/client.js",
|
|
20911
21630
|
routes: {},
|
|
20912
21631
|
layouts: {},
|
|
21632
|
+
slots: [],
|
|
20913
21633
|
sharedAssets: [
|
|
20914
21634
|
{
|
|
20915
21635
|
tag: "link",
|
|
@@ -20939,6 +21659,13 @@ export const getManifest = () => ({
|
|
|
20939
21659
|
assets: []
|
|
20940
21660
|
};
|
|
20941
21661
|
}
|
|
21662
|
+
for (const slot of manifest.slots) {
|
|
21663
|
+
fullManifest.slots.push({
|
|
21664
|
+
...slot,
|
|
21665
|
+
preloads: [slot.modulePath],
|
|
21666
|
+
assets: []
|
|
21667
|
+
});
|
|
21668
|
+
}
|
|
20942
21669
|
return `
|
|
20943
21670
|
// Auto-generated manifest for SPA navigation (TanStack Start pattern)
|
|
20944
21671
|
// This manifest is inlined in the server bundle - no file on disk
|
|
@@ -21581,7 +22308,7 @@ window.__FARM_WRAP_PROVIDERS__ = wrapWithIntegrationProviders;
|
|
|
21581
22308
|
|
|
21582
22309
|
// Get manifest from window (inlined by server in HTML)
|
|
21583
22310
|
// Fallback to empty manifest if not available yet
|
|
21584
|
-
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, clientEntry: '', sharedAssets: [] };
|
|
22311
|
+
const getManifest = () => window.__FARM_MANIFEST__ || { routes: {}, layouts: {}, slots: [], clientEntry: '', sharedAssets: [] };
|
|
21585
22312
|
|
|
21586
22313
|
// ====== CLIENT-SIDE ROUTE MATCHING ======
|
|
21587
22314
|
// Matches URL to route using manifest (no server request!)
|
|
@@ -21920,6 +22647,9 @@ let LayoutComponent = null;
|
|
|
21920
22647
|
|
|
21921
22648
|
// Track if we've taken over rendering from SSR
|
|
21922
22649
|
let hasClientTakenOver = false;
|
|
22650
|
+
const routeSlotRoots = new Map();
|
|
22651
|
+
const routeSlotDefinitions = new Map();
|
|
22652
|
+
let activeRouteInterception = null;
|
|
21923
22653
|
|
|
21924
22654
|
function normalizeServerProps(rawProps) {
|
|
21925
22655
|
const props = rawProps && typeof rawProps === 'object' ? { ...rawProps } : {};
|
|
@@ -21932,6 +22662,123 @@ function normalizeServerProps(rawProps) {
|
|
|
21932
22662
|
return props;
|
|
21933
22663
|
}
|
|
21934
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
|
+
|
|
21935
22782
|
function applyCanonicalPathFromProps(props) {
|
|
21936
22783
|
const canonicalPath = props && typeof props.__farmCanonicalPath === 'string'
|
|
21937
22784
|
? props.__farmCanonicalPath
|
|
@@ -22166,6 +23013,17 @@ async function tryHydrateImportedPage(
|
|
|
22166
23013
|
async function renderPage(pageData) {
|
|
22167
23014
|
const container = document.getElementById('root');
|
|
22168
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
|
+
}
|
|
22169
23027
|
|
|
22170
23028
|
const route = {
|
|
22171
23029
|
modulePath: pageData.modulePath,
|
|
@@ -22394,7 +23252,9 @@ async function hydrate() {
|
|
|
22394
23252
|
window.__FARM_SHOULD_HYDRATE__ === true ||
|
|
22395
23253
|
isClientComponent ||
|
|
22396
23254
|
await moduleLooksClient(modulePath);
|
|
23255
|
+
const hydratedSlots = await hydrateInitialRouteSlots();
|
|
22397
23256
|
if (!shouldHydrate) {
|
|
23257
|
+
if (hydratedSlots) replayPreHydrationClicks();
|
|
22398
23258
|
console.log('[Farm.js] Server component - SPA router ready')
|
|
22399
23259
|
return
|
|
22400
23260
|
}
|