@farm.js/core 0.1.0-beta.80 → 0.1.0-beta.81
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 +1 -1
- package/dist/agent-runtime.d.ts +1 -1
- package/dist/{app-D1fYgNSZ.d.mts → app-B9tbSdKW.d.mts} +3 -3
- package/dist/{app-DKW_R78N.d.ts → app-C7twWiJY.d.ts} +3 -3
- package/dist/app-markdown.d.mts +2 -2
- package/dist/app-markdown.d.ts +2 -2
- package/dist/{chunk-OEI62POE.mjs → chunk-6NV2RJSZ.mjs} +2 -2
- package/dist/{chunk-OEI62POE.mjs.map → chunk-6NV2RJSZ.mjs.map} +1 -1
- package/dist/{chunk-DNPQOJQW.mjs → chunk-CRK3RQ7C.mjs} +3 -3
- package/dist/{chunk-DBG42367.mjs → chunk-CVCIL6KH.mjs} +37 -14
- package/dist/chunk-CVCIL6KH.mjs.map +1 -0
- package/dist/{chunk-3UGGCJT5.mjs → chunk-HSCQGINR.mjs} +2 -2
- package/dist/{chunk-YSX4KDLV.mjs → chunk-VPEC2CWG.mjs} +42 -8
- package/dist/chunk-VPEC2CWG.mjs.map +1 -0
- package/dist/{chunk-3HIATXA4.mjs → chunk-XSUYR4Q3.mjs} +67 -25
- package/dist/chunk-XSUYR4Q3.mjs.map +1 -0
- package/dist/{chunk-3S7V7QHJ.mjs → chunk-Z73XASLT.mjs} +46 -19
- package/dist/chunk-Z73XASLT.mjs.map +1 -0
- package/dist/client/lifecycle.mjs +2 -2
- package/dist/{client-plugins-BtfLE4dW.d.mts → client-plugins-HizW0gLc.d.mts} +13 -1
- package/dist/{client-plugins-C4me5UPd.d.ts → client-plugins-w_b1wA8e.d.ts} +13 -1
- package/dist/client-plugins.cjs +1 -1
- package/dist/client-plugins.cjs.map +1 -1
- package/dist/client-plugins.d.mts +1 -1
- package/dist/client-plugins.d.ts +1 -1
- package/dist/client-plugins.mjs +2 -2
- package/dist/client.cjs +102 -37
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.mts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/client.mjs +4 -4
- package/dist/config.d.mts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/index.cjs +186 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.mjs +7 -7
- package/dist/integrations.d.mts +1 -1
- package/dist/integrations.d.ts +1 -1
- package/dist/internal/build-runtime.cjs +85 -24
- package/dist/internal/build-runtime.cjs.map +1 -1
- package/dist/internal/build-runtime.d.mts +3 -3
- package/dist/internal/build-runtime.d.ts +3 -3
- package/dist/internal/build-runtime.mjs +3 -3
- package/dist/internal/client-runtime.cjs +1 -1
- package/dist/internal/client-runtime.cjs.map +1 -1
- package/dist/internal/client-runtime.mjs +2 -2
- package/dist/internal/config-runtime.d.mts +2 -2
- package/dist/internal/config-runtime.d.ts +2 -2
- package/dist/internal/product-telemetry-runtime.cjs +1 -1
- package/dist/internal/product-telemetry-runtime.cjs.map +1 -1
- package/dist/internal/product-telemetry-runtime.mjs +1 -1
- package/dist/internal/production-runtime.d.mts +5 -5
- package/dist/internal/production-runtime.d.ts +5 -5
- package/dist/{metadata-route-Bf4aVrYO.d.mts → metadata-route-CjF_sf9F.d.mts} +1 -1
- package/dist/{metadata-route-CUPYRgfT.d.ts → metadata-route-DkyJlQFD.d.ts} +1 -1
- package/dist/middleware.d.mts +3 -3
- package/dist/middleware.d.ts +3 -3
- package/dist/navigation.cjs +66 -24
- package/dist/navigation.cjs.map +1 -1
- package/dist/navigation.mjs +3 -3
- package/dist/plugin.cjs +40 -7
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.mts +1 -1
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.mjs +2 -2
- package/dist/{production-runtime-D5ECiSmc.d.mts → production-runtime-CDSs0Rwo.d.mts} +1 -1
- package/dist/{production-runtime-Cb29k5Oi.d.ts → production-runtime-CSPVu_3h.d.ts} +1 -1
- package/dist/query/client.cjs +9 -5
- package/dist/query/client.cjs.map +1 -1
- package/dist/query/client.mjs +1 -1
- package/dist/{render-plan-DZ0LA8wX.d.ts → render-plan-C62oFdVD.d.ts} +1 -1
- package/dist/{render-plan-HL0ChBbH.d.mts → render-plan-D3TuPEmY.d.mts} +1 -1
- package/dist/renderer-client.cjs +66 -24
- package/dist/renderer-client.cjs.map +1 -1
- package/dist/renderer-client.d.mts +3 -3
- package/dist/renderer-client.d.ts +3 -3
- package/dist/renderer-client.mjs +1 -1
- package/dist/{request-8__ppqcz.d.ts → request-C-ZYE89s.d.ts} +1 -1
- package/dist/{request-DAZMscB9.d.mts → request-DPMdCOtv.d.mts} +1 -1
- package/dist/request.d.mts +2 -2
- package/dist/request.d.ts +2 -2
- package/dist/routes.d.mts +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/server-plugins.d.mts +2 -2
- package/dist/server-plugins.d.ts +2 -2
- package/dist/server.cjs +40 -7
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.mts +7 -7
- package/dist/server.d.ts +7 -7
- package/dist/server.mjs +2 -2
- package/dist/{spa-router-DMKCWHT5.d.ts → spa-router-C7RwU8o-.d.ts} +6 -2
- package/dist/{spa-router-BM-OHflh.d.mts → spa-router-Cr39oWnX.d.mts} +6 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{utils-B8t0bZ5X.d.ts → utils-B6Jk-ITz.d.ts} +1 -1
- package/dist/{utils-B7dij0CU.d.mts → utils-U4zuTiDB.d.mts} +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 +42 -7
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.mts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.mjs +4 -2
- package/package.json +1 -1
- package/dist/chunk-3HIATXA4.mjs.map +0 -1
- package/dist/chunk-3S7V7QHJ.mjs.map +0 -1
- package/dist/chunk-DBG42367.mjs.map +0 -1
- package/dist/chunk-YSX4KDLV.mjs.map +0 -1
- /package/dist/{chunk-DNPQOJQW.mjs.map → chunk-CRK3RQ7C.mjs.map} +0 -0
- /package/dist/{chunk-3UGGCJT5.mjs.map → chunk-HSCQGINR.mjs.map} +0 -0
|
@@ -51,6 +51,7 @@ var _SPARouter = class _SPARouter {
|
|
|
51
51
|
this.prefetchingUrls = /* @__PURE__ */ new Set();
|
|
52
52
|
this.observers = /* @__PURE__ */ new Map();
|
|
53
53
|
this.blockers = /* @__PURE__ */ new Set();
|
|
54
|
+
this.unloadBlockers = /* @__PURE__ */ new Map();
|
|
54
55
|
this.navigationListeners = /* @__PURE__ */ new Set();
|
|
55
56
|
this.navigationState = IDLE_NAVIGATION_STATE;
|
|
56
57
|
this.currentHistoryPath = null;
|
|
@@ -62,7 +63,7 @@ var _SPARouter = class _SPARouter {
|
|
|
62
63
|
void this.handlePopState(event);
|
|
63
64
|
}, "onPopState");
|
|
64
65
|
this.onBeforeUnload = /* @__PURE__ */ __name((event) => {
|
|
65
|
-
if (this.
|
|
66
|
+
if (this.shouldBlockUnload()) {
|
|
66
67
|
event.preventDefault();
|
|
67
68
|
event.returnValue = "";
|
|
68
69
|
}
|
|
@@ -240,6 +241,7 @@ var _SPARouter = class _SPARouter {
|
|
|
240
241
|
if (isFarmLocaleChangeHref(href)) return;
|
|
241
242
|
const url = new URL(href, window.location.origin);
|
|
242
243
|
if (isFarmExternalNavigationURL(url, window.location.origin)) return;
|
|
244
|
+
if (this.options.shouldUseDocumentNavigation(url.pathname)) return;
|
|
243
245
|
const fullPath = url.pathname + url.search;
|
|
244
246
|
const interceptFrom = window.location.pathname + window.location.search;
|
|
245
247
|
if (this.prefetchingUrls.has(fullPath)) return;
|
|
@@ -288,10 +290,15 @@ var _SPARouter = class _SPARouter {
|
|
|
288
290
|
this.observers.delete(element);
|
|
289
291
|
}
|
|
290
292
|
}
|
|
291
|
-
addBlocker(blocker) {
|
|
293
|
+
addBlocker(blocker, shouldBlockUnload) {
|
|
292
294
|
this.blockers.add(blocker);
|
|
295
|
+
this.unloadBlockers.set(
|
|
296
|
+
blocker,
|
|
297
|
+
shouldBlockUnload ?? (() => this.evaluateBlockerForUnload(blocker))
|
|
298
|
+
);
|
|
293
299
|
return () => {
|
|
294
300
|
this.blockers.delete(blocker);
|
|
301
|
+
this.unloadBlockers.delete(blocker);
|
|
295
302
|
};
|
|
296
303
|
}
|
|
297
304
|
getNavigationState() {
|
|
@@ -320,11 +327,16 @@ var _SPARouter = class _SPARouter {
|
|
|
320
327
|
this.writePageState("replace", state, href);
|
|
321
328
|
}
|
|
322
329
|
async commitNavigation(options) {
|
|
323
|
-
const
|
|
330
|
+
const historyUrl = new URL(
|
|
331
|
+
options.pageData.canonicalPath || options.fullPath,
|
|
332
|
+
window.location.origin
|
|
333
|
+
);
|
|
334
|
+
historyUrl.hash = options.url.hash;
|
|
335
|
+
const historyPath = historyUrl.pathname + historyUrl.search + historyUrl.hash;
|
|
324
336
|
const historyState = createHistoryState(
|
|
325
337
|
historyPath,
|
|
326
338
|
options.state,
|
|
327
|
-
void 0,
|
|
339
|
+
options.replace ? window.history.state : void 0,
|
|
328
340
|
options.pageData.interception?.from ?? null
|
|
329
341
|
);
|
|
330
342
|
const nextHistoryIndex = this.currentHistoryIndex == null ? null : options.replace ? this.currentHistoryIndex : this.currentHistoryIndex + 1;
|
|
@@ -338,18 +350,8 @@ var _SPARouter = class _SPARouter {
|
|
|
338
350
|
}
|
|
339
351
|
this.currentHistoryIndex = nextHistoryIndex;
|
|
340
352
|
this.currentHistoryPath = new URL(historyPath, window.location.origin).pathname + new URL(historyPath, window.location.origin).search;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
if (options.pageData.metadata?.description) {
|
|
345
|
-
let metaDesc = document.querySelector('meta[name="description"]');
|
|
346
|
-
if (!metaDesc) {
|
|
347
|
-
metaDesc = document.createElement("meta");
|
|
348
|
-
metaDesc.setAttribute("name", "description");
|
|
349
|
-
document.head.appendChild(metaDesc);
|
|
350
|
-
}
|
|
351
|
-
metaDesc.setAttribute("content", options.pageData.metadata.description);
|
|
352
|
-
}
|
|
353
|
+
notifyRouterHistoryChange();
|
|
354
|
+
this.updateDocumentMetadata(options.pageData.metadata);
|
|
353
355
|
_hydrateFarmI18n(options.pageData.i18n);
|
|
354
356
|
if (this.onNavigate) {
|
|
355
357
|
await this.onNavigate(options.pageData);
|
|
@@ -499,9 +501,7 @@ var _SPARouter = class _SPARouter {
|
|
|
499
501
|
await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);
|
|
500
502
|
}
|
|
501
503
|
if (!this.isCurrentNavigation(navigation, clientNavigation)) return;
|
|
502
|
-
|
|
503
|
-
document.title = pageData.metadata.title;
|
|
504
|
-
}
|
|
504
|
+
this.updateDocumentMetadata(pageData.metadata);
|
|
505
505
|
_hydrateFarmI18n(pageData.i18n);
|
|
506
506
|
if (this.onNavigate) {
|
|
507
507
|
await this.onNavigate(pageData);
|
|
@@ -545,6 +545,39 @@ var _SPARouter = class _SPARouter {
|
|
|
545
545
|
}
|
|
546
546
|
return false;
|
|
547
547
|
}
|
|
548
|
+
evaluateBlockerForUnload(blocker) {
|
|
549
|
+
const path = window.location.pathname + window.location.search;
|
|
550
|
+
const result = blocker({ from: path, to: path, action: "replace" });
|
|
551
|
+
if (result && typeof result !== "boolean") {
|
|
552
|
+
void result.catch(() => void 0);
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
return result === true;
|
|
556
|
+
}
|
|
557
|
+
shouldBlockUnload() {
|
|
558
|
+
for (const blocker of this.blockers) {
|
|
559
|
+
try {
|
|
560
|
+
if (this.unloadBlockers.get(blocker)?.()) return true;
|
|
561
|
+
} catch {
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
updateDocumentMetadata(metadata) {
|
|
568
|
+
document.title = metadata?.title || "Farm.js App";
|
|
569
|
+
let description = document.querySelector('meta[name="description"]');
|
|
570
|
+
if (!metadata?.description) {
|
|
571
|
+
description?.remove();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (!description) {
|
|
575
|
+
description = document.createElement("meta");
|
|
576
|
+
description.setAttribute("name", "description");
|
|
577
|
+
document.head.appendChild(description);
|
|
578
|
+
}
|
|
579
|
+
description.setAttribute("content", metadata.description);
|
|
580
|
+
}
|
|
548
581
|
startNavigation(options) {
|
|
549
582
|
this.activeNavigation?.controller.abort("superseded");
|
|
550
583
|
const navigation = {
|
|
@@ -745,6 +778,14 @@ __name(getScrollElementStorageKey, "getScrollElementStorageKey");
|
|
|
745
778
|
|
|
746
779
|
// src/client/history-sync.ts
|
|
747
780
|
var FARM_HISTORY_CHANGE_EVENT = "farm:historychange";
|
|
781
|
+
function dispatchHistoryChange(kind) {
|
|
782
|
+
window.dispatchEvent(
|
|
783
|
+
new CustomEvent(FARM_HISTORY_CHANGE_EVENT, {
|
|
784
|
+
detail: { kind }
|
|
785
|
+
})
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
__name(dispatchHistoryChange, "dispatchHistoryChange");
|
|
748
789
|
function notifyHistoryChange(kind) {
|
|
749
790
|
if (typeof window === "undefined") return;
|
|
750
791
|
setTimeout(() => {
|
|
@@ -752,14 +793,15 @@ function notifyHistoryChange(kind) {
|
|
|
752
793
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
753
794
|
return;
|
|
754
795
|
}
|
|
755
|
-
|
|
756
|
-
new CustomEvent(FARM_HISTORY_CHANGE_EVENT, {
|
|
757
|
-
detail: { kind }
|
|
758
|
-
})
|
|
759
|
-
);
|
|
796
|
+
dispatchHistoryChange(kind);
|
|
760
797
|
}, 0);
|
|
761
798
|
}
|
|
762
799
|
__name(notifyHistoryChange, "notifyHistoryChange");
|
|
800
|
+
function notifyRouterHistoryChange() {
|
|
801
|
+
if (typeof window === "undefined") return;
|
|
802
|
+
setTimeout(() => dispatchHistoryChange("url-search"), 0);
|
|
803
|
+
}
|
|
804
|
+
__name(notifyRouterHistoryChange, "notifyRouterHistoryChange");
|
|
763
805
|
function subscribeHistoryChange(listener) {
|
|
764
806
|
if (typeof window === "undefined") return () => {
|
|
765
807
|
};
|
|
@@ -784,4 +826,4 @@ export {
|
|
|
784
826
|
replaceState,
|
|
785
827
|
readPageState
|
|
786
828
|
};
|
|
787
|
-
//# sourceMappingURL=chunk-
|
|
829
|
+
//# sourceMappingURL=chunk-XSUYR4Q3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/spa-router.ts","../src/client/history-sync.ts"],"sourcesContent":["\"use client\";\n\nimport { readDeferredDataResponse } from \"../deferred\";\nimport { notifyHistoryChange, notifyRouterHistoryChange } from \"./history-sync\";\nimport {\n createFarmDeploymentMismatchError,\n createFarmDeploymentRequestHeaders,\n isFarmDeploymentMismatchResponse,\n} from \"../deployment\";\nimport { getHashTargetElement } from \"./hash-target\";\nimport { isFarmExternalNavigationURL } from \"./navigation-url\";\nimport type { FarmClientNavigationSession, FarmClientPluginManager } from \"./plugin\";\nimport { _hydrateFarmI18n, isFarmLocaleChangeHref } from \"../i18n/client-runtime\";\nimport type { FarmI18nClientSnapshot } from \"../i18n/types\";\nimport type { FarmIslandStrategy } from \"../island\";\nimport type { FarmRouteRenderPlan } from \"../navigation/render-plan\";\n\nexport { getHashTargetElement } from \"./hash-target\";\nexport { isFarmExternalNavigationURL } from \"./navigation-url\";\n\n/**\n * Farm.js SPA Router\n *\n * Provides client-side navigation without full page reloads.\n * Features:\n * - Prefetch on viewport intersection\n * - Prefetch on hover\n * - Page caching\n * - History API integration\n * - Scroll restoration\n */\n\ninterface PageData {\n props: Record<string, any>;\n modulePath: string;\n loadingModulePath?: string | null;\n canonicalPath?: string;\n isClientComponent?: boolean;\n shouldHydrate?: boolean;\n islandStrategy?: FarmIslandStrategy | null;\n renderPlan?: FarmRouteRenderPlan;\n fragment?: {\n html: string;\n layoutPatterns: string[];\n };\n metadata?: {\n title?: string;\n description?: string;\n };\n layoutModules?: string[];\n routeSlots?: RouteSlotPageData[];\n interception?: {\n from?: string;\n slots: string[];\n };\n i18n?: FarmI18nClientSnapshot;\n}\n\ninterface RouteSlotPageData {\n name: string;\n ownerPattern: string;\n containerId: string;\n interception: boolean;\n fallback: boolean;\n modulePath: string;\n isClientComponent: boolean;\n shouldHydrate: boolean;\n props: Record<string, any>;\n}\n\nexport interface RouterOptions {\n prefetchTimeout?: number;\n cacheMaxAge?: number;\n scrollRestoration?: boolean;\n shouldUseDocumentNavigation?: (pathname: string) => boolean;\n deploymentId?: string;\n}\n\ninterface CacheEntry {\n data: PageData;\n timestamp: number;\n}\n\nexport interface FarmNavigationBlockerContext {\n from: string;\n to: string;\n action: \"push\" | \"replace\" | \"pop\";\n}\n\nexport type FarmNavigationBlocker = (\n context: FarmNavigationBlockerContext,\n) => boolean | void | Promise<boolean | void>;\n\nexport type FarmViewTransitionMode = boolean | \"auto\";\n\nexport interface FarmNavigateOptions {\n replace?: boolean;\n scroll?: boolean;\n state?: unknown;\n viewTransition?: FarmViewTransitionMode;\n /** Re-fetch the current route even when its URL has not changed. */\n refresh?: boolean;\n}\n\nexport interface FarmNavigationLocation {\n href: string;\n pathname: string;\n search: string;\n hash: string;\n}\n\nexport interface FarmNavigationState {\n state: \"idle\" | \"loading\";\n pending: boolean;\n from: string | null;\n to: FarmNavigationLocation | null;\n action: FarmNavigationBlockerContext[\"action\"] | null;\n startedAt: number | null;\n}\n\nexport type FarmNavigationListener = (state: FarmNavigationState) => void;\n\nconst FARM_PAGE_STATE_KEY = \"__farmPageState\";\nconst FARM_INTERCEPT_FROM_KEY = \"__farmInterceptFrom\";\nconst FARM_HISTORY_INDEX_KEY = \"__farmHistoryIndex\";\n\nfunction readHistoryIndex(state: unknown): number | null {\n if (!state || typeof state !== \"object\") return null;\n const value = (state as Record<string, unknown>)[FARM_HISTORY_INDEX_KEY];\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\nconst IDLE_NAVIGATION_STATE: FarmNavigationState = {\n state: \"idle\",\n pending: false,\n from: null,\n to: null,\n action: null,\n startedAt: null,\n};\n\nfunction getActiveLayoutChainHeader(): string | undefined {\n if (typeof document === \"undefined\") return undefined;\n const patterns = Array.from(\n document.querySelectorAll<HTMLElement>('[data-farm-layout-boundary=\"true\"]'),\n )\n .map((element) => element.dataset.farmLayoutPattern)\n .filter((pattern): pattern is string => Boolean(pattern));\n return patterns.length > 0 ? JSON.stringify(patterns) : undefined;\n}\n\n// Global router instance\nlet routerInstance: SPARouter | null = null;\n\nexport class SPARouter {\n private cache: Map<string, CacheEntry> = new Map();\n private prefetchingUrls: Set<string> = new Set();\n private observers: Map<Element, IntersectionObserver> = new Map();\n private blockers: Set<FarmNavigationBlocker> = new Set();\n private unloadBlockers: Map<FarmNavigationBlocker, () => boolean> = new Map();\n private navigationListeners: Set<FarmNavigationListener> = new Set();\n private navigationState: FarmNavigationState = IDLE_NAVIGATION_STATE;\n private currentHistoryPath: string | null = null;\n private currentHistoryIndex: number | null = null;\n private suppressNextPopState = false;\n private navigationSequence = 0;\n private activeNavigation?: {\n id: number;\n controller: AbortController;\n };\n private scrollElements: Map<string, HTMLElement> = new Map();\n private options: Required<Omit<RouterOptions, \"deploymentId\">> &\n Pick<RouterOptions, \"deploymentId\">;\n private onNavigate?: (data: PageData) => Promise<void>;\n private clientPlugins?: Pick<\n FarmClientPluginManager,\n | \"beginNavigation\"\n | \"markNavigationLoaded\"\n | \"resolveNavigation\"\n | \"scheduleNavigationRendered\"\n | \"failNavigation\"\n >;\n\n private readonly onPopState = (event: PopStateEvent) => {\n void this.handlePopState(event);\n };\n\n private readonly onBeforeUnload = (event: BeforeUnloadEvent) => {\n if (this.shouldBlockUnload()) {\n event.preventDefault();\n event.returnValue = \"\";\n }\n this.saveScrollPosition(window.location.pathname + window.location.search);\n };\n\n constructor(options: RouterOptions = {}) {\n this.options = {\n prefetchTimeout: options.prefetchTimeout ?? 100,\n cacheMaxAge: options.cacheMaxAge ?? 30000, // 30 seconds\n scrollRestoration: options.scrollRestoration ?? true,\n shouldUseDocumentNavigation: options.shouldUseDocumentNavigation ?? (() => false),\n deploymentId: options.deploymentId ?? readBrowserDeploymentId(),\n };\n\n if (typeof window !== \"undefined\") {\n // Listen for popstate (back/forward navigation)\n window.addEventListener(\"popstate\", this.onPopState);\n\n // Save scroll position before unload\n window.addEventListener(\"beforeunload\", this.onBeforeUnload);\n\n // Track the rendered location and its position in the history stack so\n // popstate can report a real `from` and revert blocked traversals.\n this.currentHistoryPath = window.location.pathname + window.location.search;\n const existingIndex = readHistoryIndex(window.history.state);\n if (existingIndex == null) {\n try {\n window.history.replaceState(\n {\n ...((window.history.state as object | null) ?? {}),\n [FARM_HISTORY_INDEX_KEY]: 0,\n },\n \"\",\n window.location.href,\n );\n this.currentHistoryIndex = 0;\n } catch {\n this.currentHistoryIndex = null;\n }\n } else {\n this.currentHistoryIndex = existingIndex;\n }\n }\n }\n\n /** Remove global listeners. Intended for tests and teardown. */\n destroy(): void {\n if (typeof window === \"undefined\") return;\n this.cancelActiveNavigation();\n window.removeEventListener(\"popstate\", this.onPopState);\n window.removeEventListener(\"beforeunload\", this.onBeforeUnload);\n }\n\n /**\n * Set the navigation handler that updates React\n */\n setNavigationHandler(handler: (data: PageData) => Promise<void>) {\n this.onNavigate = handler;\n }\n\n /**\n * Connect Farm's browser plugin lifecycle to SPA navigation.\n */\n setClientPluginManager(manager: FarmClientPluginManager) {\n this.clientPlugins = manager;\n }\n\n /**\n * Navigate to a new URL\n */\n async navigate(href: string, options: FarmNavigateOptions = {}): Promise<void> {\n const {\n replace = false,\n scroll = true,\n state,\n viewTransition = false,\n refresh = false,\n } = options;\n\n // Parse the URL\n const url = new URL(href, window.location.origin);\n const pathname = url.pathname;\n const search = url.search;\n const fullPath = pathname + search;\n\n if (\n isFarmExternalNavigationURL(url, window.location.origin) ||\n isFarmLocaleChangeHref(url.toString()) ||\n this.options.shouldUseDocumentNavigation(pathname)\n ) {\n this.cancelActiveNavigation();\n if (replace) window.location.replace(url.toString());\n else window.location.assign(url.toString());\n return;\n }\n\n // Same page navigation - update fragment history without fetching route data.\n if (!refresh && pathname === window.location.pathname && search === window.location.search) {\n this.cancelActiveNavigation();\n if (url.hash === window.location.hash) return;\n\n this.writePageState(\n replace ? \"replace\" : \"push\",\n state === undefined ? readPageState() : state,\n url.toString(),\n );\n if (scroll) {\n if (url.hash) {\n getHashTargetElement(url.hash)?.scrollIntoView();\n } else {\n window.scrollTo(0, 0);\n }\n }\n return;\n }\n\n const from = window.location.pathname + window.location.search;\n if (\n await this.shouldBlockNavigation({\n from,\n to: fullPath,\n action: replace ? \"replace\" : \"push\",\n })\n ) {\n return;\n }\n\n // Save current scroll position\n if (this.options.scrollRestoration) {\n this.saveScrollPosition(window.location.pathname + window.location.search);\n }\n\n const navigation = this.startNavigation({\n from,\n to: createNavigationLocation(url),\n action: replace ? \"replace\" : \"push\",\n });\n\n let clientNavigation: FarmClientNavigationSession | undefined;\n try {\n clientNavigation = await this.clientPlugins?.beginNavigation({\n from,\n to: url,\n action: replace ? \"replace\" : \"push\",\n });\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n // Fetch page data (from cache or server)\n const pageData = await this.fetchPageData(\n fullPath,\n true,\n from,\n refresh,\n navigation.controller.signal,\n );\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n if (clientNavigation) {\n await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);\n }\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n await this.runViewTransition(viewTransition, () =>\n this.isCurrentNavigation(navigation, clientNavigation)\n ? this.commitNavigation({\n fullPath,\n pageData,\n pathname,\n replace,\n scroll,\n state,\n url,\n })\n : Promise.resolve(),\n );\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n if (clientNavigation) {\n await this.clientPlugins?.resolveNavigation(clientNavigation);\n void this.clientPlugins?.scheduleNavigationRendered(clientNavigation);\n }\n this.finishNavigation(navigation);\n } catch (error) {\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n if (clientNavigation) {\n await this.clientPlugins?.failNavigation(clientNavigation, error);\n }\n this.finishNavigation(navigation);\n console.error(\"[Farm.js] Navigation error:\", error);\n // Fall back to full page navigation\n window.location.href = href;\n }\n }\n\n /**\n * Re-render the active route from the server while preserving the document,\n * shared layouts, client runtime, and browser history entry.\n */\n refresh(options: Omit<FarmNavigateOptions, \"replace\" | \"refresh\"> = {}): Promise<void> {\n return this.navigate(window.location.href, {\n ...options,\n replace: true,\n refresh: true,\n scroll: options.scroll ?? false,\n });\n }\n\n /**\n * Prefetch a URL\n */\n async prefetch(href: string): Promise<void> {\n if (isFarmLocaleChangeHref(href)) return;\n const url = new URL(href, window.location.origin);\n if (isFarmExternalNavigationURL(url, window.location.origin)) return;\n if (this.options.shouldUseDocumentNavigation(url.pathname)) return;\n const fullPath = url.pathname + url.search;\n const interceptFrom = window.location.pathname + window.location.search;\n\n // Skip if already prefetching or cached\n if (this.prefetchingUrls.has(fullPath)) return;\n if (this.isCached(fullPath, interceptFrom)) return;\n\n this.prefetchingUrls.add(fullPath);\n\n try {\n await this.fetchPageData(fullPath, false, interceptFrom);\n } catch (error) {\n console.warn(\"[Farm.js] Prefetch failed:\", href, error);\n } finally {\n this.prefetchingUrls.delete(fullPath);\n }\n }\n\n /**\n * Observe an element for viewport intersection (prefetch when visible)\n */\n observeForPrefetch(element: HTMLAnchorElement): void {\n if (typeof IntersectionObserver === \"undefined\") return;\n\n const href = element.getAttribute(\"href\");\n if (!href || this.isExternalUrl(href)) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n // Delay prefetch slightly to avoid prefetching during scroll\n setTimeout(() => {\n this.prefetch(href);\n }, this.options.prefetchTimeout);\n\n // Stop observing after first intersection\n observer.unobserve(element);\n this.observers.delete(element);\n }\n }\n },\n { rootMargin: \"200px\" }, // Start prefetching when 200px from viewport\n );\n\n observer.observe(element);\n this.observers.set(element, observer);\n }\n\n /**\n * Stop observing an element\n */\n unobserveForPrefetch(element: HTMLAnchorElement): void {\n const observer = this.observers.get(element);\n if (observer) {\n observer.unobserve(element);\n this.observers.delete(element);\n }\n }\n\n addBlocker(blocker: FarmNavigationBlocker, shouldBlockUnload?: () => boolean): () => void {\n this.blockers.add(blocker);\n this.unloadBlockers.set(\n blocker,\n shouldBlockUnload ?? (() => this.evaluateBlockerForUnload(blocker)),\n );\n return () => {\n this.blockers.delete(blocker);\n this.unloadBlockers.delete(blocker);\n };\n }\n\n getNavigationState(): FarmNavigationState {\n return this.navigationState;\n }\n\n subscribeNavigation(listener: FarmNavigationListener): () => void {\n this.navigationListeners.add(listener);\n listener(this.navigationState);\n return () => {\n this.navigationListeners.delete(listener);\n };\n }\n\n registerScrollElement(key: string, element: HTMLElement): () => void {\n this.scrollElements.set(key, element);\n this.restoreScrollElement(window.location.pathname + window.location.search, key, element);\n return () => {\n if (this.scrollElements.get(key) === element) {\n this.scrollElements.delete(key);\n }\n };\n }\n\n pushState(state: unknown, href?: string): void {\n this.writePageState(\"push\", state, href);\n }\n\n replaceState(state: unknown, href?: string): void {\n this.writePageState(\"replace\", state, href);\n }\n\n private async commitNavigation(options: {\n fullPath: string;\n pageData: PageData;\n pathname: string;\n replace: boolean;\n scroll: boolean;\n state: unknown;\n url: URL;\n }): Promise<void> {\n const historyUrl = new URL(\n options.pageData.canonicalPath || options.fullPath,\n window.location.origin,\n );\n historyUrl.hash = options.url.hash;\n const historyPath = historyUrl.pathname + historyUrl.search + historyUrl.hash;\n const historyState = createHistoryState(\n historyPath,\n options.state,\n options.replace ? window.history.state : undefined,\n options.pageData.interception?.from ?? null,\n ) as Record<string, unknown>;\n const nextHistoryIndex =\n this.currentHistoryIndex == null\n ? null\n : options.replace\n ? this.currentHistoryIndex\n : this.currentHistoryIndex + 1;\n if (nextHistoryIndex != null) {\n historyState[FARM_HISTORY_INDEX_KEY] = nextHistoryIndex;\n }\n if (options.replace) {\n window.history.replaceState(historyState, \"\", historyPath);\n } else {\n window.history.pushState(historyState, \"\", historyPath);\n }\n this.currentHistoryIndex = nextHistoryIndex;\n this.currentHistoryPath =\n new URL(historyPath, window.location.origin).pathname +\n new URL(historyPath, window.location.origin).search;\n notifyRouterHistoryChange();\n\n this.updateDocumentMetadata(options.pageData.metadata);\n\n _hydrateFarmI18n(options.pageData.i18n);\n\n if (this.onNavigate) {\n await this.onNavigate(options.pageData);\n }\n\n if (options.scroll) {\n if (options.url.hash) {\n const element = getHashTargetElement(options.url.hash);\n if (element) {\n element.scrollIntoView();\n }\n } else {\n window.scrollTo(0, 0);\n }\n } else if (this.options.scrollRestoration) {\n this.restoreScrollPosition(this.currentHistoryPath ?? options.fullPath);\n }\n }\n\n private async runViewTransition(\n mode: FarmViewTransitionMode,\n callback: () => Promise<void>,\n ): Promise<void> {\n if (!mode || typeof document === \"undefined\") {\n await callback();\n return;\n }\n\n const startViewTransition = (document as any).startViewTransition;\n if (typeof startViewTransition !== \"function\") {\n await callback();\n return;\n }\n\n const transition = startViewTransition.call(document, () => callback());\n const updateDone = transition?.updateCallbackDone || transition?.ready;\n if (updateDone && typeof updateDone.then === \"function\") {\n await updateDone;\n }\n transition?.finished?.catch?.(() => undefined);\n }\n\n /**\n * Fetch page data from cache or server\n */\n private async fetchPageData(\n path: string,\n recover = true,\n interceptFrom?: string,\n fresh = false,\n signal?: AbortSignal,\n ): Promise<PageData> {\n const cacheKey = getPageDataCacheKey(path, interceptFrom);\n // Check cache first\n const cached = fresh ? undefined : this.cache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < this.options.cacheMaxAge) {\n return cached.data;\n }\n\n // Fetch from server. The active layout chain lets the server omit shared\n // shell HTML from the fragment without inspecting component source.\n const activeLayoutChain = getActiveLayoutChainHeader();\n const response = await fetch(`/__farm/page-data?path=${encodeURIComponent(path)}`, {\n signal,\n headers: createFarmDeploymentRequestHeaders(this.options.deploymentId, {\n Accept: \"application/x-farm-deferred+json, application/json\",\n \"X-Farm-SPA\": \"1\",\n ...(activeLayoutChain ? { \"X-Farm-Layout-Chain\": activeLayoutChain } : {}),\n ...(interceptFrom ? { \"X-Farm-Intercept-From\": interceptFrom } : {}),\n }),\n });\n\n if (isFarmDeploymentMismatchResponse(response, this.options.deploymentId)) {\n const error = createFarmDeploymentMismatchError(\n response,\n this.options.deploymentId || \"unknown\",\n );\n dispatchDeploymentMismatch(error);\n if (recover) {\n window.location.assign(path);\n }\n throw error;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch page data: ${response.status}`);\n }\n\n const data = await readDeferredDataResponse<PageData>(response);\n\n // Cache the result\n this.cache.set(cacheKey, {\n data,\n timestamp: Date.now(),\n });\n\n return data;\n }\n\n /**\n * Put the browser URL back on the rendered page after a blocked pop. When\n * both entries carry a Farm history index the traversal is reversed\n * exactly; otherwise the current path is pushed again, which restores the\n * address bar at the cost of one extra history entry.\n */\n private revertBlockedPopState(event: PopStateEvent, from: string): void {\n const eventIndex = readHistoryIndex(event.state);\n if (eventIndex != null && this.currentHistoryIndex != null) {\n const delta = eventIndex - this.currentHistoryIndex;\n if (delta !== 0) {\n this.suppressNextPopState = true;\n window.history.go(-delta);\n return;\n }\n }\n\n try {\n const restoredState: Record<string, unknown> = {\n path: from,\n };\n if (this.currentHistoryIndex != null && eventIndex != null) {\n restoredState[FARM_HISTORY_INDEX_KEY] = eventIndex + 1;\n this.currentHistoryIndex = eventIndex + 1;\n }\n window.history.pushState(restoredState, \"\", from);\n } catch {\n // Leave the URL as-is if the history API rejects the write; the\n // rendered page is still the blocked-from page.\n }\n }\n\n /**\n * Handle browser back/forward navigation\n */\n private async handlePopState(event: PopStateEvent): Promise<void> {\n if (document.documentElement.dataset.farmDocsRuntime === \"true\") return;\n\n if (this.suppressNextPopState) {\n // This traversal is our own revert of a blocked pop; the rendered page\n // never changed.\n this.suppressNextPopState = false;\n return;\n }\n\n const path = window.location.pathname + window.location.search;\n // The browser has already moved to the destination entry, so its state\n // describes `to`; the page still rendered is the tracked current path.\n const from = this.currentHistoryPath ?? path;\n\n if (\n await this.shouldBlockNavigation({\n from,\n to: path,\n action: \"pop\",\n })\n ) {\n this.revertBlockedPopState(event, from);\n return;\n }\n\n this.currentHistoryPath = path;\n this.currentHistoryIndex = readHistoryIndex(event.state);\n\n const navigation = this.startNavigation({\n from,\n to: createNavigationLocation(new URL(window.location.href)),\n action: \"pop\",\n });\n\n let clientNavigation: FarmClientNavigationSession | undefined;\n try {\n clientNavigation = await this.clientPlugins?.beginNavigation({\n from: null,\n to: window.location.href,\n action: \"pop\",\n });\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n const interceptFrom =\n typeof event.state?.[FARM_INTERCEPT_FROM_KEY] === \"string\"\n ? event.state[FARM_INTERCEPT_FROM_KEY]\n : undefined;\n const pageData = await this.fetchPageData(\n path,\n true,\n interceptFrom,\n false,\n navigation.controller.signal,\n );\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n if (clientNavigation) {\n await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);\n }\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n this.updateDocumentMetadata(pageData.metadata);\n\n _hydrateFarmI18n(pageData.i18n);\n\n // Call the navigation handler to update React\n if (this.onNavigate) {\n await this.onNavigate(pageData);\n }\n\n // Restore scroll position\n if (this.options.scrollRestoration) {\n this.restoreScrollPosition(window.location.pathname + window.location.search);\n }\n\n if (clientNavigation) {\n await this.clientPlugins?.resolveNavigation(clientNavigation);\n void this.clientPlugins?.scheduleNavigationRendered(clientNavigation);\n }\n this.finishNavigation(navigation);\n } catch (error) {\n if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n if (clientNavigation) {\n await this.clientPlugins?.failNavigation(clientNavigation, error);\n }\n this.finishNavigation(navigation);\n console.error(\"[Farm.js] Popstate navigation error:\", error);\n // Reload the page as fallback\n window.location.reload();\n }\n }\n\n /**\n * Check if URL is cached\n */\n private isCached(path: string, interceptFrom?: string): boolean {\n const cached = this.cache.get(getPageDataCacheKey(path, interceptFrom));\n return cached !== undefined && Date.now() - cached.timestamp < this.options.cacheMaxAge;\n }\n\n /**\n * Check if URL is external\n */\n private isExternalUrl(href: string): boolean {\n return href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\");\n }\n\n private async shouldBlockNavigation(context: FarmNavigationBlockerContext): Promise<boolean> {\n for (const blocker of this.blockers) {\n if (await blocker(context)) {\n return true;\n }\n }\n return false;\n }\n\n private evaluateBlockerForUnload(blocker: FarmNavigationBlocker): boolean {\n const path = window.location.pathname + window.location.search;\n const result = blocker({ from: path, to: path, action: \"replace\" });\n if (result && typeof result !== \"boolean\") {\n void result.catch(() => undefined);\n return true;\n }\n return result === true;\n }\n\n private shouldBlockUnload(): boolean {\n for (const blocker of this.blockers) {\n try {\n if (this.unloadBlockers.get(blocker)?.()) return true;\n } catch {\n return true;\n }\n }\n return false;\n }\n\n private updateDocumentMetadata(metadata: PageData[\"metadata\"]): void {\n document.title = metadata?.title || \"Farm.js App\";\n\n let description = document.querySelector('meta[name=\"description\"]');\n if (!metadata?.description) {\n description?.remove();\n return;\n }\n\n if (!description) {\n description = document.createElement(\"meta\");\n description.setAttribute(\"name\", \"description\");\n document.head.appendChild(description);\n }\n description.setAttribute(\"content\", metadata.description);\n }\n\n private startNavigation(options: {\n from: string;\n to: FarmNavigationLocation;\n action: FarmNavigationBlockerContext[\"action\"];\n }): { id: number; controller: AbortController } {\n this.activeNavigation?.controller.abort(\"superseded\");\n const navigation = {\n id: ++this.navigationSequence,\n controller: new AbortController(),\n };\n this.activeNavigation = navigation;\n this.setNavigationState({\n state: \"loading\",\n pending: true,\n from: options.from,\n to: options.to,\n action: options.action,\n startedAt: Date.now(),\n });\n return navigation;\n }\n\n private isCurrentNavigation(\n navigation: { id: number; controller: AbortController },\n clientNavigation?: FarmClientNavigationSession,\n ): boolean {\n return (\n this.activeNavigation?.id === navigation.id &&\n !navigation.controller.signal.aborted &&\n !clientNavigation?.signal.aborted\n );\n }\n\n private finishNavigation(navigation: { id: number; controller: AbortController }): void {\n if (this.activeNavigation?.id !== navigation.id) return;\n this.activeNavigation = undefined;\n this.setNavigationState(IDLE_NAVIGATION_STATE);\n }\n\n private cancelActiveNavigation(): void {\n if (!this.activeNavigation) return;\n this.activeNavigation.controller.abort(\"superseded\");\n this.activeNavigation = undefined;\n this.setNavigationState(IDLE_NAVIGATION_STATE);\n }\n\n private setNavigationState(state: FarmNavigationState): void {\n this.navigationState = state;\n for (const listener of this.navigationListeners) {\n listener(state);\n }\n }\n\n private writePageState(action: \"push\" | \"replace\", state: unknown, href?: string): void {\n if (typeof window === \"undefined\") return;\n\n const url = href ? new URL(href, window.location.origin).toString() : window.location.href;\n const nextPath = new URL(url).pathname + new URL(url).search;\n const nextState = createHistoryState(nextPath, state, window.history.state) as Record<\n string,\n unknown\n >;\n\n if (action === \"replace\") {\n window.history.replaceState(nextState, \"\", url);\n } else {\n if (this.currentHistoryIndex != null) {\n nextState[FARM_HISTORY_INDEX_KEY] = this.currentHistoryIndex + 1;\n }\n window.history.pushState(nextState, \"\", url);\n this.currentHistoryIndex =\n this.currentHistoryIndex == null ? null : this.currentHistoryIndex + 1;\n }\n this.currentHistoryPath = nextPath;\n\n notifyHistoryChange(\"page-state\");\n }\n\n /**\n * Save scroll position for a path\n */\n private saveScrollPosition(path: string): void {\n try {\n sessionStorage.setItem(\n `farm-scroll-${path}`,\n JSON.stringify({ x: window.scrollX, y: window.scrollY }),\n );\n for (const [key, element] of this.scrollElements) {\n sessionStorage.setItem(\n getScrollElementStorageKey(path, key),\n JSON.stringify({ x: element.scrollLeft, y: element.scrollTop }),\n );\n }\n } catch {\n // Ignore storage errors\n }\n }\n\n /**\n * Restore scroll position for a path\n */\n private restoreScrollPosition(path: string): void {\n try {\n const saved = sessionStorage.getItem(`farm-scroll-${path}`);\n if (saved) {\n const { x, y } = JSON.parse(saved);\n setTimeout(() => window.scrollTo(x, y), 0);\n }\n for (const [key, element] of this.scrollElements) {\n this.restoreScrollElement(path, key, element);\n }\n } catch {\n // Ignore storage errors\n }\n }\n\n private restoreScrollElement(path: string, key: string, element: HTMLElement): void {\n try {\n const saved = sessionStorage.getItem(getScrollElementStorageKey(path, key));\n if (!saved) return;\n const { x, y } = JSON.parse(saved);\n setTimeout(() => {\n element.scrollLeft = x;\n element.scrollTop = y;\n }, 0);\n } catch {\n // Ignore storage errors\n }\n }\n\n /**\n * Clear the page cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n\nfunction readBrowserDeploymentId(): string | undefined {\n if (typeof window === \"undefined\") return undefined;\n\n const runtimeId = (window as Window & { __FARM_DEPLOYMENT_ID__?: unknown })\n .__FARM_DEPLOYMENT_ID__;\n if (typeof runtimeId === \"string\" && runtimeId) return runtimeId;\n\n return document.querySelector<HTMLMetaElement>('meta[name=\"farm-deployment-id\"]')?.content;\n}\n\nfunction dispatchDeploymentMismatch(error: Error): void {\n if (typeof window === \"undefined\" || typeof CustomEvent === \"undefined\") return;\n window.dispatchEvent(new CustomEvent(\"farm:deployment-mismatch\", { detail: error }));\n}\n\n/**\n * Get or create the global router instance\n */\nexport function getInstalledFarmSPARouter(): SPARouter | undefined {\n if (typeof window === \"undefined\") return undefined;\n return (window as Window & { __FARM_SPA_ROUTER__?: SPARouter }).__FARM_SPA_ROUTER__;\n}\n\nexport function getRouter(): SPARouter {\n if (typeof window === \"undefined\") {\n // Return a no-op router for SSR\n return new SPARouter();\n }\n\n const installedRouter = getInstalledFarmSPARouter();\n if (installedRouter) {\n routerInstance = installedRouter;\n return installedRouter;\n }\n\n if (!routerInstance) {\n routerInstance = new SPARouter();\n }\n\n return routerInstance;\n}\n\n/**\n * Navigate to a URL using the SPA router\n */\nexport function navigateTo(href: string, options?: FarmNavigateOptions): Promise<void> {\n return getRouter().navigate(href, options);\n}\n\n/**\n * Prefetch a URL\n */\nexport function prefetch(href: string): Promise<void> {\n return getRouter().prefetch(href);\n}\n\nexport function pushState(state: unknown, href?: string): void {\n getRouter().pushState(state, href);\n}\n\nexport function replaceState(state: unknown, href?: string): void {\n getRouter().replaceState(state, href);\n}\n\nexport function readPageState<TState = unknown>(): TState | null {\n if (typeof window === \"undefined\") return null;\n const state = window.history.state;\n if (!state || typeof state !== \"object\") return null;\n return ((state as Record<string, unknown>)[FARM_PAGE_STATE_KEY] as TState | undefined) ?? null;\n}\n\nfunction createHistoryState(\n path: string,\n pageState: unknown,\n currentState?: unknown,\n interceptFrom?: string | null,\n) {\n const base =\n currentState && typeof currentState === \"object\" ? { ...(currentState as object) } : {};\n const nextState: Record<string, unknown> = {\n ...base,\n path,\n [FARM_PAGE_STATE_KEY]: pageState,\n };\n if (interceptFrom === null) {\n delete nextState[FARM_INTERCEPT_FROM_KEY];\n } else if (interceptFrom) {\n nextState[FARM_INTERCEPT_FROM_KEY] = interceptFrom;\n }\n return nextState;\n}\n\nfunction getPageDataCacheKey(path: string, interceptFrom?: string): string {\n return interceptFrom ? `${path}\\nintercept:${interceptFrom}` : path;\n}\n\nfunction createNavigationLocation(url: URL): FarmNavigationLocation {\n return {\n href: url.href,\n pathname: url.pathname,\n search: url.search,\n hash: url.hash,\n };\n}\n\nfunction getScrollElementStorageKey(path: string, key: string): string {\n return `farm-scroll-${path}:${key}`;\n}\n","import { getInstalledFarmSPARouter } from \"./spa-router\";\n\n/** Fired after programmatic history writes that must not start a navigation. */\nexport const FARM_HISTORY_CHANGE_EVENT = \"farm:historychange\";\n\nexport type FarmHistoryChangeKind = \"url-search\" | \"page-state\";\n\nexport interface FarmHistoryChangeDetail {\n kind: FarmHistoryChangeKind;\n}\n\nfunction dispatchHistoryChange(kind: FarmHistoryChangeKind): void {\n window.dispatchEvent(\n new CustomEvent<FarmHistoryChangeDetail>(FARM_HISTORY_CHANGE_EVENT, {\n detail: { kind },\n }),\n );\n}\n\n/**\n * Notify history observers after pushState/replaceState.\n *\n * Farm's SPA router treats `popstate` as real back/forward navigation, so a\n * dedicated event is used instead. `url-search` keeps the nuqs-style synthetic\n * `popstate` when no Farm router is installed, so standalone `useQueryState`\n * consumers still resync; `page-state` is Farm-internal and never falls back.\n */\nexport function notifyHistoryChange(kind: FarmHistoryChangeKind): void {\n if (typeof window === \"undefined\") return;\n\n setTimeout(() => {\n if (kind === \"url-search\" && !getInstalledFarmSPARouter()) {\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n return;\n }\n\n dispatchHistoryChange(kind);\n }, 0);\n}\n\n/** Notify observers after a Farm router commit without simulating traversal. */\nexport function notifyRouterHistoryChange(): void {\n if (typeof window === \"undefined\") return;\n setTimeout(() => dispatchHistoryChange(\"url-search\"), 0);\n}\n\nexport function subscribeHistoryChange(listener: () => void): () => void {\n if (typeof window === \"undefined\") return () => {};\n\n window.addEventListener(\"popstate\", listener);\n window.addEventListener(FARM_HISTORY_CHANGE_EVENT, listener);\n\n return () => {\n window.removeEventListener(\"popstate\", listener);\n window.removeEventListener(FARM_HISTORY_CHANGE_EVENT, listener);\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
mergeFarmViteConfig,
|
|
44
44
|
resolveFarmNotFoundComponentPath,
|
|
45
45
|
resolveRouteRenderingConfigFromFile
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-VPEC2CWG.mjs";
|
|
47
47
|
import {
|
|
48
48
|
farmEnvironmentFunctionsPlugin
|
|
49
49
|
} from "./chunk-V6WE6JSZ.mjs";
|
|
@@ -1870,6 +1870,7 @@ __name(generateRuntimePathMatcherSource, "generateRuntimePathMatcherSource");
|
|
|
1870
1870
|
function generateUniversalRouterStateProperties() {
|
|
1871
1871
|
return `
|
|
1872
1872
|
blockers: new Set(),
|
|
1873
|
+
unloadBlockers: new Map(),
|
|
1873
1874
|
navigationListeners: new Set(),
|
|
1874
1875
|
navigationState: IDLE_NAVIGATION_STATE,
|
|
1875
1876
|
navigationSequence: 0,
|
|
@@ -1913,9 +1914,20 @@ function generateUniversalRouterStateProperties() {
|
|
|
1913
1914
|
return () => this.navigationListeners.delete(listener);
|
|
1914
1915
|
},
|
|
1915
1916
|
|
|
1916
|
-
addBlocker: function(blocker) {
|
|
1917
|
+
addBlocker: function(blocker, shouldBlockUnload) {
|
|
1917
1918
|
this.blockers.add(blocker);
|
|
1918
|
-
|
|
1919
|
+
this.unloadBlockers.set(blocker, shouldBlockUnload || (() => {
|
|
1920
|
+
const result = blocker({ from: this.currentPath, to: this.currentPath, action: "replace" });
|
|
1921
|
+
if (result && typeof result.then === "function") {
|
|
1922
|
+
result.catch(() => undefined);
|
|
1923
|
+
return true;
|
|
1924
|
+
}
|
|
1925
|
+
return result === true;
|
|
1926
|
+
}));
|
|
1927
|
+
return () => {
|
|
1928
|
+
this.blockers.delete(blocker);
|
|
1929
|
+
this.unloadBlockers.delete(blocker);
|
|
1930
|
+
};
|
|
1919
1931
|
},
|
|
1920
1932
|
|
|
1921
1933
|
shouldBlockNavigation: async function(context) {
|
|
@@ -1925,6 +1937,17 @@ function generateUniversalRouterStateProperties() {
|
|
|
1925
1937
|
return false;
|
|
1926
1938
|
},
|
|
1927
1939
|
|
|
1940
|
+
shouldBlockUnload: function() {
|
|
1941
|
+
for (const blocker of this.blockers) {
|
|
1942
|
+
try {
|
|
1943
|
+
if (this.unloadBlockers.get(blocker)?.()) return true;
|
|
1944
|
+
} catch {
|
|
1945
|
+
return true;
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
return false;
|
|
1949
|
+
},
|
|
1950
|
+
|
|
1928
1951
|
handlePopState: function(event) {
|
|
1929
1952
|
if (document.documentElement.dataset.farmDocsRuntime === "true") return;
|
|
1930
1953
|
return this.navigate(window.location.href, {
|
|
@@ -2015,17 +2038,10 @@ function generateUniversalRouterStateProperties() {
|
|
|
2015
2038
|
|
|
2016
2039
|
writePageState: function(action, state, href) {
|
|
2017
2040
|
const url = new URL(href || window.location.href, window.location.origin);
|
|
2018
|
-
this.writeHistoryEntry(action, url.pathname + url.search, state, url);
|
|
2019
|
-
// Announce on the dedicated history channel; a synthetic popstate would
|
|
2020
|
-
// be treated as back/forward by the popstate listener below and trigger
|
|
2021
|
-
// a full navigation for a shallow page-state write. The bundled client
|
|
2022
|
-
// hooks subscribe to this event via subscribeHistoryChange.
|
|
2023
|
-
window.dispatchEvent(
|
|
2024
|
-
new CustomEvent("farm:historychange", { detail: { kind: "page-state" } }),
|
|
2025
|
-
);
|
|
2041
|
+
this.writeHistoryEntry(action, url.pathname + url.search, state, url, "page-state");
|
|
2026
2042
|
},
|
|
2027
2043
|
|
|
2028
|
-
writeHistoryEntry: function(action, path, pageState, url) {
|
|
2044
|
+
writeHistoryEntry: function(action, path, pageState, url, changeKind = "url-search") {
|
|
2029
2045
|
if (action === "pop") return;
|
|
2030
2046
|
const nextState = createHistoryState(path, pageState, window.history.state);
|
|
2031
2047
|
const nextIndex = this.currentHistoryIndex == null
|
|
@@ -2038,6 +2054,11 @@ function generateUniversalRouterStateProperties() {
|
|
|
2038
2054
|
else window.history.pushState(nextState, "", url);
|
|
2039
2055
|
this.currentHistoryIndex = nextIndex;
|
|
2040
2056
|
this.currentHistoryState = nextState;
|
|
2057
|
+
// Announce programmatic history writes without synthesizing popstate,
|
|
2058
|
+
// which the router reserves for real back/forward navigation.
|
|
2059
|
+
window.dispatchEvent(
|
|
2060
|
+
new CustomEvent("farm:historychange", { detail: { kind: changeKind } }),
|
|
2061
|
+
);
|
|
2041
2062
|
},
|
|
2042
2063
|
|
|
2043
2064
|
registerScrollElement: function(key, element) {
|
|
@@ -2236,12 +2257,14 @@ ${generateUniversalRouterStateProperties()}
|
|
|
2236
2257
|
const url = new URL(href, window.location.origin);
|
|
2237
2258
|
if (isFarmExternalNavigationURL(url, window.location.origin)) {
|
|
2238
2259
|
this.cancelActiveNavigation();
|
|
2239
|
-
window.location.href
|
|
2260
|
+
if (options.replace || options.action === "replace") window.location.replace(href);
|
|
2261
|
+
else window.location.href = href;
|
|
2240
2262
|
return;
|
|
2241
2263
|
}
|
|
2242
2264
|
if (isFarmDocsPath(url.pathname)) {
|
|
2243
2265
|
this.cancelActiveNavigation();
|
|
2244
|
-
window.location.href
|
|
2266
|
+
if (options.replace || options.action === "replace") window.location.replace(href);
|
|
2267
|
+
else window.location.href = href;
|
|
2245
2268
|
return;
|
|
2246
2269
|
}
|
|
2247
2270
|
|
|
@@ -2403,6 +2426,7 @@ ${generateUniversalRouterStateProperties()}
|
|
|
2403
2426
|
prefetch: function(href) {
|
|
2404
2427
|
const url = new URL(href, window.location.origin);
|
|
2405
2428
|
if (isFarmExternalNavigationURL(url, window.location.origin)) return;
|
|
2429
|
+
if (isFarmDocsPath(url.pathname)) return;
|
|
2406
2430
|
|
|
2407
2431
|
const pathname = url.pathname + url.search;
|
|
2408
2432
|
if (this.prefetchCache.has(pathname)) return;
|
|
@@ -2466,7 +2490,7 @@ window.__FARM_SPA_ROUTER__ = spaRouter;
|
|
|
2466
2490
|
void hydrateFarmDocsAdapterRuntime();
|
|
2467
2491
|
|
|
2468
2492
|
window.addEventListener("beforeunload", function(event) {
|
|
2469
|
-
if (spaRouter.
|
|
2493
|
+
if (spaRouter.shouldBlockUnload()) {
|
|
2470
2494
|
event.preventDefault();
|
|
2471
2495
|
event.returnValue = "";
|
|
2472
2496
|
}
|
|
@@ -3089,12 +3113,14 @@ ${generateUniversalRouterStateProperties()}
|
|
|
3089
3113
|
const url = new URL(href, window.location.origin);
|
|
3090
3114
|
if (isFarmExternalNavigationURL(url, window.location.origin)) {
|
|
3091
3115
|
this.cancelActiveNavigation();
|
|
3092
|
-
window.location.href
|
|
3116
|
+
if (options.replace || options.action === "replace") window.location.replace(href);
|
|
3117
|
+
else window.location.href = href;
|
|
3093
3118
|
return;
|
|
3094
3119
|
}
|
|
3095
3120
|
if (isFarmDocsPath(url.pathname)) {
|
|
3096
3121
|
this.cancelActiveNavigation();
|
|
3097
|
-
window.location.href
|
|
3122
|
+
if (options.replace || options.action === "replace") window.location.replace(href);
|
|
3123
|
+
else window.location.href = href;
|
|
3098
3124
|
return;
|
|
3099
3125
|
}
|
|
3100
3126
|
|
|
@@ -3431,6 +3457,7 @@ ${generateUniversalRouterStateProperties()}
|
|
|
3431
3457
|
prefetch: function(href) {
|
|
3432
3458
|
const url = new URL(href, window.location.origin);
|
|
3433
3459
|
if (isFarmExternalNavigationURL(url, window.location.origin)) return;
|
|
3460
|
+
if (isFarmDocsPath(url.pathname)) return;
|
|
3434
3461
|
|
|
3435
3462
|
const pathname = url.pathname + url.search;
|
|
3436
3463
|
const interceptFrom = this.currentPath;
|
|
@@ -3490,7 +3517,7 @@ spaRouter.initializeHistory();
|
|
|
3490
3517
|
window.__FARM_SPA_ROUTER__ = spaRouter;
|
|
3491
3518
|
|
|
3492
3519
|
window.addEventListener("beforeunload", function(event) {
|
|
3493
|
-
if (spaRouter.
|
|
3520
|
+
if (spaRouter.shouldBlockUnload()) {
|
|
3494
3521
|
event.preventDefault();
|
|
3495
3522
|
event.returnValue = "";
|
|
3496
3523
|
}
|
|
@@ -8309,4 +8336,4 @@ __name(buildNitro, "buildNitro");
|
|
|
8309
8336
|
export {
|
|
8310
8337
|
build
|
|
8311
8338
|
};
|
|
8312
|
-
//# sourceMappingURL=chunk-
|
|
8339
|
+
//# sourceMappingURL=chunk-Z73XASLT.mjs.map
|