@lolyjs/core 0.2.0-alpha.24 → 0.2.0-alpha.26
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/cli.cjs +21 -21
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +21 -21
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +21 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1 -6
- package/dist/index.d.ts +1 -6
- package/dist/index.js +21 -23
- package/dist/index.js.map +1 -1
- package/dist/react/sockets.cjs +0 -8
- package/dist/react/sockets.cjs.map +1 -1
- package/dist/react/sockets.js +0 -8
- package/dist/react/sockets.js.map +1 -1
- package/dist/runtime.cjs +0 -2
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +0 -2
- package/dist/runtime.js.map +1 -1
- package/package.json +1 -1
package/dist/react/sockets.cjs
CHANGED
|
@@ -31,20 +31,12 @@ var lolySocket = (namespace, opts) => {
|
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
const normalizedNamespace = namespace.startsWith("/") ? namespace : `/${namespace}`;
|
|
34
|
-
console.log("[loly:socket] Connecting to namespace:", normalizedNamespace, "path:", "/wss");
|
|
35
34
|
const socket = (0, import_socket.io)(normalizedNamespace, {
|
|
36
35
|
path: "/wss",
|
|
37
36
|
transports: ["websocket", "polling"],
|
|
38
37
|
autoConnect: true,
|
|
39
38
|
...opts
|
|
40
39
|
});
|
|
41
|
-
socket.on("connect_error", (error) => {
|
|
42
|
-
console.error("[loly:socket] Connection error:", error.message);
|
|
43
|
-
console.error("[loly:socket] Namespace:", normalizedNamespace);
|
|
44
|
-
});
|
|
45
|
-
socket.on("connect", () => {
|
|
46
|
-
console.log("[loly:socket] \u2705 Connected to namespace:", normalizedNamespace);
|
|
47
|
-
});
|
|
48
40
|
return socket;
|
|
49
41
|
};
|
|
50
42
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n // SIMPLIFICADO: Siempre usar el origin actual en el navegador\r\n // Socket.IO maneja el namespace automáticamente\r\n if (typeof window === \"undefined\") {\r\n throw new Error(\r\n \"[loly:socket] lolySocket can only be called on the client side.\"\r\n );\r\n }\r\n\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n \r\n // Socket.IO: io(namespace, { path: '/wss' })\r\n // Socket.IO usa window.location.origin automáticamente\r\n // El path '/wss' es el endpoint del engine de Socket.IO\r\n // El namespace se maneja en el handshake\r\n
|
|
1
|
+
{"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n // SIMPLIFICADO: Siempre usar el origin actual en el navegador\r\n // Socket.IO maneja el namespace automáticamente\r\n if (typeof window === \"undefined\") {\r\n throw new Error(\r\n \"[loly:socket] lolySocket can only be called on the client side.\"\r\n );\r\n }\r\n\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n \r\n // Socket.IO: io(namespace, { path: '/wss' })\r\n // Socket.IO usa window.location.origin automáticamente\r\n // El path '/wss' es el endpoint del engine de Socket.IO\r\n // El namespace se maneja en el handshake\r\n\r\n const socket = io(normalizedNamespace, {\r\n path: \"/wss\",\r\n transports: [\"websocket\", \"polling\"],\r\n autoConnect: true,\r\n ...opts,\r\n });\r\n\r\n return socket;\r\n};\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA0D;AA0BnD,IAAM,aAAa,CACxB,WACA,SACW;AAGX,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,sBAAsB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAOjF,QAAM,aAAS,kBAAG,qBAAqB;AAAA,IACrC,MAAM;AAAA,IACN,YAAY,CAAC,aAAa,SAAS;AAAA,IACnC,aAAa;AAAA,IACb,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AACT;","names":[]}
|
package/dist/react/sockets.js
CHANGED
|
@@ -7,20 +7,12 @@ var lolySocket = (namespace, opts) => {
|
|
|
7
7
|
);
|
|
8
8
|
}
|
|
9
9
|
const normalizedNamespace = namespace.startsWith("/") ? namespace : `/${namespace}`;
|
|
10
|
-
console.log("[loly:socket] Connecting to namespace:", normalizedNamespace, "path:", "/wss");
|
|
11
10
|
const socket = io(normalizedNamespace, {
|
|
12
11
|
path: "/wss",
|
|
13
12
|
transports: ["websocket", "polling"],
|
|
14
13
|
autoConnect: true,
|
|
15
14
|
...opts
|
|
16
15
|
});
|
|
17
|
-
socket.on("connect_error", (error) => {
|
|
18
|
-
console.error("[loly:socket] Connection error:", error.message);
|
|
19
|
-
console.error("[loly:socket] Namespace:", normalizedNamespace);
|
|
20
|
-
});
|
|
21
|
-
socket.on("connect", () => {
|
|
22
|
-
console.log("[loly:socket] \u2705 Connected to namespace:", normalizedNamespace);
|
|
23
|
-
});
|
|
24
16
|
return socket;
|
|
25
17
|
};
|
|
26
18
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n // SIMPLIFICADO: Siempre usar el origin actual en el navegador\r\n // Socket.IO maneja el namespace automáticamente\r\n if (typeof window === \"undefined\") {\r\n throw new Error(\r\n \"[loly:socket] lolySocket can only be called on the client side.\"\r\n );\r\n }\r\n\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n \r\n // Socket.IO: io(namespace, { path: '/wss' })\r\n // Socket.IO usa window.location.origin automáticamente\r\n // El path '/wss' es el endpoint del engine de Socket.IO\r\n // El namespace se maneja en el handshake\r\n
|
|
1
|
+
{"version":3,"sources":["../../modules/react/sockets/index.ts"],"sourcesContent":["import { io, ManagerOptions, Socket, SocketOptions } from \"socket.io-client\";\r\n\r\n/**\r\n * Creates a Socket.IO client connection to a specific namespace.\r\n * \r\n * This helper function simplifies Socket.IO client setup by handling:\r\n * - Namespace normalization (ensures leading slash)\r\n * - Base URL resolution (from environment or current origin)\r\n * - Default Socket.IO configuration (path: '/wss', transports: ['websocket', 'polling'])\r\n * \r\n * @param namespace - The namespace to connect to (e.g., '/chat' or 'chat').\r\n * The namespace will be normalized to always start with '/'.\r\n * Must match the namespace pattern defined in your server's WSS routes.\r\n * @param opts - Optional Socket.IO client options that will override the defaults.\r\n * \r\n * @returns A Socket.IO client instance connected to the specified namespace.\r\n * \r\n * @example\r\n * ```ts\r\n * const socket = lolySocket('/chat');\r\n * socket.on('message', (data) => {\r\n * console.log('Received:', data);\r\n * });\r\n * socket.emit('message', { text: 'Hello' });\r\n * ```\r\n */\r\nexport const lolySocket = (\r\n namespace: string,\r\n opts?: Partial<ManagerOptions & SocketOptions>\r\n): Socket => {\r\n // SIMPLIFICADO: Siempre usar el origin actual en el navegador\r\n // Socket.IO maneja el namespace automáticamente\r\n if (typeof window === \"undefined\") {\r\n throw new Error(\r\n \"[loly:socket] lolySocket can only be called on the client side.\"\r\n );\r\n }\r\n\r\n const normalizedNamespace = namespace.startsWith(\"/\") ? namespace : `/${namespace}`;\r\n \r\n // Socket.IO: io(namespace, { path: '/wss' })\r\n // Socket.IO usa window.location.origin automáticamente\r\n // El path '/wss' es el endpoint del engine de Socket.IO\r\n // El namespace se maneja en el handshake\r\n\r\n const socket = io(normalizedNamespace, {\r\n path: \"/wss\",\r\n transports: [\"websocket\", \"polling\"],\r\n autoConnect: true,\r\n ...opts,\r\n });\r\n\r\n return socket;\r\n};\r\n"],"mappings":";AAAA,SAAS,UAAiD;AA0BnD,IAAM,aAAa,CACxB,WACA,SACW;AAGX,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,sBAAsB,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,SAAS;AAOjF,QAAM,SAAS,GAAG,qBAAqB;AAAA,IACrC,MAAM;AAAA,IACN,YAAY,CAAC,aAAa,SAAS;AAAA,IACnC,aAAa;AAAA,IACb,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AACT;","names":[]}
|
package/dist/runtime.cjs
CHANGED
|
@@ -923,9 +923,7 @@ function AppShell({
|
|
|
923
923
|
function setupHotReload() {
|
|
924
924
|
const nodeEnv = process.env.NODE_ENV || "production";
|
|
925
925
|
const isDev = nodeEnv === "development";
|
|
926
|
-
console.log(`[hot-reload] NODE_ENV: ${nodeEnv}, isDev: ${isDev}`);
|
|
927
926
|
if (!isDev) {
|
|
928
|
-
console.log("[hot-reload] Skipping hot reload setup (not in development mode)");
|
|
929
927
|
return;
|
|
930
928
|
}
|
|
931
929
|
console.log("[hot-reload] Setting up hot reload client...");
|
package/dist/runtime.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../modules/runtime/client/index.tsx","../modules/runtime/client/bootstrap.tsx","../modules/runtime/client/constants.ts","../modules/runtime/client/window-data.ts","../modules/runtime/client/route-matcher.ts","../modules/runtime/client/metadata.ts","../modules/runtime/client/AppShell.tsx","../modules/runtime/client/RouterView.tsx","../modules/react/cache/client-data-cache/index.ts","../modules/runtime/client/navigation.ts","../modules/runtime/client/RouterContext.tsx","../modules/runtime/client/hot-reload.ts"],"sourcesContent":["// Re-export all public types and functions\r\nexport type {\r\n ClientLoadedComponents,\r\n ClientRouteLoaded,\r\n ClientRouteMatch,\r\n RouteViewState,\r\n InitialData,\r\n} from \"./types\";\r\n\r\nexport { bootstrapClient } from \"./bootstrap\";\r\nexport type { AppShellProps } from \"./AppShell\";\r\n","import { hydrateRoot } from \"react-dom/client\";\r\nimport { APP_CONTAINER_ID } from \"./constants\";\r\nimport { getWindowData, getRouterData, setRouterData, setPreservedLayoutProps } from \"./window-data\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { AppShell } from \"./AppShell\";\r\nimport { setupHotReload } from \"./hot-reload\";\r\nimport type {\r\n InitialData,\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n} from \"./types\";\r\n\r\nexport async function loadInitialRoute(\r\n initialUrl: string,\r\n initialData: InitialData | null,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null\r\n): Promise<RouteViewState> {\r\n const isInitialNotFound = initialData?.notFound === true;\r\n const isInitialError = initialData?.error === true;\r\n\r\n let initialRoute: ClientRouteLoaded | null = null;\r\n let initialParams: Record<string, string> = {};\r\n let initialComponents = null;\r\n\r\n if (isInitialError && errorRoute) {\r\n initialRoute = errorRoute;\r\n initialParams = initialData?.params ?? {};\r\n initialComponents = await errorRoute.load();\r\n } else if (isInitialNotFound && notFoundRoute) {\r\n initialRoute = notFoundRoute;\r\n initialParams = {};\r\n initialComponents = await notFoundRoute.load();\r\n } else {\r\n const match = matchRouteClient(initialUrl, routes);\r\n if (match) {\r\n initialRoute = match.route;\r\n initialParams = match.params;\r\n initialComponents = await match.route.load();\r\n } else if (notFoundRoute) {\r\n initialRoute = notFoundRoute;\r\n initialParams = {};\r\n initialComponents = await notFoundRoute.load();\r\n } else {\r\n console.warn(\r\n `[client] No route match found for ${initialUrl}. Available routes:`,\r\n routes.map((r) => r.pattern)\r\n );\r\n }\r\n }\r\n\r\n return {\r\n url: initialUrl,\r\n route: initialRoute,\r\n params: initialParams,\r\n components: initialComponents,\r\n props: initialData?.props ?? {},\r\n };\r\n}\r\n\r\n/**\r\n * Initializes router data from server or builds it from the current URL.\r\n */\r\nfunction initializeRouterData(\r\n initialUrl: string,\r\n initialData: InitialData | null\r\n): void {\r\n let routerData = getRouterData();\r\n if (!routerData) {\r\n const url = new URL(initialUrl, window.location.origin);\r\n routerData = {\r\n pathname: url.pathname,\r\n params: initialData?.params || {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n }\r\n}\r\n\r\n/**\r\n * Loads and hydrates the initial route.\r\n */\r\nasync function hydrateInitialRoute(\r\n container: HTMLElement,\r\n initialUrl: string,\r\n initialData: InitialData | null,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null\r\n): Promise<void> {\r\n try {\r\n // Load initial route\r\n const initialState = await loadInitialRoute(\r\n initialUrl,\r\n initialData,\r\n routes,\r\n notFoundRoute,\r\n errorRoute\r\n );\r\n\r\n // Apply metadata if available\r\n if (initialData?.metadata) {\r\n try {\r\n applyMetadata(initialData.metadata);\r\n } catch (metadataError) {\r\n console.warn(\"[client] Error applying metadata:\", metadataError);\r\n // Continue even if metadata fails\r\n }\r\n }\r\n\r\n // Hydrate React root\r\n hydrateRoot(\r\n container,\r\n <AppShell\r\n initialState={initialState}\r\n routes={routes}\r\n notFoundRoute={notFoundRoute}\r\n errorRoute={errorRoute}\r\n />\r\n );\r\n } catch (error) {\r\n console.error(\r\n \"[client] Error loading initial route components for\",\r\n initialUrl,\r\n error\r\n );\r\n throw error; // Re-throw to handle in bootstrapClient\r\n }\r\n}\r\n\r\n/**\r\n * Bootstraps the client-side application.\r\n * \r\n * Simplified flow:\r\n * 1. Setup hot reload (development only)\r\n * 2. Get container and initial data\r\n * 3. Initialize router data\r\n * 4. Load and hydrate initial route\r\n *\r\n * @param routes - Array of client routes\r\n * @param notFoundRoute - Not-found route definition\r\n * @param errorRoute - Error route definition\r\n */\r\nexport function bootstrapClient(\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null = null\r\n): void {\r\n // 1. Setup hot reload (development only)\r\n setupHotReload();\r\n\r\n // Start bootstrap process\r\n (async () => {\r\n try {\r\n // 2. Get container and initial data\r\n const container = document.getElementById(APP_CONTAINER_ID);\r\n if (!container) {\r\n console.error(`\\n❌ [client] Hydration failed: Container #${APP_CONTAINER_ID} not found`);\r\n console.error(\"💡 This usually means:\");\r\n console.error(\" • The HTML structure doesn't match what React expects\");\r\n console.error(\" • The container was removed before hydration\");\r\n console.error(\" • There's a mismatch between SSR and client HTML\\n\");\r\n return;\r\n }\r\n\r\n const initialData = getWindowData();\r\n const initialUrl = window.location.pathname + window.location.search;\r\n\r\n // Preserve layout props from initial load (they come combined in initialData.props)\r\n // In SSR, layout hooks are always executed, so we need to extract layout props\r\n // For now, we'll preserve all props as layout props since they're combined\r\n // This ensures navigation items are available even in SPA navigation\r\n if (initialData?.props) {\r\n // In SSR, props are combined (layout + page), so we preserve them all as layout props\r\n // This is not perfect but ensures layout props are available in SPA navigation\r\n setPreservedLayoutProps(initialData.props);\r\n }\r\n\r\n // 3. Initialize router data\r\n initializeRouterData(initialUrl, initialData);\r\n\r\n // 4. Load and hydrate initial route\r\n await hydrateInitialRoute(\r\n container,\r\n initialUrl,\r\n initialData,\r\n routes,\r\n notFoundRoute,\r\n errorRoute\r\n );\r\n } catch (error) {\r\n // Fatal error during bootstrap - reload the page\r\n console.error(\"\\n❌ [client] Fatal error during bootstrap:\");\r\n console.error(error);\r\n if (error instanceof Error) {\r\n console.error(\"\\nError details:\");\r\n console.error(` Message: ${error.message}`);\r\n if (error.stack) {\r\n console.error(` Stack: ${error.stack}`);\r\n }\r\n }\r\n console.error(\"\\n💡 Attempting page reload to recover...\\n\");\r\n window.location.reload();\r\n }\r\n })();\r\n}\r\n\r\n","// Client-side constants (hardcoded to avoid alias resolution issues in Rspack)\r\nexport const WINDOW_DATA_KEY = \"__FW_DATA__\";\r\nexport const ROUTER_DATA_KEY = \"__LOLY_ROUTER_DATA__\";\r\nexport const APP_CONTAINER_ID = \"__app\";\r\n// Global key for navigate function fallback (exposed by AppShell for hydration timing issues)\r\nexport const ROUTER_NAVIGATE_KEY = \"__LOLY_ROUTER_NAVIGATE__\";\r\n\r\n","import { WINDOW_DATA_KEY, ROUTER_DATA_KEY } from \"./constants\";\r\nimport type { InitialData, RouterData } from \"./types\";\r\n\r\nconst LAYOUT_PROPS_KEY = \"__FW_LAYOUT_PROPS__\";\r\n\r\nexport function getWindowData(): InitialData | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return (window[WINDOW_DATA_KEY] as InitialData | undefined) ?? null;\r\n}\r\n\r\n/**\r\n * Gets preserved layout props from window storage.\r\n * Layout props are preserved across SPA navigations when layout hooks are skipped.\r\n */\r\nexport function getPreservedLayoutProps(): Record<string, any> | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return ((window as any)[LAYOUT_PROPS_KEY] as Record<string, any> | undefined) ?? null;\r\n}\r\n\r\n/**\r\n * Sets preserved layout props in window storage.\r\n * These props are used when layout hooks are skipped in SPA navigation.\r\n */\r\nexport function setPreservedLayoutProps(props: Record<string, any> | null): void {\r\n if (typeof window === \"undefined\") {\r\n return;\r\n }\r\n if (props === null) {\r\n delete (window as any)[LAYOUT_PROPS_KEY];\r\n } else {\r\n (window as any)[LAYOUT_PROPS_KEY] = props;\r\n }\r\n}\r\n\r\nexport function getRouterData(): RouterData | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return (window[ROUTER_DATA_KEY] as RouterData | undefined) ?? null;\r\n}\r\n\r\nexport function setWindowData(data: InitialData): void {\r\n window[WINDOW_DATA_KEY] = data;\r\n \r\n // Dispatch event for components to listen to (e.g. ThemeProvider)\r\n // This ensures components update when navigating in SPA mode\r\n if (typeof window !== \"undefined\") {\r\n window.dispatchEvent(\r\n new CustomEvent(\"fw-data-refresh\", {\r\n detail: { data },\r\n })\r\n );\r\n }\r\n}\r\n\r\nexport function setRouterData(data: RouterData): void {\r\n window[ROUTER_DATA_KEY] = data;\r\n \r\n // Dispatch event for router data updates\r\n if (typeof window !== \"undefined\") {\r\n window.dispatchEvent(\r\n new CustomEvent(\"fw-router-data-refresh\", {\r\n detail: { data },\r\n })\r\n );\r\n }\r\n}\r\n\r\nexport function getCurrentTheme(): string | null {\r\n return getWindowData()?.theme ?? null;\r\n}\r\n\r\n","import type { ClientRouteLoaded, ClientRouteMatch } from \"./types\";\r\n\r\nexport function buildClientRegexFromPattern(pattern: string): RegExp {\r\n const segments = pattern.split(\"/\").filter(Boolean);\r\n const regexParts: string[] = [];\r\n\r\n for (let i = 0; i < segments.length; i++) {\r\n const seg = segments[i];\r\n\r\n // catch-all [...slug]\r\n if (seg.startsWith(\"[...\") && seg.endsWith(\"]\")) {\r\n if (i !== segments.length - 1) {\r\n throw new Error(\r\n `Catch-all segment \"${seg}\" in \"${pattern}\" must be the last segment.`\r\n );\r\n }\r\n regexParts.push(\"(.+)\");\r\n continue;\r\n }\r\n\r\n // dynamic [id]\r\n if (seg.startsWith(\"[\") && seg.endsWith(\"]\")) {\r\n regexParts.push(\"([^/]+)\");\r\n continue;\r\n }\r\n\r\n // static segment\r\n const escaped = seg.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n regexParts.push(escaped);\r\n }\r\n\r\n const regexSource = \"^/\" + regexParts.join(\"/\") + \"/?$\";\r\n return new RegExp(regexSource);\r\n}\r\n\r\nexport function matchRouteClient(\r\n pathWithSearch: string,\r\n routes: ClientRouteLoaded[]\r\n): ClientRouteMatch | null {\r\n const [pathname] = pathWithSearch.split(\"?\");\r\n for (const r of routes) {\r\n const regex = buildClientRegexFromPattern(r.pattern);\r\n const match = regex.exec(pathname);\r\n if (!match) continue;\r\n\r\n const params: Record<string, string> = {};\r\n r.paramNames.forEach((name, idx) => {\r\n params[name] = decodeURIComponent(match[idx + 1] || \"\");\r\n });\r\n\r\n return { route: r, params };\r\n }\r\n return null;\r\n}\r\n\r\n","import type { PageMetadata } from \"@router/index\";\r\n\r\n/**\r\n * Helper to get or create a meta tag element\r\n */\r\nfunction getOrCreateMeta(\r\n selector: string,\r\n attributes: { name?: string; property?: string; httpEquiv?: string }\r\n): HTMLMetaElement {\r\n let meta = document.querySelector(selector) as HTMLMetaElement | null;\r\n if (!meta) {\r\n meta = document.createElement(\"meta\");\r\n if (attributes.name) meta.name = attributes.name;\r\n if (attributes.property) meta.setAttribute(\"property\", attributes.property);\r\n if (attributes.httpEquiv) meta.httpEquiv = attributes.httpEquiv;\r\n document.head.appendChild(meta);\r\n }\r\n return meta;\r\n}\r\n\r\n/**\r\n * Helper to get or create a link tag element\r\n */\r\nfunction getOrCreateLink(rel: string, href: string): HTMLLinkElement {\r\n const selector = `link[rel=\"${rel}\"]`;\r\n let link = document.querySelector(selector) as HTMLLinkElement | null;\r\n if (!link) {\r\n link = document.createElement(\"link\");\r\n link.rel = rel;\r\n link.href = href;\r\n document.head.appendChild(link);\r\n } else {\r\n link.href = href;\r\n }\r\n return link;\r\n}\r\n\r\n/**\r\n * Updates page metadata in the document head.\r\n * Supports all metadata fields including Open Graph, Twitter Cards, canonical URLs, etc.\r\n * \r\n * @param md - Page metadata object\r\n */\r\nexport function applyMetadata(md?: PageMetadata | null): void {\r\n if (!md) return;\r\n\r\n // Title\r\n if (md.title) {\r\n document.title = md.title;\r\n }\r\n\r\n // Description\r\n if (md.description) {\r\n const meta = getOrCreateMeta('meta[name=\"description\"]', { name: \"description\" });\r\n meta.content = md.description;\r\n }\r\n\r\n // Robots\r\n if (md.robots) {\r\n const meta = getOrCreateMeta('meta[name=\"robots\"]', { name: \"robots\" });\r\n meta.content = md.robots;\r\n }\r\n\r\n // Theme color\r\n if (md.themeColor) {\r\n const meta = getOrCreateMeta('meta[name=\"theme-color\"]', { name: \"theme-color\" });\r\n meta.content = md.themeColor;\r\n }\r\n\r\n // Viewport\r\n if (md.viewport) {\r\n const meta = getOrCreateMeta('meta[name=\"viewport\"]', { name: \"viewport\" });\r\n meta.content = md.viewport;\r\n }\r\n\r\n // Canonical URL\r\n if (md.canonical) {\r\n getOrCreateLink(\"canonical\", md.canonical);\r\n }\r\n\r\n // Open Graph tags\r\n if (md.openGraph) {\r\n const og = md.openGraph;\r\n\r\n if (og.title) {\r\n const meta = getOrCreateMeta('meta[property=\"og:title\"]', { property: \"og:title\" });\r\n meta.content = og.title;\r\n }\r\n\r\n if (og.description) {\r\n const meta = getOrCreateMeta('meta[property=\"og:description\"]', { property: \"og:description\" });\r\n meta.content = og.description;\r\n }\r\n\r\n if (og.type) {\r\n const meta = getOrCreateMeta('meta[property=\"og:type\"]', { property: \"og:type\" });\r\n meta.content = og.type;\r\n }\r\n\r\n if (og.url) {\r\n const meta = getOrCreateMeta('meta[property=\"og:url\"]', { property: \"og:url\" });\r\n meta.content = og.url;\r\n }\r\n\r\n if (og.image) {\r\n if (typeof og.image === \"string\") {\r\n const meta = getOrCreateMeta('meta[property=\"og:image\"]', { property: \"og:image\" });\r\n meta.content = og.image;\r\n } else {\r\n const meta = getOrCreateMeta('meta[property=\"og:image\"]', { property: \"og:image\" });\r\n meta.content = og.image.url;\r\n\r\n if (og.image.width) {\r\n const metaWidth = getOrCreateMeta('meta[property=\"og:image:width\"]', { property: \"og:image:width\" });\r\n metaWidth.content = String(og.image.width);\r\n }\r\n\r\n if (og.image.height) {\r\n const metaHeight = getOrCreateMeta('meta[property=\"og:image:height\"]', { property: \"og:image:height\" });\r\n metaHeight.content = String(og.image.height);\r\n }\r\n\r\n if (og.image.alt) {\r\n const metaAlt = getOrCreateMeta('meta[property=\"og:image:alt\"]', { property: \"og:image:alt\" });\r\n metaAlt.content = og.image.alt;\r\n }\r\n }\r\n }\r\n\r\n if (og.siteName) {\r\n const meta = getOrCreateMeta('meta[property=\"og:site_name\"]', { property: \"og:site_name\" });\r\n meta.content = og.siteName;\r\n }\r\n\r\n if (og.locale) {\r\n const meta = getOrCreateMeta('meta[property=\"og:locale\"]', { property: \"og:locale\" });\r\n meta.content = og.locale;\r\n }\r\n }\r\n\r\n // Twitter Card tags\r\n if (md.twitter) {\r\n const twitter = md.twitter;\r\n\r\n if (twitter.card) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:card\"]', { name: \"twitter:card\" });\r\n meta.content = twitter.card;\r\n }\r\n\r\n if (twitter.title) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:title\"]', { name: \"twitter:title\" });\r\n meta.content = twitter.title;\r\n }\r\n\r\n if (twitter.description) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:description\"]', { name: \"twitter:description\" });\r\n meta.content = twitter.description;\r\n }\r\n\r\n if (twitter.image) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:image\"]', { name: \"twitter:image\" });\r\n meta.content = twitter.image;\r\n }\r\n\r\n if (twitter.imageAlt) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:image:alt\"]', { name: \"twitter:image:alt\" });\r\n meta.content = twitter.imageAlt;\r\n }\r\n\r\n if (twitter.site) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:site\"]', { name: \"twitter:site\" });\r\n meta.content = twitter.site;\r\n }\r\n\r\n if (twitter.creator) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:creator\"]', { name: \"twitter:creator\" });\r\n meta.content = twitter.creator;\r\n }\r\n }\r\n\r\n // Custom meta tags\r\n if (md.metaTags && Array.isArray(md.metaTags)) {\r\n md.metaTags.forEach((tag) => {\r\n let selector = \"\";\r\n if (tag.name) {\r\n selector = `meta[name=\"${tag.name}\"]`;\r\n } else if (tag.property) {\r\n selector = `meta[property=\"${tag.property}\"]`;\r\n } else if (tag.httpEquiv) {\r\n selector = `meta[http-equiv=\"${tag.httpEquiv}\"]`;\r\n }\r\n\r\n if (selector) {\r\n const meta = getOrCreateMeta(selector, {\r\n name: tag.name,\r\n property: tag.property,\r\n httpEquiv: tag.httpEquiv,\r\n });\r\n meta.content = tag.content;\r\n }\r\n });\r\n }\r\n\r\n // Custom link tags\r\n if (md.links && Array.isArray(md.links)) {\r\n md.links.forEach((link) => {\r\n getOrCreateLink(link.rel, link.href);\r\n // Note: Additional attributes like 'as', 'crossorigin', 'type' would need\r\n // more complex logic to update existing links. For now, we just ensure\r\n // the link exists with the correct href.\r\n });\r\n }\r\n}\r\n\r\n","import { useEffect, useState, useRef, useCallback } from \"react\";\r\nimport { RouterView } from \"./RouterView\";\r\nimport {\r\n navigate,\r\n createClickHandler,\r\n createPopStateHandler,\r\n createHoverHandler,\r\n type NavigationHandlers,\r\n} from \"./navigation\";\r\nimport { RouterContext } from \"./RouterContext\";\r\nimport { ROUTER_NAVIGATE_KEY, WINDOW_DATA_KEY } from \"./constants\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport type {\r\n RouteViewState,\r\n ClientRouteLoaded,\r\n} from \"./types\";\r\n\r\nexport interface AppShellProps {\r\n initialState: RouteViewState;\r\n routes: ClientRouteLoaded[];\r\n notFoundRoute: ClientRouteLoaded | null;\r\n errorRoute: ClientRouteLoaded | null;\r\n}\r\n\r\nexport function AppShell({\r\n initialState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n}: AppShellProps) {\r\n const [state, setState] = useState<RouteViewState>(initialState);\r\n const handlersRef = useRef<NavigationHandlers>({\r\n setState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n });\r\n\r\n useEffect(() => {\r\n handlersRef.current = {\r\n setState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n };\r\n }, [routes, notFoundRoute, errorRoute]);\r\n\r\n // Create navigate function for router context\r\n const handleNavigate = useCallback(\r\n async (\r\n nextUrl: string,\r\n options?: { revalidate?: boolean; replace?: boolean }\r\n ) => {\r\n await navigate(nextUrl, handlersRef.current, {\r\n revalidate: options?.revalidate,\r\n });\r\n },\r\n []\r\n );\r\n\r\n /**\r\n * SOLUTION: Expose navigate function globally as fallback\r\n * \r\n * During React hydration, components rendered in layouts may execute before\r\n * RouterContext is fully available. By exposing navigate globally, useRouter\r\n * can access it even when the context isn't ready yet, ensuring SPA navigation\r\n * works correctly from the first render.\r\n * \r\n * This is similar to how window.__FW_DATA__ is used for initial data.\r\n */\r\n useEffect(() => {\r\n if (typeof window !== \"undefined\") {\r\n window[ROUTER_NAVIGATE_KEY] = handleNavigate;\r\n return () => {\r\n delete window[ROUTER_NAVIGATE_KEY];\r\n };\r\n }\r\n }, [handleNavigate]);\r\n\r\n useEffect(() => {\r\n let isMounted = true;\r\n\r\n async function handleNavigateInternal(\r\n nextUrl: string,\r\n options?: { revalidate?: boolean }\r\n ) {\r\n if (!isMounted) return;\r\n await navigate(nextUrl, handlersRef.current, options);\r\n }\r\n\r\n const handleClick = createClickHandler(handleNavigateInternal);\r\n const handlePopState = createPopStateHandler(handleNavigateInternal);\r\n const handleHover = createHoverHandler(routes, notFoundRoute);\r\n\r\n window.addEventListener(\"click\", handleClick, false);\r\n window.addEventListener(\"popstate\", handlePopState, false);\r\n window.addEventListener(\"mouseover\", handleHover, false);\r\n\r\n return () => {\r\n isMounted = false;\r\n window.removeEventListener(\"click\", handleClick, false);\r\n window.removeEventListener(\"popstate\", handlePopState, false);\r\n window.removeEventListener(\"mouseover\", handleHover, false);\r\n };\r\n }, [routes, notFoundRoute]);\r\n\r\n // Listen for data refresh events and update state when current route is revalidated\r\n useEffect(() => {\r\n const handleDataRefresh = () => {\r\n const freshData = window[WINDOW_DATA_KEY];\r\n \r\n if (!freshData) return;\r\n \r\n const currentPathname = window.location.pathname;\r\n const freshPathname = freshData.pathname;\r\n \r\n if (freshPathname === currentPathname) {\r\n if (freshData.metadata !== undefined) {\r\n applyMetadata(freshData.metadata);\r\n }\r\n \r\n setState((prevState) => ({\r\n ...prevState,\r\n props: freshData.props ?? prevState.props,\r\n params: freshData.params ?? prevState.params,\r\n }));\r\n }\r\n };\r\n\r\n window.addEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n\r\n return () => {\r\n window.removeEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n };\r\n }, []); // Empty deps - only register once, not when state.url changes\r\n\r\n const isError = state.route === errorRoute;\r\n const isNotFound = state.route === notFoundRoute;\r\n const routeType = isError ? \"error\" : isNotFound ? \"notfound\" : \"normal\";\r\n const routeKey = `${state.url}:${routeType}`;\r\n\r\n return (\r\n <RouterContext.Provider value={{ navigate: handleNavigate }}>\r\n <RouterView key={routeKey} state={state} />\r\n </RouterContext.Provider>\r\n );\r\n}\r\n\r\n","import type { RouteViewState } from \"./types\";\r\n\r\nexport function RouterView({ state }: { state: RouteViewState }) {\r\n if (!state.route) {\r\n // Don't show 404 if we're waiting for components to load\r\n if (state.components === null) {\r\n return null;\r\n }\r\n return <h1>404 - Route not found</h1>;\r\n }\r\n\r\n if (!state.components) {\r\n return null;\r\n }\r\n\r\n const { Page, layouts } = state.components;\r\n const { params, props } = state;\r\n\r\n let element = <Page params={params} {...props} />;\r\n\r\n const layoutChain = layouts.slice().reverse();\r\n for (const Layout of layoutChain) {\r\n element = (\r\n <Layout params={params} {...props}>\r\n {element}\r\n </Layout>\r\n );\r\n }\r\n\r\n return element;\r\n}\r\n\r\n","import type { PageMetadata } from \"@router/index\";\n\n/**\n * Response data structure from server for route data requests\n */\nexport type RouteDataResponse = {\n /** Combined props (layout + page) - kept for backward compatibility */\n props?: Record<string, unknown>;\n /** Layout props (from layout.server.hook.ts) - only present when layout hooks were executed */\n layoutProps?: Record<string, unknown>;\n /** Page props (from page.server.hook.ts) - always present in data requests */\n pageProps?: Record<string, unknown>;\n metadata?: PageMetadata | null;\n theme?: string;\n redirect?: { destination: string; permanent?: boolean };\n notFound?: boolean;\n error?: boolean;\n message?: string;\n params?: Record<string, string>;\n};\n\ntype RouteData = {\n ok: boolean;\n status: number;\n json: RouteDataResponse;\n};\n\ntype CacheEntry =\n | { status: \"pending\"; promise: Promise<RouteData> }\n | { status: \"fulfilled\"; value: RouteData }\n | { status: \"rejected\"; error: any };\n\n// Use window to guarantee a single shared cache instance\n// across all bundles/modules\nconst CACHE_KEY = \"__FW_DATA_CACHE__\";\n\n// Maximum number of entries in the cache (LRU)\nconst MAX_CACHE_SIZE = 100;\n\ntype CacheStore = {\n data: Map<string, CacheEntry>;\n index: Map<string, Set<string>>; // pathBase -> Set of keys\n lru: string[]; // Ordered list: most recent at end, oldest at start\n};\n\nfunction getCacheStore(): CacheStore {\n if (typeof window !== \"undefined\") {\n if (!(window as any)[CACHE_KEY]) {\n (window as any)[CACHE_KEY] = {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n }\n return (window as any)[CACHE_KEY];\n }\n // Fallback for SSR (though this shouldn't be used on the client)\n return {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n}\n\nconst cacheStore = getCacheStore();\nconst dataCache = cacheStore.data;\nconst pathIndex = cacheStore.index;\nconst lru = cacheStore.lru;\n\n// Helper functions for cache management\n\n/**\n * Extract base path from a cache key (removes query params)\n */\nfunction extractPathBase(key: string): string {\n return key.split(\"?\")[0];\n}\n\n/**\n * Add key to path index\n */\nfunction addToIndex(key: string): void {\n const pathBase = extractPathBase(key);\n if (!pathIndex.has(pathBase)) {\n pathIndex.set(pathBase, new Set());\n }\n pathIndex.get(pathBase)!.add(key);\n}\n\n/**\n * Remove key from path index\n */\nfunction removeFromIndex(key: string): void {\n const pathBase = extractPathBase(key);\n const keys = pathIndex.get(pathBase);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n pathIndex.delete(pathBase);\n }\n }\n}\n\n/**\n * Update LRU order - move key to end (most recent)\n */\nfunction updateLRU(key: string): void {\n const index = lru.indexOf(key);\n if (index !== -1) {\n lru.splice(index, 1);\n }\n lru.push(key);\n}\n\n/**\n * Remove oldest entries if cache exceeds MAX_CACHE_SIZE\n */\nfunction evictOldest(): void {\n while (lru.length >= MAX_CACHE_SIZE && lru.length > 0) {\n const oldestKey = lru.shift()!;\n dataCache.delete(oldestKey);\n removeFromIndex(oldestKey);\n }\n}\n\n/**\n * Set cache entry and maintain indexes\n */\nfunction setCacheEntry(key: string, entry: CacheEntry): void {\n const existingEntry = dataCache.get(key);\n const wasFulfilled = existingEntry?.status === \"fulfilled\";\n \n dataCache.set(key, entry);\n \n // Only track fulfilled entries in LRU and index (not pending/rejected)\n if (entry.status === \"fulfilled\") {\n // Add to index if it wasn't already fulfilled (new entry or transition from pending/rejected)\n if (!wasFulfilled) {\n addToIndex(key);\n }\n updateLRU(key);\n evictOldest();\n } else if (wasFulfilled) {\n // If entry was fulfilled and now isn't (transitioning to pending/rejected), remove from index\n removeFromIndex(key);\n }\n}\n\n/**\n * Delete cache entry and clean up indexes\n */\nfunction deleteCacheEntry(key: string): void {\n if (dataCache.has(key)) {\n dataCache.delete(key);\n removeFromIndex(key);\n const lruIndex = lru.indexOf(key);\n if (lruIndex !== -1) {\n lru.splice(lruIndex, 1);\n }\n }\n}\n\nfunction buildDataUrl(url: string): string {\n return url + (url.includes(\"?\") ? \"&\" : \"?\") + \"__fw_data=1\";\n}\n\nasync function fetchRouteDataOnce(\n url: string,\n skipLayoutHooks: boolean = true\n): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const headers: Record<string, string> = {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n };\n\n // Send header to skip layout hooks execution in SPA navigation\n // Only skip if skipLayoutHooks is true (normal SPA navigation)\n // If false (revalidate), don't send header to force execution of all hooks\n if (skipLayoutHooks) {\n headers[\"x-skip-layout-hooks\"] = \"true\";\n }\n\n const res = await fetch(dataUrl, { headers });\n\n let json: any = {};\n\n try {\n const text = await res.text();\n if (text) {\n json = JSON.parse(text);\n }\n } catch (parseError) {\n console.error(\n \"[client][cache] Failed to parse response as JSON:\",\n parseError\n );\n }\n\n const result: RouteData = {\n ok: res.ok,\n status: res.status,\n json,\n };\n\n return result;\n}\n\n/**\n * Revalidates route data by removing it from the cache.\n * The next time you navigate to this route, fresh data will be fetched from the server.\n * This is a client-side function and does not require a server-side revalidation.\n *\n * @param path - The route path to revalidate (e.g., '/posts/1' or '/posts/1?page=2')\n * If query params are not included, revalidates all variants of that route.\n *\n * @example\n * ```ts\n * // After saving something to the DB, revalidate the route\n * await saveToDatabase(data);\n * revalidatePath('/posts');\n * \n * // Revalidate a specific route with query params\n * revalidatePath('/posts?page=2');\n * ```\n */\nexport function revalidatePath(path: string, skipAutoRevalidate: boolean = false): void {\n // Normalize the base path (without query params)\n const normalizedPath = path.split(\"?\")[0];\n const hasQueryParams = path.includes(\"?\");\n \n // Get all keys for this path base from index (O(1) lookup)\n const keysForPath = pathIndex.get(normalizedPath);\n \n if (!keysForPath || keysForPath.size === 0) {\n return; // No entries to revalidate\n }\n \n // If the path includes specific query params, extract them\n let specificQueryParams: string | undefined;\n if (hasQueryParams) {\n const queryPart = path.split(\"?\")[1];\n // Sort query params for consistent comparison\n specificQueryParams = queryPart\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n }\n \n // Iterate only over keys for this path (much smaller set)\n const keysToDelete: string[] = [];\n for (const key of keysForPath) {\n // If specific query params were specified, check if they match\n if (hasQueryParams && specificQueryParams) {\n const [, keyQuery = \"\"] = key.split(\"?\");\n const keyQueryParams = keyQuery\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (keyQueryParams === specificQueryParams) {\n keysToDelete.push(key);\n }\n } else {\n // If no specific query params, revalidate all variants\n keysToDelete.push(key);\n }\n }\n \n // Delete matching entries\n keysToDelete.forEach((key) => {\n deleteCacheEntry(key);\n });\n \n // If the revalidated path matches the current route, automatically refresh data\n // UNLESS skipAutoRevalidate is true (to prevent recursive calls from revalidate())\n if (!skipAutoRevalidate && typeof window !== \"undefined\") {\n const currentPathname = window.location.pathname;\n const currentSearch = window.location.search;\n const matchesCurrentPath = normalizedPath === currentPathname;\n \n if (matchesCurrentPath) {\n if (hasQueryParams && specificQueryParams) {\n const currentQueryParams = currentSearch\n .replace(\"?\", \"\")\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (currentQueryParams === specificQueryParams) {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n } else {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n }\n }\n}\n\n/**\n * Revalidates and refreshes the current page data.\n * Similar to Next.js's `router.refresh()`.\n * \n * This function:\n * 1. Removes the current route from cache\n * 2. Fetches fresh data from the server\n * 3. Updates window.__FW_DATA__ with the new data\n * 4. Dispatches a 'fw-data-refresh' event for components to listen to\n * \n * @returns Promise that resolves with the fresh route data\n * \n * @example\n * ```ts\n * // Refresh current page data after a mutation\n * await revalidate();\n * ```\n */\n// Flag to prevent recursive calls to revalidate()\nlet isRevalidating = false;\n\nexport async function revalidate(): Promise<RouteData> {\n if (typeof window === \"undefined\") {\n throw new Error(\"revalidate() can only be called on the client\");\n }\n\n // Prevent multiple simultaneous revalidations\n if (isRevalidating) {\n // Wait for the current revalidation to complete\n const key = buildDataUrl(window.location.pathname + window.location.search);\n const entry = dataCache.get(key);\n if (entry && entry.status === \"pending\") {\n return entry.promise;\n }\n // If no pending entry, something went wrong, allow the call\n }\n\n isRevalidating = true;\n try {\n const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n // Pass a flag to prevent revalidatePath from calling revalidate() again (recursive call)\n revalidatePath(pathname, true); // true = skip auto-revalidate\n \n // Fetch fresh data\n const freshData = await getRouteData(pathname, { revalidate: true });\n \n // Update window.__FW_DATA__ if it exists\n if ((window as any).__FW_DATA__ && freshData.ok && freshData.json) {\n const currentData = (window as any).__FW_DATA__;\n \n // Update preserved layout props if new ones were returned\n if (freshData.json.layoutProps !== undefined && freshData.json.layoutProps !== null) {\n (window as any).__FW_LAYOUT_PROPS__ = freshData.json.layoutProps;\n }\n \n // Combine layout props (new or preserved) + page props\n let combinedProps = currentData.props || {};\n if (freshData.json.layoutProps !== undefined && freshData.json.layoutProps !== null) {\n // Use new layout props\n combinedProps = {\n ...freshData.json.layoutProps,\n ...(freshData.json.pageProps ?? freshData.json.props ?? {}),\n };\n } else if (freshData.json.pageProps !== undefined) {\n // Use preserved layout props + new page props\n const preservedLayoutProps = (window as any).__FW_LAYOUT_PROPS__ || {};\n combinedProps = {\n ...preservedLayoutProps,\n ...freshData.json.pageProps,\n };\n } else if (freshData.json.props) {\n // Fallback to combined props\n combinedProps = freshData.json.props;\n }\n \n (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: combinedProps,\n metadata: freshData.json.metadata ?? currentData.metadata ?? null,\n notFound: freshData.json.notFound ?? false,\n error: freshData.json.error ?? false,\n };\n \n // Dispatch event for components to listen to\n window.dispatchEvent(new CustomEvent(\"fw-data-refresh\", {\n detail: { data: freshData },\n }));\n }\n \n return freshData;\n } finally {\n isRevalidating = false;\n }\n}\n\n/**\n * @deprecated Use `revalidatePath()` instead. This function is kept for backwards compatibility.\n */\nexport function revalidateRouteData(url: string): void {\n revalidatePath(url);\n}\n\nexport function prefetchRouteData(url: string): void {\n const key = buildDataUrl(url);\n\n const cached = dataCache.get(key);\n\n if (cached && cached.status !== \"rejected\") {\n // Update LRU if it exists and is fulfilled\n if (cached.status === \"fulfilled\") {\n updateLRU(key);\n }\n return;\n }\n\n // Prefetch uses skipLayoutHooks: true (normal navigation behavior)\n const promise = fetchRouteDataOnce(url, true)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error prefetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n}\n\nexport type GetRouteDataOptions = {\n /**\n * If true, forces revalidation of route data,\n * ignoring the cache and fetching fresh data from the server.\n * Similar to Next.js's `router.refresh()` behavior.\n */\n revalidate?: boolean;\n};\n\nexport async function getRouteData(\n url: string,\n options?: GetRouteDataOptions\n): Promise<RouteData> {\n const key = buildDataUrl(url);\n\n // If revalidation is requested, remove the entry from cache\n // This ensures we don't reuse pending or fulfilled entries\n if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry && !options?.revalidate) {\n // Only use cached entry if not revalidating\n if (entry.status === \"fulfilled\") {\n // Update LRU: mark as recently used\n updateLRU(key);\n return entry.value;\n }\n if (entry.status === \"pending\") {\n // Return existing pending promise to avoid duplicate requests\n return entry.promise;\n }\n }\n\n // No entry in cache (or revalidating), fetch it\n // skipLayoutHooks: true for normal SPA navigation, false when revalidating\n const skipLayoutHooks = !options?.revalidate;\n \n // Check again if an entry was added while we were processing (race condition)\n const currentEntry = dataCache.get(key);\n if (currentEntry && !options?.revalidate) {\n if (currentEntry.status === \"fulfilled\") {\n updateLRU(key);\n return currentEntry.value;\n }\n if (currentEntry.status === \"pending\") {\n return currentEntry.promise;\n }\n }\n \n // Create a new promise for this fetch\n const promise = fetchRouteDataOnce(url, skipLayoutHooks)\n .then((value) => {\n // Only set cache entry if this is still the current fetch for this key\n // This prevents race conditions where multiple revalidations happen simultaneously\n const entryAfterFetch = dataCache.get(key);\n if (!entryAfterFetch || entryAfterFetch.status === \"pending\") {\n setCacheEntry(key, { status: \"fulfilled\", value });\n }\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n const entryAfterFetch = dataCache.get(key);\n if (!entryAfterFetch || entryAfterFetch.status === \"pending\") {\n dataCache.set(key, { status: \"rejected\", error });\n }\n throw error;\n });\n\n // Set pending entry - if revalidating, we already deleted it, so this is safe\n dataCache.set(key, { status: \"pending\", promise });\n \n return promise;\n}\n","import { getRouteData } from \"../../react/cache/index\";\r\nimport type { RouteDataResponse } from \"../../react/cache/client-data-cache\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { setWindowData, getCurrentTheme, setRouterData, getPreservedLayoutProps, setPreservedLayoutProps } from \"./window-data\";\r\nimport type {\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n InitialData,\r\n RouterData,\r\n ClientLoadedComponents,\r\n} from \"./types\";\r\n\r\nexport type NavigationHandlers = {\r\n setState: (state: RouteViewState) => void;\r\n routes: ClientRouteLoaded[];\r\n notFoundRoute: ClientRouteLoaded | null;\r\n errorRoute: ClientRouteLoaded | null;\r\n};\r\n\r\nasync function handleErrorRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n errorRoute: ClientRouteLoaded,\r\n setState: (state: RouteViewState) => void\r\n): Promise<boolean> {\r\n try {\r\n const components = await errorRoute.load();\r\n \r\n // Get theme: prioritize cookie, then server, then window data, then default\r\n let theme: string = \"light\";\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) theme = currentTheme;\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Preserve layout props if not in response (SPA navigation)\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n const pageProps = json.pageProps ?? json.props ?? {\r\n error: json.message || \"An error occurred\",\r\n };\r\n\r\n const errorProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme,\r\n };\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: json.params || {},\r\n props: errorProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: false,\r\n error: true,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: json.params || {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n setState({\r\n url: nextUrl,\r\n route: errorRoute,\r\n params: json.params || {},\r\n components,\r\n props: errorProps,\r\n });\r\n return true;\r\n } catch (loadError) {\r\n console.error(\"\\n❌ [client] Error loading error route components:\");\r\n console.error(loadError);\r\n if (loadError instanceof Error) {\r\n console.error(` Message: ${loadError.message}`);\r\n if (loadError.stack) {\r\n console.error(` Stack: ${loadError.stack.split('\\n').slice(0, 3).join('\\n ')}`);\r\n }\r\n }\r\n console.error(\"💡 Falling back to full page reload\\n\");\r\n window.location.href = nextUrl;\r\n return false;\r\n }\r\n}\r\n\r\nasync function handleNotFoundRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n notFoundRoute: ClientRouteLoaded | null,\r\n setState: (state: RouteViewState) => void\r\n): Promise<void> {\r\n // Get theme: prioritize cookie, then server, then window data, then default\r\n let theme: string = \"light\";\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) theme = currentTheme;\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Preserve layout props if not in response (SPA navigation)\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n const pageProps = json.pageProps ?? json.props ?? {};\r\n\r\n const notFoundProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme,\r\n };\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: {},\r\n props: notFoundProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: true,\r\n error: false,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n if (notFoundRoute) {\r\n const components = await notFoundRoute.load();\r\n setState({\r\n url: nextUrl,\r\n route: notFoundRoute,\r\n params: {},\r\n components,\r\n props: notFoundProps,\r\n });\r\n } else {\r\n setState({\r\n url: nextUrl,\r\n route: null,\r\n params: {},\r\n components: null,\r\n props: {},\r\n });\r\n }\r\n}\r\n\r\nasync function handleNormalRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n routes: ClientRouteLoaded[],\r\n setState: (state: RouteViewState) => void\r\n): Promise<boolean> {\r\n applyMetadata(json.metadata ?? null);\r\n \r\n // Get theme: prioritize cookie (source of truth), then server response, then window data, then default\r\n // Cookie is the source of truth because it persists across navigation\r\n let theme: string = \"light\"; // Default\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) {\r\n theme = currentTheme;\r\n }\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Handle layout props preservation:\r\n // - If layoutProps are in response, use them and preserve them\r\n // - If layoutProps are NOT in response (layout hooks were skipped), use preserved ones\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n // Layout hooks were executed, use new layout props and preserve them\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n // Layout hooks were skipped, use preserved layout props\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n // Get page props (always from response)\r\n const pageProps = json.pageProps ?? json.props ?? {};\r\n\r\n // Combine: layout props (preserved or new) + page props (always new)\r\n // Page props override layout props if there's a conflict\r\n const combinedProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme, // Always include theme\r\n };\r\n\r\n const matched = matchRouteClient(nextUrl, routes);\r\n\r\n if (!matched) {\r\n window.location.href = nextUrl;\r\n return false;\r\n }\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: matched.params,\r\n props: combinedProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: false,\r\n error: false,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: matched.params,\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n // Use prefetched route if available, otherwise load it\r\n const prefetched = prefetchedRoutes.get(matched.route);\r\n const components = prefetched ? await prefetched : await matched.route.load();\r\n \r\n // Cache the loaded route for future use\r\n if (!prefetched) {\r\n prefetchedRoutes.set(matched.route, Promise.resolve(components));\r\n }\r\n\r\n window.scrollTo({\r\n top: 0,\r\n behavior: \"smooth\",\r\n });\r\n\r\n setState({\r\n url: nextUrl,\r\n route: matched.route,\r\n params: matched.params,\r\n components,\r\n props: combinedProps,\r\n });\r\n\r\n return true;\r\n}\r\n\r\nexport type NavigateOptions = {\r\n /**\r\n * If true, forces revalidation of route data,\r\n * ignoring the cache and fetching fresh data from the server.\r\n * Similar to Next.js's `router.refresh()` behavior.\r\n */\r\n revalidate?: boolean;\r\n};\r\n\r\nexport async function navigate(\r\n nextUrl: string,\r\n handlers: NavigationHandlers,\r\n options?: NavigateOptions\r\n): Promise<void> {\r\n const { setState, routes, notFoundRoute, errorRoute } = handlers;\r\n\r\n try {\r\n const { ok, json } = await getRouteData(nextUrl, {\r\n revalidate: options?.revalidate,\r\n });\r\n\r\n if (json && json.error) {\r\n if (errorRoute) {\r\n const handled = await handleErrorRoute(\r\n nextUrl,\r\n json,\r\n errorRoute,\r\n setState\r\n );\r\n if (handled) return;\r\n } else {\r\n console.warn(\r\n \"[client] Error route not available, reloading page.\",\r\n errorRoute\r\n );\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n }\r\n\r\n // 🔴 HTTP error (404/500/etc)\r\n if (!ok) {\r\n if (json?.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n\r\n // Redirect via JSON\r\n if (json.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n\r\n // Handle notFound\r\n if (json.notFound) {\r\n await handleNotFoundRoute(nextUrl, json, notFoundRoute, setState);\r\n return;\r\n }\r\n\r\n // Normal route\r\n await handleNormalRoute(nextUrl, json, routes, setState);\r\n } catch (err) {\r\n console.error(\"[client] Error fetching FW data:\", err);\r\n window.location.href = nextUrl;\r\n }\r\n}\r\n\r\n// Cache for prefetched routes to avoid loading twice\r\nconst prefetchedRoutes = new WeakMap<ClientRouteLoaded, Promise<ClientLoadedComponents>>();\r\n\r\n/**\r\n * Prefetches a route's components when user hovers over a link.\r\n * This improves perceived performance by loading the route before the user clicks.\r\n */\r\nfunction prefetchRoute(\r\n url: string,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null\r\n): void {\r\n const [pathname] = url.split(\"?\");\r\n const matched = matchRouteClient(pathname, routes);\r\n \r\n if (!matched) {\r\n // If no match, might be not-found route\r\n if (notFoundRoute) {\r\n const existing = prefetchedRoutes.get(notFoundRoute);\r\n if (!existing) {\r\n const promise = notFoundRoute.load();\r\n prefetchedRoutes.set(notFoundRoute, promise);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Prefetch the matched route if not already prefetched\r\n const existing = prefetchedRoutes.get(matched.route);\r\n if (!existing) {\r\n const promise = matched.route.load();\r\n prefetchedRoutes.set(matched.route, promise);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a hover handler for prefetching routes on link hover.\r\n */\r\nexport function createHoverHandler(\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null\r\n): (ev: MouseEvent) => void {\r\n return function handleHover(ev: MouseEvent) {\r\n try {\r\n const target = ev.target as HTMLElement | null;\r\n if (!target) return;\r\n\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) return;\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) return;\r\n if (href.startsWith(\"#\")) return;\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) return;\r\n if (anchor.target && anchor.target !== \"_self\") return;\r\n\r\n const nextUrl = url.pathname + url.search;\r\n const currentUrl = window.location.pathname + window.location.search;\r\n if (nextUrl === currentUrl) return;\r\n\r\n // Prefetch the route\r\n prefetchRoute(nextUrl, routes, notFoundRoute);\r\n } catch (error) {\r\n // Silently fail - prefetch is an optimization, not critical\r\n }\r\n };\r\n}\r\n\r\nexport function createClickHandler(\r\n navigate: (url: string, options?: NavigateOptions) => void\r\n): (ev: MouseEvent) => void {\r\n return function handleClick(ev: MouseEvent) {\r\n try {\r\n // Exit early if event was already prevented\r\n if (ev.defaultPrevented) return;\r\n \r\n // Verify it's a real mouse event (not synthetic or keyboard)\r\n if (ev.type !== \"click\") return;\r\n if (ev.button !== 0) return;\r\n if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;\r\n \r\n // Verify event has valid coordinates (real mouse events have them)\r\n const target = ev.target as HTMLElement | null;\r\n if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {\r\n // Could be a synthetic event, be more cautious\r\n if (target) {\r\n const tagName = target.tagName.toLowerCase();\r\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"button\" || tagName === \"select\") {\r\n return; // It's an input, don't process synthetic events\r\n }\r\n }\r\n }\r\n\r\n if (!target) return;\r\n\r\n // Check FIRST if target is an interactive element (faster)\r\n const tagName = target.tagName.toLowerCase();\r\n if (\r\n tagName === \"input\" ||\r\n tagName === \"textarea\" ||\r\n tagName === \"button\" ||\r\n tagName === \"select\" ||\r\n target.isContentEditable ||\r\n target.getAttribute(\"contenteditable\") === \"true\"\r\n ) {\r\n return; // It's an interactive element, don't process\r\n }\r\n\r\n // Check if it's inside an interactive element using closest (more efficient than composedPath)\r\n const interactiveParent = target.closest(\"input, textarea, button, select, [contenteditable], label\");\r\n if (interactiveParent) {\r\n // If parent is a label, check if it has an associated control\r\n if (interactiveParent.tagName.toLowerCase() === \"label\") {\r\n const label = interactiveParent as HTMLLabelElement;\r\n if (label.control) {\r\n return; // Label has an associated control (input, etc)\r\n }\r\n } else {\r\n return; // It's inside an interactive element\r\n }\r\n }\r\n\r\n // Only search for anchor if it's not an interactive element\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) return;\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) return;\r\n if (href.startsWith(\"#\")) return;\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) return;\r\n if (anchor.target && anchor.target !== \"_self\") return;\r\n\r\n ev.preventDefault();\r\n\r\n const nextUrl = url.pathname + url.search;\r\n const currentUrl = window.location.pathname + window.location.search;\r\n if (nextUrl === currentUrl) return;\r\n\r\n // Detect if link has data-revalidate to force revalidation\r\n const shouldRevalidate =\r\n anchor.hasAttribute(\"data-revalidate\") &&\r\n anchor.getAttribute(\"data-revalidate\") !== \"false\";\r\n\r\n window.history.pushState({}, \"\", nextUrl);\r\n navigate(nextUrl, shouldRevalidate ? { revalidate: true } : undefined);\r\n } catch (error) {\r\n // Silenciar errores para evitar bloquear el navegador\r\n console.error(\"[navigation] Error in click handler:\", error);\r\n }\r\n };\r\n}\r\n\r\nexport function createPopStateHandler(\r\n navigate: (url: string, options?: NavigateOptions) => void\r\n): () => void {\r\n return function handlePopState() {\r\n const nextUrl = window.location.pathname + window.location.search;\r\n navigate(nextUrl);\r\n };\r\n}\r\n\r\n","import { createContext, useContext } from \"react\";\r\n\r\nexport type NavigateFunction = (\r\n url: string,\r\n options?: { revalidate?: boolean; replace?: boolean }\r\n) => Promise<void>;\r\n\r\nexport interface RouterContextValue {\r\n navigate: NavigateFunction;\r\n}\r\n\r\nexport const RouterContext = createContext<RouterContextValue | null>(null);\r\n\r\nexport function useRouterContext(): RouterContextValue {\r\n const context = useContext(RouterContext);\r\n if (!context) {\r\n throw new Error(\r\n \"useRouter must be used within a RouterProvider. Make sure you're using it inside a Loly app.\"\r\n );\r\n }\r\n return context;\r\n}\r\n","/**\r\n * Sets up hot reload via Server-Sent Events (SSE) in development mode.\r\n * Listens for file changes and reloads the page when needed.\r\n * \r\n * This module is separate from bootstrap to keep concerns separated\r\n * and make the code more maintainable.\r\n */\r\nexport function setupHotReload(): void {\r\n // process.env.NODE_ENV is replaced by DefinePlugin at build time\r\n // DefinePlugin replaces this with a string literal: \"development\" or \"production\"\r\n // @ts-expect-error - process.env.NODE_ENV is replaced at build time by DefinePlugin\r\n const nodeEnv: string = process.env.NODE_ENV || \"production\";\r\n const isDev = nodeEnv === \"development\";\r\n \r\n console.log(`[hot-reload] NODE_ENV: ${nodeEnv}, isDev: ${isDev}`);\r\n \r\n if (!isDev) {\r\n console.log(\"[hot-reload] Skipping hot reload setup (not in development mode)\");\r\n return;\r\n }\r\n \r\n console.log(\"[hot-reload] Setting up hot reload client...\");\r\n\r\n let eventSource: EventSource | null = null;\r\n let reloadTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let reconnectAttempts = 0;\r\n const MAX_RECONNECT_ATTEMPTS = 10;\r\n const RECONNECT_DELAY = 1000; // 1 second\r\n const RELOAD_DELAY = 100; // Reduced from 500ms to 100ms for faster reload\r\n\r\n function connect(): void {\r\n try {\r\n if (eventSource) {\r\n console.log(\"[hot-reload] Closing existing EventSource connection\");\r\n eventSource.close();\r\n }\r\n\r\n const endpoint = \"/__fw/hot\";\r\n eventSource = new EventSource(endpoint);\r\n \r\n // Register ping listener FIRST (before message) to catch initial ping\r\n eventSource.addEventListener(\"ping\", (event: Event) => {\r\n if ('data' in event) {\r\n console.log(\"[hot-reload] ✅ Connected to hot reload server\");\r\n }\r\n reconnectAttempts = 0;\r\n });\r\n\r\n // Register message listener for reload events\r\n eventSource.addEventListener(\"message\", (event: MessageEvent) => {\r\n const data = event.data;\r\n if (data && typeof data === \"string\" && data.startsWith(\"reload:\")) {\r\n const filePath = data.slice(7);\r\n console.log(`[hot-reload] 📝 File changed: ${filePath}, reloading...`);\r\n\r\n // Clear existing timeout to debounce rapid events\r\n if (reloadTimeout) {\r\n clearTimeout(reloadTimeout);\r\n }\r\n\r\n // Debounce reload - wait a bit in case multiple files change at once\r\n reloadTimeout = setTimeout(() => {\r\n try {\r\n window.location.reload();\r\n } catch (error) {\r\n console.error(\"[hot-reload] ❌ Error reloading page:\", error);\r\n // Fallback: try to reload after a short delay\r\n setTimeout(() => window.location.reload(), 100);\r\n }\r\n }, RELOAD_DELAY);\r\n }\r\n });\r\n\r\n eventSource.onopen = () => {\r\n reconnectAttempts = 0; // Reset on successful connection\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n const states = [\"CONNECTING\", \"OPEN\", \"CLOSED\"];\r\n const state = states[eventSource?.readyState ?? 0] || \"UNKNOWN\";\r\n \r\n if (eventSource?.readyState === EventSource.CONNECTING) {\r\n // Still connecting, this is normal\r\n console.log(\"[hot-reload] ⏳ Still connecting...\");\r\n return;\r\n } else if (eventSource?.readyState === EventSource.OPEN) {\r\n // Connection is open but error occurred (might be temporary)\r\n console.warn(\"[hot-reload] ⚠️ Connection error (but connection is open):\", error);\r\n } else {\r\n // Connection closed, try to reconnect\r\n console.warn(`[hot-reload] ❌ Connection closed (readyState: ${state})`);\r\n \r\n if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {\r\n reconnectAttempts++;\r\n const delay = RECONNECT_DELAY * reconnectAttempts; // Exponential backoff\r\n \r\n if (reconnectTimeout) {\r\n clearTimeout(reconnectTimeout);\r\n }\r\n \r\n reconnectTimeout = setTimeout(() => {\r\n console.log(`[hot-reload] 🔄 Reconnecting... (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);\r\n connect();\r\n }, delay);\r\n } else {\r\n console.error(\"[hot-reload] ❌ Max reconnect attempts reached. Please refresh the page manually.\");\r\n }\r\n }\r\n };\r\n } catch (error) {\r\n console.error(\"[hot-reload] ❌ Failed to create EventSource:\", error);\r\n console.error(\"[hot-reload] EventSource may not be supported in this browser.\");\r\n }\r\n }\r\n\r\n // Initial connection\r\n connect();\r\n}\r\n\r\n"],"mappings":"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","names":["import_react","existing","navigate","tagName","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../modules/runtime/client/index.tsx","../modules/runtime/client/bootstrap.tsx","../modules/runtime/client/constants.ts","../modules/runtime/client/window-data.ts","../modules/runtime/client/route-matcher.ts","../modules/runtime/client/metadata.ts","../modules/runtime/client/AppShell.tsx","../modules/runtime/client/RouterView.tsx","../modules/react/cache/client-data-cache/index.ts","../modules/runtime/client/navigation.ts","../modules/runtime/client/RouterContext.tsx","../modules/runtime/client/hot-reload.ts"],"sourcesContent":["// Re-export all public types and functions\r\nexport type {\r\n ClientLoadedComponents,\r\n ClientRouteLoaded,\r\n ClientRouteMatch,\r\n RouteViewState,\r\n InitialData,\r\n} from \"./types\";\r\n\r\nexport { bootstrapClient } from \"./bootstrap\";\r\nexport type { AppShellProps } from \"./AppShell\";\r\n","import { hydrateRoot } from \"react-dom/client\";\r\nimport { APP_CONTAINER_ID } from \"./constants\";\r\nimport { getWindowData, getRouterData, setRouterData, setPreservedLayoutProps } from \"./window-data\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { AppShell } from \"./AppShell\";\r\nimport { setupHotReload } from \"./hot-reload\";\r\nimport type {\r\n InitialData,\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n} from \"./types\";\r\n\r\nexport async function loadInitialRoute(\r\n initialUrl: string,\r\n initialData: InitialData | null,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null\r\n): Promise<RouteViewState> {\r\n const isInitialNotFound = initialData?.notFound === true;\r\n const isInitialError = initialData?.error === true;\r\n\r\n let initialRoute: ClientRouteLoaded | null = null;\r\n let initialParams: Record<string, string> = {};\r\n let initialComponents = null;\r\n\r\n if (isInitialError && errorRoute) {\r\n initialRoute = errorRoute;\r\n initialParams = initialData?.params ?? {};\r\n initialComponents = await errorRoute.load();\r\n } else if (isInitialNotFound && notFoundRoute) {\r\n initialRoute = notFoundRoute;\r\n initialParams = {};\r\n initialComponents = await notFoundRoute.load();\r\n } else {\r\n const match = matchRouteClient(initialUrl, routes);\r\n if (match) {\r\n initialRoute = match.route;\r\n initialParams = match.params;\r\n initialComponents = await match.route.load();\r\n } else if (notFoundRoute) {\r\n initialRoute = notFoundRoute;\r\n initialParams = {};\r\n initialComponents = await notFoundRoute.load();\r\n } else {\r\n console.warn(\r\n `[client] No route match found for ${initialUrl}. Available routes:`,\r\n routes.map((r) => r.pattern)\r\n );\r\n }\r\n }\r\n\r\n return {\r\n url: initialUrl,\r\n route: initialRoute,\r\n params: initialParams,\r\n components: initialComponents,\r\n props: initialData?.props ?? {},\r\n };\r\n}\r\n\r\n/**\r\n * Initializes router data from server or builds it from the current URL.\r\n */\r\nfunction initializeRouterData(\r\n initialUrl: string,\r\n initialData: InitialData | null\r\n): void {\r\n let routerData = getRouterData();\r\n if (!routerData) {\r\n const url = new URL(initialUrl, window.location.origin);\r\n routerData = {\r\n pathname: url.pathname,\r\n params: initialData?.params || {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n }\r\n}\r\n\r\n/**\r\n * Loads and hydrates the initial route.\r\n */\r\nasync function hydrateInitialRoute(\r\n container: HTMLElement,\r\n initialUrl: string,\r\n initialData: InitialData | null,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null\r\n): Promise<void> {\r\n try {\r\n // Load initial route\r\n const initialState = await loadInitialRoute(\r\n initialUrl,\r\n initialData,\r\n routes,\r\n notFoundRoute,\r\n errorRoute\r\n );\r\n\r\n // Apply metadata if available\r\n if (initialData?.metadata) {\r\n try {\r\n applyMetadata(initialData.metadata);\r\n } catch (metadataError) {\r\n console.warn(\"[client] Error applying metadata:\", metadataError);\r\n // Continue even if metadata fails\r\n }\r\n }\r\n\r\n // Hydrate React root\r\n hydrateRoot(\r\n container,\r\n <AppShell\r\n initialState={initialState}\r\n routes={routes}\r\n notFoundRoute={notFoundRoute}\r\n errorRoute={errorRoute}\r\n />\r\n );\r\n } catch (error) {\r\n console.error(\r\n \"[client] Error loading initial route components for\",\r\n initialUrl,\r\n error\r\n );\r\n throw error; // Re-throw to handle in bootstrapClient\r\n }\r\n}\r\n\r\n/**\r\n * Bootstraps the client-side application.\r\n * \r\n * Simplified flow:\r\n * 1. Setup hot reload (development only)\r\n * 2. Get container and initial data\r\n * 3. Initialize router data\r\n * 4. Load and hydrate initial route\r\n *\r\n * @param routes - Array of client routes\r\n * @param notFoundRoute - Not-found route definition\r\n * @param errorRoute - Error route definition\r\n */\r\nexport function bootstrapClient(\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null,\r\n errorRoute: ClientRouteLoaded | null = null\r\n): void {\r\n // 1. Setup hot reload (development only)\r\n setupHotReload();\r\n\r\n // Start bootstrap process\r\n (async () => {\r\n try {\r\n // 2. Get container and initial data\r\n const container = document.getElementById(APP_CONTAINER_ID);\r\n if (!container) {\r\n console.error(`\\n❌ [client] Hydration failed: Container #${APP_CONTAINER_ID} not found`);\r\n console.error(\"💡 This usually means:\");\r\n console.error(\" • The HTML structure doesn't match what React expects\");\r\n console.error(\" • The container was removed before hydration\");\r\n console.error(\" • There's a mismatch between SSR and client HTML\\n\");\r\n return;\r\n }\r\n\r\n const initialData = getWindowData();\r\n const initialUrl = window.location.pathname + window.location.search;\r\n\r\n // Preserve layout props from initial load (they come combined in initialData.props)\r\n // In SSR, layout hooks are always executed, so we need to extract layout props\r\n // For now, we'll preserve all props as layout props since they're combined\r\n // This ensures navigation items are available even in SPA navigation\r\n if (initialData?.props) {\r\n // In SSR, props are combined (layout + page), so we preserve them all as layout props\r\n // This is not perfect but ensures layout props are available in SPA navigation\r\n setPreservedLayoutProps(initialData.props);\r\n }\r\n\r\n // 3. Initialize router data\r\n initializeRouterData(initialUrl, initialData);\r\n\r\n // 4. Load and hydrate initial route\r\n await hydrateInitialRoute(\r\n container,\r\n initialUrl,\r\n initialData,\r\n routes,\r\n notFoundRoute,\r\n errorRoute\r\n );\r\n } catch (error) {\r\n // Fatal error during bootstrap - reload the page\r\n console.error(\"\\n❌ [client] Fatal error during bootstrap:\");\r\n console.error(error);\r\n if (error instanceof Error) {\r\n console.error(\"\\nError details:\");\r\n console.error(` Message: ${error.message}`);\r\n if (error.stack) {\r\n console.error(` Stack: ${error.stack}`);\r\n }\r\n }\r\n console.error(\"\\n💡 Attempting page reload to recover...\\n\");\r\n window.location.reload();\r\n }\r\n })();\r\n}\r\n\r\n","// Client-side constants (hardcoded to avoid alias resolution issues in Rspack)\r\nexport const WINDOW_DATA_KEY = \"__FW_DATA__\";\r\nexport const ROUTER_DATA_KEY = \"__LOLY_ROUTER_DATA__\";\r\nexport const APP_CONTAINER_ID = \"__app\";\r\n// Global key for navigate function fallback (exposed by AppShell for hydration timing issues)\r\nexport const ROUTER_NAVIGATE_KEY = \"__LOLY_ROUTER_NAVIGATE__\";\r\n\r\n","import { WINDOW_DATA_KEY, ROUTER_DATA_KEY } from \"./constants\";\r\nimport type { InitialData, RouterData } from \"./types\";\r\n\r\nconst LAYOUT_PROPS_KEY = \"__FW_LAYOUT_PROPS__\";\r\n\r\nexport function getWindowData(): InitialData | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return (window[WINDOW_DATA_KEY] as InitialData | undefined) ?? null;\r\n}\r\n\r\n/**\r\n * Gets preserved layout props from window storage.\r\n * Layout props are preserved across SPA navigations when layout hooks are skipped.\r\n */\r\nexport function getPreservedLayoutProps(): Record<string, any> | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return ((window as any)[LAYOUT_PROPS_KEY] as Record<string, any> | undefined) ?? null;\r\n}\r\n\r\n/**\r\n * Sets preserved layout props in window storage.\r\n * These props are used when layout hooks are skipped in SPA navigation.\r\n */\r\nexport function setPreservedLayoutProps(props: Record<string, any> | null): void {\r\n if (typeof window === \"undefined\") {\r\n return;\r\n }\r\n if (props === null) {\r\n delete (window as any)[LAYOUT_PROPS_KEY];\r\n } else {\r\n (window as any)[LAYOUT_PROPS_KEY] = props;\r\n }\r\n}\r\n\r\nexport function getRouterData(): RouterData | null {\r\n if (typeof window === \"undefined\") {\r\n return null;\r\n }\r\n return (window[ROUTER_DATA_KEY] as RouterData | undefined) ?? null;\r\n}\r\n\r\nexport function setWindowData(data: InitialData): void {\r\n window[WINDOW_DATA_KEY] = data;\r\n \r\n // Dispatch event for components to listen to (e.g. ThemeProvider)\r\n // This ensures components update when navigating in SPA mode\r\n if (typeof window !== \"undefined\") {\r\n window.dispatchEvent(\r\n new CustomEvent(\"fw-data-refresh\", {\r\n detail: { data },\r\n })\r\n );\r\n }\r\n}\r\n\r\nexport function setRouterData(data: RouterData): void {\r\n window[ROUTER_DATA_KEY] = data;\r\n \r\n // Dispatch event for router data updates\r\n if (typeof window !== \"undefined\") {\r\n window.dispatchEvent(\r\n new CustomEvent(\"fw-router-data-refresh\", {\r\n detail: { data },\r\n })\r\n );\r\n }\r\n}\r\n\r\nexport function getCurrentTheme(): string | null {\r\n return getWindowData()?.theme ?? null;\r\n}\r\n\r\n","import type { ClientRouteLoaded, ClientRouteMatch } from \"./types\";\r\n\r\nexport function buildClientRegexFromPattern(pattern: string): RegExp {\r\n const segments = pattern.split(\"/\").filter(Boolean);\r\n const regexParts: string[] = [];\r\n\r\n for (let i = 0; i < segments.length; i++) {\r\n const seg = segments[i];\r\n\r\n // catch-all [...slug]\r\n if (seg.startsWith(\"[...\") && seg.endsWith(\"]\")) {\r\n if (i !== segments.length - 1) {\r\n throw new Error(\r\n `Catch-all segment \"${seg}\" in \"${pattern}\" must be the last segment.`\r\n );\r\n }\r\n regexParts.push(\"(.+)\");\r\n continue;\r\n }\r\n\r\n // dynamic [id]\r\n if (seg.startsWith(\"[\") && seg.endsWith(\"]\")) {\r\n regexParts.push(\"([^/]+)\");\r\n continue;\r\n }\r\n\r\n // static segment\r\n const escaped = seg.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n regexParts.push(escaped);\r\n }\r\n\r\n const regexSource = \"^/\" + regexParts.join(\"/\") + \"/?$\";\r\n return new RegExp(regexSource);\r\n}\r\n\r\nexport function matchRouteClient(\r\n pathWithSearch: string,\r\n routes: ClientRouteLoaded[]\r\n): ClientRouteMatch | null {\r\n const [pathname] = pathWithSearch.split(\"?\");\r\n for (const r of routes) {\r\n const regex = buildClientRegexFromPattern(r.pattern);\r\n const match = regex.exec(pathname);\r\n if (!match) continue;\r\n\r\n const params: Record<string, string> = {};\r\n r.paramNames.forEach((name, idx) => {\r\n params[name] = decodeURIComponent(match[idx + 1] || \"\");\r\n });\r\n\r\n return { route: r, params };\r\n }\r\n return null;\r\n}\r\n\r\n","import type { PageMetadata } from \"@router/index\";\r\n\r\n/**\r\n * Helper to get or create a meta tag element\r\n */\r\nfunction getOrCreateMeta(\r\n selector: string,\r\n attributes: { name?: string; property?: string; httpEquiv?: string }\r\n): HTMLMetaElement {\r\n let meta = document.querySelector(selector) as HTMLMetaElement | null;\r\n if (!meta) {\r\n meta = document.createElement(\"meta\");\r\n if (attributes.name) meta.name = attributes.name;\r\n if (attributes.property) meta.setAttribute(\"property\", attributes.property);\r\n if (attributes.httpEquiv) meta.httpEquiv = attributes.httpEquiv;\r\n document.head.appendChild(meta);\r\n }\r\n return meta;\r\n}\r\n\r\n/**\r\n * Helper to get or create a link tag element\r\n */\r\nfunction getOrCreateLink(rel: string, href: string): HTMLLinkElement {\r\n const selector = `link[rel=\"${rel}\"]`;\r\n let link = document.querySelector(selector) as HTMLLinkElement | null;\r\n if (!link) {\r\n link = document.createElement(\"link\");\r\n link.rel = rel;\r\n link.href = href;\r\n document.head.appendChild(link);\r\n } else {\r\n link.href = href;\r\n }\r\n return link;\r\n}\r\n\r\n/**\r\n * Updates page metadata in the document head.\r\n * Supports all metadata fields including Open Graph, Twitter Cards, canonical URLs, etc.\r\n * \r\n * @param md - Page metadata object\r\n */\r\nexport function applyMetadata(md?: PageMetadata | null): void {\r\n if (!md) return;\r\n\r\n // Title\r\n if (md.title) {\r\n document.title = md.title;\r\n }\r\n\r\n // Description\r\n if (md.description) {\r\n const meta = getOrCreateMeta('meta[name=\"description\"]', { name: \"description\" });\r\n meta.content = md.description;\r\n }\r\n\r\n // Robots\r\n if (md.robots) {\r\n const meta = getOrCreateMeta('meta[name=\"robots\"]', { name: \"robots\" });\r\n meta.content = md.robots;\r\n }\r\n\r\n // Theme color\r\n if (md.themeColor) {\r\n const meta = getOrCreateMeta('meta[name=\"theme-color\"]', { name: \"theme-color\" });\r\n meta.content = md.themeColor;\r\n }\r\n\r\n // Viewport\r\n if (md.viewport) {\r\n const meta = getOrCreateMeta('meta[name=\"viewport\"]', { name: \"viewport\" });\r\n meta.content = md.viewport;\r\n }\r\n\r\n // Canonical URL\r\n if (md.canonical) {\r\n getOrCreateLink(\"canonical\", md.canonical);\r\n }\r\n\r\n // Open Graph tags\r\n if (md.openGraph) {\r\n const og = md.openGraph;\r\n\r\n if (og.title) {\r\n const meta = getOrCreateMeta('meta[property=\"og:title\"]', { property: \"og:title\" });\r\n meta.content = og.title;\r\n }\r\n\r\n if (og.description) {\r\n const meta = getOrCreateMeta('meta[property=\"og:description\"]', { property: \"og:description\" });\r\n meta.content = og.description;\r\n }\r\n\r\n if (og.type) {\r\n const meta = getOrCreateMeta('meta[property=\"og:type\"]', { property: \"og:type\" });\r\n meta.content = og.type;\r\n }\r\n\r\n if (og.url) {\r\n const meta = getOrCreateMeta('meta[property=\"og:url\"]', { property: \"og:url\" });\r\n meta.content = og.url;\r\n }\r\n\r\n if (og.image) {\r\n if (typeof og.image === \"string\") {\r\n const meta = getOrCreateMeta('meta[property=\"og:image\"]', { property: \"og:image\" });\r\n meta.content = og.image;\r\n } else {\r\n const meta = getOrCreateMeta('meta[property=\"og:image\"]', { property: \"og:image\" });\r\n meta.content = og.image.url;\r\n\r\n if (og.image.width) {\r\n const metaWidth = getOrCreateMeta('meta[property=\"og:image:width\"]', { property: \"og:image:width\" });\r\n metaWidth.content = String(og.image.width);\r\n }\r\n\r\n if (og.image.height) {\r\n const metaHeight = getOrCreateMeta('meta[property=\"og:image:height\"]', { property: \"og:image:height\" });\r\n metaHeight.content = String(og.image.height);\r\n }\r\n\r\n if (og.image.alt) {\r\n const metaAlt = getOrCreateMeta('meta[property=\"og:image:alt\"]', { property: \"og:image:alt\" });\r\n metaAlt.content = og.image.alt;\r\n }\r\n }\r\n }\r\n\r\n if (og.siteName) {\r\n const meta = getOrCreateMeta('meta[property=\"og:site_name\"]', { property: \"og:site_name\" });\r\n meta.content = og.siteName;\r\n }\r\n\r\n if (og.locale) {\r\n const meta = getOrCreateMeta('meta[property=\"og:locale\"]', { property: \"og:locale\" });\r\n meta.content = og.locale;\r\n }\r\n }\r\n\r\n // Twitter Card tags\r\n if (md.twitter) {\r\n const twitter = md.twitter;\r\n\r\n if (twitter.card) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:card\"]', { name: \"twitter:card\" });\r\n meta.content = twitter.card;\r\n }\r\n\r\n if (twitter.title) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:title\"]', { name: \"twitter:title\" });\r\n meta.content = twitter.title;\r\n }\r\n\r\n if (twitter.description) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:description\"]', { name: \"twitter:description\" });\r\n meta.content = twitter.description;\r\n }\r\n\r\n if (twitter.image) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:image\"]', { name: \"twitter:image\" });\r\n meta.content = twitter.image;\r\n }\r\n\r\n if (twitter.imageAlt) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:image:alt\"]', { name: \"twitter:image:alt\" });\r\n meta.content = twitter.imageAlt;\r\n }\r\n\r\n if (twitter.site) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:site\"]', { name: \"twitter:site\" });\r\n meta.content = twitter.site;\r\n }\r\n\r\n if (twitter.creator) {\r\n const meta = getOrCreateMeta('meta[name=\"twitter:creator\"]', { name: \"twitter:creator\" });\r\n meta.content = twitter.creator;\r\n }\r\n }\r\n\r\n // Custom meta tags\r\n if (md.metaTags && Array.isArray(md.metaTags)) {\r\n md.metaTags.forEach((tag) => {\r\n let selector = \"\";\r\n if (tag.name) {\r\n selector = `meta[name=\"${tag.name}\"]`;\r\n } else if (tag.property) {\r\n selector = `meta[property=\"${tag.property}\"]`;\r\n } else if (tag.httpEquiv) {\r\n selector = `meta[http-equiv=\"${tag.httpEquiv}\"]`;\r\n }\r\n\r\n if (selector) {\r\n const meta = getOrCreateMeta(selector, {\r\n name: tag.name,\r\n property: tag.property,\r\n httpEquiv: tag.httpEquiv,\r\n });\r\n meta.content = tag.content;\r\n }\r\n });\r\n }\r\n\r\n // Custom link tags\r\n if (md.links && Array.isArray(md.links)) {\r\n md.links.forEach((link) => {\r\n getOrCreateLink(link.rel, link.href);\r\n // Note: Additional attributes like 'as', 'crossorigin', 'type' would need\r\n // more complex logic to update existing links. For now, we just ensure\r\n // the link exists with the correct href.\r\n });\r\n }\r\n}\r\n\r\n","import { useEffect, useState, useRef, useCallback } from \"react\";\r\nimport { RouterView } from \"./RouterView\";\r\nimport {\r\n navigate,\r\n createClickHandler,\r\n createPopStateHandler,\r\n createHoverHandler,\r\n type NavigationHandlers,\r\n} from \"./navigation\";\r\nimport { RouterContext } from \"./RouterContext\";\r\nimport { ROUTER_NAVIGATE_KEY, WINDOW_DATA_KEY } from \"./constants\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport type {\r\n RouteViewState,\r\n ClientRouteLoaded,\r\n} from \"./types\";\r\n\r\nexport interface AppShellProps {\r\n initialState: RouteViewState;\r\n routes: ClientRouteLoaded[];\r\n notFoundRoute: ClientRouteLoaded | null;\r\n errorRoute: ClientRouteLoaded | null;\r\n}\r\n\r\nexport function AppShell({\r\n initialState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n}: AppShellProps) {\r\n const [state, setState] = useState<RouteViewState>(initialState);\r\n const handlersRef = useRef<NavigationHandlers>({\r\n setState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n });\r\n\r\n useEffect(() => {\r\n handlersRef.current = {\r\n setState,\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n };\r\n }, [routes, notFoundRoute, errorRoute]);\r\n\r\n // Create navigate function for router context\r\n const handleNavigate = useCallback(\r\n async (\r\n nextUrl: string,\r\n options?: { revalidate?: boolean; replace?: boolean }\r\n ) => {\r\n await navigate(nextUrl, handlersRef.current, {\r\n revalidate: options?.revalidate,\r\n });\r\n },\r\n []\r\n );\r\n\r\n /**\r\n * SOLUTION: Expose navigate function globally as fallback\r\n * \r\n * During React hydration, components rendered in layouts may execute before\r\n * RouterContext is fully available. By exposing navigate globally, useRouter\r\n * can access it even when the context isn't ready yet, ensuring SPA navigation\r\n * works correctly from the first render.\r\n * \r\n * This is similar to how window.__FW_DATA__ is used for initial data.\r\n */\r\n useEffect(() => {\r\n if (typeof window !== \"undefined\") {\r\n window[ROUTER_NAVIGATE_KEY] = handleNavigate;\r\n return () => {\r\n delete window[ROUTER_NAVIGATE_KEY];\r\n };\r\n }\r\n }, [handleNavigate]);\r\n\r\n useEffect(() => {\r\n let isMounted = true;\r\n\r\n async function handleNavigateInternal(\r\n nextUrl: string,\r\n options?: { revalidate?: boolean }\r\n ) {\r\n if (!isMounted) return;\r\n await navigate(nextUrl, handlersRef.current, options);\r\n }\r\n\r\n const handleClick = createClickHandler(handleNavigateInternal);\r\n const handlePopState = createPopStateHandler(handleNavigateInternal);\r\n const handleHover = createHoverHandler(routes, notFoundRoute);\r\n\r\n window.addEventListener(\"click\", handleClick, false);\r\n window.addEventListener(\"popstate\", handlePopState, false);\r\n window.addEventListener(\"mouseover\", handleHover, false);\r\n\r\n return () => {\r\n isMounted = false;\r\n window.removeEventListener(\"click\", handleClick, false);\r\n window.removeEventListener(\"popstate\", handlePopState, false);\r\n window.removeEventListener(\"mouseover\", handleHover, false);\r\n };\r\n }, [routes, notFoundRoute]);\r\n\r\n // Listen for data refresh events and update state when current route is revalidated\r\n useEffect(() => {\r\n const handleDataRefresh = () => {\r\n const freshData = window[WINDOW_DATA_KEY];\r\n \r\n if (!freshData) return;\r\n \r\n const currentPathname = window.location.pathname;\r\n const freshPathname = freshData.pathname;\r\n \r\n if (freshPathname === currentPathname) {\r\n if (freshData.metadata !== undefined) {\r\n applyMetadata(freshData.metadata);\r\n }\r\n \r\n setState((prevState) => ({\r\n ...prevState,\r\n props: freshData.props ?? prevState.props,\r\n params: freshData.params ?? prevState.params,\r\n }));\r\n }\r\n };\r\n\r\n window.addEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n\r\n return () => {\r\n window.removeEventListener(\"fw-data-refresh\", handleDataRefresh);\r\n };\r\n }, []); // Empty deps - only register once, not when state.url changes\r\n\r\n const isError = state.route === errorRoute;\r\n const isNotFound = state.route === notFoundRoute;\r\n const routeType = isError ? \"error\" : isNotFound ? \"notfound\" : \"normal\";\r\n const routeKey = `${state.url}:${routeType}`;\r\n\r\n return (\r\n <RouterContext.Provider value={{ navigate: handleNavigate }}>\r\n <RouterView key={routeKey} state={state} />\r\n </RouterContext.Provider>\r\n );\r\n}\r\n\r\n","import type { RouteViewState } from \"./types\";\r\n\r\nexport function RouterView({ state }: { state: RouteViewState }) {\r\n if (!state.route) {\r\n // Don't show 404 if we're waiting for components to load\r\n if (state.components === null) {\r\n return null;\r\n }\r\n return <h1>404 - Route not found</h1>;\r\n }\r\n\r\n if (!state.components) {\r\n return null;\r\n }\r\n\r\n const { Page, layouts } = state.components;\r\n const { params, props } = state;\r\n\r\n let element = <Page params={params} {...props} />;\r\n\r\n const layoutChain = layouts.slice().reverse();\r\n for (const Layout of layoutChain) {\r\n element = (\r\n <Layout params={params} {...props}>\r\n {element}\r\n </Layout>\r\n );\r\n }\r\n\r\n return element;\r\n}\r\n\r\n","import type { PageMetadata } from \"@router/index\";\n\n/**\n * Response data structure from server for route data requests\n */\nexport type RouteDataResponse = {\n /** Combined props (layout + page) - kept for backward compatibility */\n props?: Record<string, unknown>;\n /** Layout props (from layout.server.hook.ts) - only present when layout hooks were executed */\n layoutProps?: Record<string, unknown>;\n /** Page props (from page.server.hook.ts) - always present in data requests */\n pageProps?: Record<string, unknown>;\n metadata?: PageMetadata | null;\n theme?: string;\n redirect?: { destination: string; permanent?: boolean };\n notFound?: boolean;\n error?: boolean;\n message?: string;\n params?: Record<string, string>;\n};\n\ntype RouteData = {\n ok: boolean;\n status: number;\n json: RouteDataResponse;\n};\n\ntype CacheEntry =\n | { status: \"pending\"; promise: Promise<RouteData> }\n | { status: \"fulfilled\"; value: RouteData }\n | { status: \"rejected\"; error: any };\n\n// Use window to guarantee a single shared cache instance\n// across all bundles/modules\nconst CACHE_KEY = \"__FW_DATA_CACHE__\";\n\n// Maximum number of entries in the cache (LRU)\nconst MAX_CACHE_SIZE = 100;\n\ntype CacheStore = {\n data: Map<string, CacheEntry>;\n index: Map<string, Set<string>>; // pathBase -> Set of keys\n lru: string[]; // Ordered list: most recent at end, oldest at start\n};\n\nfunction getCacheStore(): CacheStore {\n if (typeof window !== \"undefined\") {\n if (!(window as any)[CACHE_KEY]) {\n (window as any)[CACHE_KEY] = {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n }\n return (window as any)[CACHE_KEY];\n }\n // Fallback for SSR (though this shouldn't be used on the client)\n return {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n}\n\nconst cacheStore = getCacheStore();\nconst dataCache = cacheStore.data;\nconst pathIndex = cacheStore.index;\nconst lru = cacheStore.lru;\n\n// Helper functions for cache management\n\n/**\n * Extract base path from a cache key (removes query params)\n */\nfunction extractPathBase(key: string): string {\n return key.split(\"?\")[0];\n}\n\n/**\n * Add key to path index\n */\nfunction addToIndex(key: string): void {\n const pathBase = extractPathBase(key);\n if (!pathIndex.has(pathBase)) {\n pathIndex.set(pathBase, new Set());\n }\n pathIndex.get(pathBase)!.add(key);\n}\n\n/**\n * Remove key from path index\n */\nfunction removeFromIndex(key: string): void {\n const pathBase = extractPathBase(key);\n const keys = pathIndex.get(pathBase);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n pathIndex.delete(pathBase);\n }\n }\n}\n\n/**\n * Update LRU order - move key to end (most recent)\n */\nfunction updateLRU(key: string): void {\n const index = lru.indexOf(key);\n if (index !== -1) {\n lru.splice(index, 1);\n }\n lru.push(key);\n}\n\n/**\n * Remove oldest entries if cache exceeds MAX_CACHE_SIZE\n */\nfunction evictOldest(): void {\n while (lru.length >= MAX_CACHE_SIZE && lru.length > 0) {\n const oldestKey = lru.shift()!;\n dataCache.delete(oldestKey);\n removeFromIndex(oldestKey);\n }\n}\n\n/**\n * Set cache entry and maintain indexes\n */\nfunction setCacheEntry(key: string, entry: CacheEntry): void {\n const existingEntry = dataCache.get(key);\n const wasFulfilled = existingEntry?.status === \"fulfilled\";\n \n dataCache.set(key, entry);\n \n // Only track fulfilled entries in LRU and index (not pending/rejected)\n if (entry.status === \"fulfilled\") {\n // Add to index if it wasn't already fulfilled (new entry or transition from pending/rejected)\n if (!wasFulfilled) {\n addToIndex(key);\n }\n updateLRU(key);\n evictOldest();\n } else if (wasFulfilled) {\n // If entry was fulfilled and now isn't (transitioning to pending/rejected), remove from index\n removeFromIndex(key);\n }\n}\n\n/**\n * Delete cache entry and clean up indexes\n */\nfunction deleteCacheEntry(key: string): void {\n if (dataCache.has(key)) {\n dataCache.delete(key);\n removeFromIndex(key);\n const lruIndex = lru.indexOf(key);\n if (lruIndex !== -1) {\n lru.splice(lruIndex, 1);\n }\n }\n}\n\nfunction buildDataUrl(url: string): string {\n return url + (url.includes(\"?\") ? \"&\" : \"?\") + \"__fw_data=1\";\n}\n\nasync function fetchRouteDataOnce(\n url: string,\n skipLayoutHooks: boolean = true\n): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const headers: Record<string, string> = {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n };\n\n // Send header to skip layout hooks execution in SPA navigation\n // Only skip if skipLayoutHooks is true (normal SPA navigation)\n // If false (revalidate), don't send header to force execution of all hooks\n if (skipLayoutHooks) {\n headers[\"x-skip-layout-hooks\"] = \"true\";\n }\n\n const res = await fetch(dataUrl, { headers });\n\n let json: any = {};\n\n try {\n const text = await res.text();\n if (text) {\n json = JSON.parse(text);\n }\n } catch (parseError) {\n console.error(\n \"[client][cache] Failed to parse response as JSON:\",\n parseError\n );\n }\n\n const result: RouteData = {\n ok: res.ok,\n status: res.status,\n json,\n };\n\n return result;\n}\n\n/**\n * Revalidates route data by removing it from the cache.\n * The next time you navigate to this route, fresh data will be fetched from the server.\n * This is a client-side function and does not require a server-side revalidation.\n *\n * @param path - The route path to revalidate (e.g., '/posts/1' or '/posts/1?page=2')\n * If query params are not included, revalidates all variants of that route.\n *\n * @example\n * ```ts\n * // After saving something to the DB, revalidate the route\n * await saveToDatabase(data);\n * revalidatePath('/posts');\n * \n * // Revalidate a specific route with query params\n * revalidatePath('/posts?page=2');\n * ```\n */\nexport function revalidatePath(path: string, skipAutoRevalidate: boolean = false): void {\n // Normalize the base path (without query params)\n const normalizedPath = path.split(\"?\")[0];\n const hasQueryParams = path.includes(\"?\");\n \n // Get all keys for this path base from index (O(1) lookup)\n const keysForPath = pathIndex.get(normalizedPath);\n \n if (!keysForPath || keysForPath.size === 0) {\n return; // No entries to revalidate\n }\n \n // If the path includes specific query params, extract them\n let specificQueryParams: string | undefined;\n if (hasQueryParams) {\n const queryPart = path.split(\"?\")[1];\n // Sort query params for consistent comparison\n specificQueryParams = queryPart\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n }\n \n // Iterate only over keys for this path (much smaller set)\n const keysToDelete: string[] = [];\n for (const key of keysForPath) {\n // If specific query params were specified, check if they match\n if (hasQueryParams && specificQueryParams) {\n const [, keyQuery = \"\"] = key.split(\"?\");\n const keyQueryParams = keyQuery\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (keyQueryParams === specificQueryParams) {\n keysToDelete.push(key);\n }\n } else {\n // If no specific query params, revalidate all variants\n keysToDelete.push(key);\n }\n }\n \n // Delete matching entries\n keysToDelete.forEach((key) => {\n deleteCacheEntry(key);\n });\n \n // If the revalidated path matches the current route, automatically refresh data\n // UNLESS skipAutoRevalidate is true (to prevent recursive calls from revalidate())\n if (!skipAutoRevalidate && typeof window !== \"undefined\") {\n const currentPathname = window.location.pathname;\n const currentSearch = window.location.search;\n const matchesCurrentPath = normalizedPath === currentPathname;\n \n if (matchesCurrentPath) {\n if (hasQueryParams && specificQueryParams) {\n const currentQueryParams = currentSearch\n .replace(\"?\", \"\")\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (currentQueryParams === specificQueryParams) {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n } else {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n }\n }\n}\n\n/**\n * Revalidates and refreshes the current page data.\n * Similar to Next.js's `router.refresh()`.\n * \n * This function:\n * 1. Removes the current route from cache\n * 2. Fetches fresh data from the server\n * 3. Updates window.__FW_DATA__ with the new data\n * 4. Dispatches a 'fw-data-refresh' event for components to listen to\n * \n * @returns Promise that resolves with the fresh route data\n * \n * @example\n * ```ts\n * // Refresh current page data after a mutation\n * await revalidate();\n * ```\n */\n// Flag to prevent recursive calls to revalidate()\nlet isRevalidating = false;\n\nexport async function revalidate(): Promise<RouteData> {\n if (typeof window === \"undefined\") {\n throw new Error(\"revalidate() can only be called on the client\");\n }\n\n // Prevent multiple simultaneous revalidations\n if (isRevalidating) {\n // Wait for the current revalidation to complete\n const key = buildDataUrl(window.location.pathname + window.location.search);\n const entry = dataCache.get(key);\n if (entry && entry.status === \"pending\") {\n return entry.promise;\n }\n // If no pending entry, something went wrong, allow the call\n }\n\n isRevalidating = true;\n try {\n const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n // Pass a flag to prevent revalidatePath from calling revalidate() again (recursive call)\n revalidatePath(pathname, true); // true = skip auto-revalidate\n \n // Fetch fresh data\n const freshData = await getRouteData(pathname, { revalidate: true });\n \n // Update window.__FW_DATA__ if it exists\n if ((window as any).__FW_DATA__ && freshData.ok && freshData.json) {\n const currentData = (window as any).__FW_DATA__;\n \n // Update preserved layout props if new ones were returned\n if (freshData.json.layoutProps !== undefined && freshData.json.layoutProps !== null) {\n (window as any).__FW_LAYOUT_PROPS__ = freshData.json.layoutProps;\n }\n \n // Combine layout props (new or preserved) + page props\n let combinedProps = currentData.props || {};\n if (freshData.json.layoutProps !== undefined && freshData.json.layoutProps !== null) {\n // Use new layout props\n combinedProps = {\n ...freshData.json.layoutProps,\n ...(freshData.json.pageProps ?? freshData.json.props ?? {}),\n };\n } else if (freshData.json.pageProps !== undefined) {\n // Use preserved layout props + new page props\n const preservedLayoutProps = (window as any).__FW_LAYOUT_PROPS__ || {};\n combinedProps = {\n ...preservedLayoutProps,\n ...freshData.json.pageProps,\n };\n } else if (freshData.json.props) {\n // Fallback to combined props\n combinedProps = freshData.json.props;\n }\n \n (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: combinedProps,\n metadata: freshData.json.metadata ?? currentData.metadata ?? null,\n notFound: freshData.json.notFound ?? false,\n error: freshData.json.error ?? false,\n };\n \n // Dispatch event for components to listen to\n window.dispatchEvent(new CustomEvent(\"fw-data-refresh\", {\n detail: { data: freshData },\n }));\n }\n \n return freshData;\n } finally {\n isRevalidating = false;\n }\n}\n\n/**\n * @deprecated Use `revalidatePath()` instead. This function is kept for backwards compatibility.\n */\nexport function revalidateRouteData(url: string): void {\n revalidatePath(url);\n}\n\nexport function prefetchRouteData(url: string): void {\n const key = buildDataUrl(url);\n\n const cached = dataCache.get(key);\n\n if (cached && cached.status !== \"rejected\") {\n // Update LRU if it exists and is fulfilled\n if (cached.status === \"fulfilled\") {\n updateLRU(key);\n }\n return;\n }\n\n // Prefetch uses skipLayoutHooks: true (normal navigation behavior)\n const promise = fetchRouteDataOnce(url, true)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error prefetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n}\n\nexport type GetRouteDataOptions = {\n /**\n * If true, forces revalidation of route data,\n * ignoring the cache and fetching fresh data from the server.\n * Similar to Next.js's `router.refresh()` behavior.\n */\n revalidate?: boolean;\n};\n\nexport async function getRouteData(\n url: string,\n options?: GetRouteDataOptions\n): Promise<RouteData> {\n const key = buildDataUrl(url);\n\n // If revalidation is requested, remove the entry from cache\n // This ensures we don't reuse pending or fulfilled entries\n if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry && !options?.revalidate) {\n // Only use cached entry if not revalidating\n if (entry.status === \"fulfilled\") {\n // Update LRU: mark as recently used\n updateLRU(key);\n return entry.value;\n }\n if (entry.status === \"pending\") {\n // Return existing pending promise to avoid duplicate requests\n return entry.promise;\n }\n }\n\n // No entry in cache (or revalidating), fetch it\n // skipLayoutHooks: true for normal SPA navigation, false when revalidating\n const skipLayoutHooks = !options?.revalidate;\n \n // Check again if an entry was added while we were processing (race condition)\n const currentEntry = dataCache.get(key);\n if (currentEntry && !options?.revalidate) {\n if (currentEntry.status === \"fulfilled\") {\n updateLRU(key);\n return currentEntry.value;\n }\n if (currentEntry.status === \"pending\") {\n return currentEntry.promise;\n }\n }\n \n // Create a new promise for this fetch\n const promise = fetchRouteDataOnce(url, skipLayoutHooks)\n .then((value) => {\n // Only set cache entry if this is still the current fetch for this key\n // This prevents race conditions where multiple revalidations happen simultaneously\n const entryAfterFetch = dataCache.get(key);\n if (!entryAfterFetch || entryAfterFetch.status === \"pending\") {\n setCacheEntry(key, { status: \"fulfilled\", value });\n }\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n const entryAfterFetch = dataCache.get(key);\n if (!entryAfterFetch || entryAfterFetch.status === \"pending\") {\n dataCache.set(key, { status: \"rejected\", error });\n }\n throw error;\n });\n\n // Set pending entry - if revalidating, we already deleted it, so this is safe\n dataCache.set(key, { status: \"pending\", promise });\n \n return promise;\n}\n","import { getRouteData } from \"../../react/cache/index\";\r\nimport type { RouteDataResponse } from \"../../react/cache/client-data-cache\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { setWindowData, getCurrentTheme, setRouterData, getPreservedLayoutProps, setPreservedLayoutProps } from \"./window-data\";\r\nimport type {\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n InitialData,\r\n RouterData,\r\n ClientLoadedComponents,\r\n} from \"./types\";\r\n\r\nexport type NavigationHandlers = {\r\n setState: (state: RouteViewState) => void;\r\n routes: ClientRouteLoaded[];\r\n notFoundRoute: ClientRouteLoaded | null;\r\n errorRoute: ClientRouteLoaded | null;\r\n};\r\n\r\nasync function handleErrorRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n errorRoute: ClientRouteLoaded,\r\n setState: (state: RouteViewState) => void\r\n): Promise<boolean> {\r\n try {\r\n const components = await errorRoute.load();\r\n \r\n // Get theme: prioritize cookie, then server, then window data, then default\r\n let theme: string = \"light\";\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) theme = currentTheme;\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Preserve layout props if not in response (SPA navigation)\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n const pageProps = json.pageProps ?? json.props ?? {\r\n error: json.message || \"An error occurred\",\r\n };\r\n\r\n const errorProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme,\r\n };\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: json.params || {},\r\n props: errorProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: false,\r\n error: true,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: json.params || {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n setState({\r\n url: nextUrl,\r\n route: errorRoute,\r\n params: json.params || {},\r\n components,\r\n props: errorProps,\r\n });\r\n return true;\r\n } catch (loadError) {\r\n console.error(\"\\n❌ [client] Error loading error route components:\");\r\n console.error(loadError);\r\n if (loadError instanceof Error) {\r\n console.error(` Message: ${loadError.message}`);\r\n if (loadError.stack) {\r\n console.error(` Stack: ${loadError.stack.split('\\n').slice(0, 3).join('\\n ')}`);\r\n }\r\n }\r\n console.error(\"💡 Falling back to full page reload\\n\");\r\n window.location.href = nextUrl;\r\n return false;\r\n }\r\n}\r\n\r\nasync function handleNotFoundRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n notFoundRoute: ClientRouteLoaded | null,\r\n setState: (state: RouteViewState) => void\r\n): Promise<void> {\r\n // Get theme: prioritize cookie, then server, then window data, then default\r\n let theme: string = \"light\";\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) theme = currentTheme;\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Preserve layout props if not in response (SPA navigation)\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n const pageProps = json.pageProps ?? json.props ?? {};\r\n\r\n const notFoundProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme,\r\n };\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: {},\r\n props: notFoundProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: true,\r\n error: false,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: {},\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n if (notFoundRoute) {\r\n const components = await notFoundRoute.load();\r\n setState({\r\n url: nextUrl,\r\n route: notFoundRoute,\r\n params: {},\r\n components,\r\n props: notFoundProps,\r\n });\r\n } else {\r\n setState({\r\n url: nextUrl,\r\n route: null,\r\n params: {},\r\n components: null,\r\n props: {},\r\n });\r\n }\r\n}\r\n\r\nasync function handleNormalRoute(\r\n nextUrl: string,\r\n json: RouteDataResponse,\r\n routes: ClientRouteLoaded[],\r\n setState: (state: RouteViewState) => void\r\n): Promise<boolean> {\r\n applyMetadata(json.metadata ?? null);\r\n \r\n // Get theme: prioritize cookie (source of truth), then server response, then window data, then default\r\n // Cookie is the source of truth because it persists across navigation\r\n let theme: string = \"light\"; // Default\r\n if (typeof document !== \"undefined\") {\r\n const cookieMatch = document.cookie.match(/theme=([^;]+)/);\r\n if (cookieMatch) {\r\n theme = cookieMatch[1];\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n } else {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme) {\r\n theme = currentTheme;\r\n }\r\n }\r\n } else if (json.theme) {\r\n theme = json.theme;\r\n }\r\n \r\n // Handle layout props preservation:\r\n // - If layoutProps are in response, use them and preserve them\r\n // - If layoutProps are NOT in response (layout hooks were skipped), use preserved ones\r\n let layoutProps: Record<string, any> = {};\r\n if (json.layoutProps !== undefined && json.layoutProps !== null) {\r\n // Layout hooks were executed, use new layout props and preserve them\r\n layoutProps = json.layoutProps;\r\n setPreservedLayoutProps(layoutProps);\r\n } else {\r\n // Layout hooks were skipped, use preserved layout props\r\n const preserved = getPreservedLayoutProps();\r\n if (preserved) {\r\n layoutProps = preserved;\r\n }\r\n }\r\n\r\n // Get page props (always from response)\r\n const pageProps = json.pageProps ?? json.props ?? {};\r\n\r\n // Combine: layout props (preserved or new) + page props (always new)\r\n // Page props override layout props if there's a conflict\r\n const combinedProps = {\r\n ...layoutProps,\r\n ...pageProps,\r\n theme, // Always include theme\r\n };\r\n\r\n const matched = matchRouteClient(nextUrl, routes);\r\n\r\n if (!matched) {\r\n window.location.href = nextUrl;\r\n return false;\r\n }\r\n\r\n const windowData: InitialData = {\r\n pathname: nextUrl,\r\n params: matched.params,\r\n props: combinedProps,\r\n metadata: json.metadata ?? null,\r\n theme,\r\n notFound: false,\r\n error: false,\r\n };\r\n\r\n setWindowData(windowData);\r\n\r\n // Update routerData\r\n const url = new URL(nextUrl, typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\");\r\n const routerData: RouterData = {\r\n pathname: url.pathname,\r\n params: matched.params,\r\n searchParams: Object.fromEntries(url.searchParams.entries()),\r\n };\r\n setRouterData(routerData);\r\n\r\n // Use prefetched route if available, otherwise load it\r\n const prefetched = prefetchedRoutes.get(matched.route);\r\n const components = prefetched ? await prefetched : await matched.route.load();\r\n \r\n // Cache the loaded route for future use\r\n if (!prefetched) {\r\n prefetchedRoutes.set(matched.route, Promise.resolve(components));\r\n }\r\n\r\n window.scrollTo({\r\n top: 0,\r\n behavior: \"smooth\",\r\n });\r\n\r\n setState({\r\n url: nextUrl,\r\n route: matched.route,\r\n params: matched.params,\r\n components,\r\n props: combinedProps,\r\n });\r\n\r\n return true;\r\n}\r\n\r\nexport type NavigateOptions = {\r\n /**\r\n * If true, forces revalidation of route data,\r\n * ignoring the cache and fetching fresh data from the server.\r\n * Similar to Next.js's `router.refresh()` behavior.\r\n */\r\n revalidate?: boolean;\r\n};\r\n\r\nexport async function navigate(\r\n nextUrl: string,\r\n handlers: NavigationHandlers,\r\n options?: NavigateOptions\r\n): Promise<void> {\r\n const { setState, routes, notFoundRoute, errorRoute } = handlers;\r\n\r\n try {\r\n const { ok, json } = await getRouteData(nextUrl, {\r\n revalidate: options?.revalidate,\r\n });\r\n\r\n if (json && json.error) {\r\n if (errorRoute) {\r\n const handled = await handleErrorRoute(\r\n nextUrl,\r\n json,\r\n errorRoute,\r\n setState\r\n );\r\n if (handled) return;\r\n } else {\r\n console.warn(\r\n \"[client] Error route not available, reloading page.\",\r\n errorRoute\r\n );\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n }\r\n\r\n // 🔴 HTTP error (404/500/etc)\r\n if (!ok) {\r\n if (json?.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n\r\n // Redirect via JSON\r\n if (json.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n\r\n // Handle notFound\r\n if (json.notFound) {\r\n await handleNotFoundRoute(nextUrl, json, notFoundRoute, setState);\r\n return;\r\n }\r\n\r\n // Normal route\r\n await handleNormalRoute(nextUrl, json, routes, setState);\r\n } catch (err) {\r\n console.error(\"[client] Error fetching FW data:\", err);\r\n window.location.href = nextUrl;\r\n }\r\n}\r\n\r\n// Cache for prefetched routes to avoid loading twice\r\nconst prefetchedRoutes = new WeakMap<ClientRouteLoaded, Promise<ClientLoadedComponents>>();\r\n\r\n/**\r\n * Prefetches a route's components when user hovers over a link.\r\n * This improves perceived performance by loading the route before the user clicks.\r\n */\r\nfunction prefetchRoute(\r\n url: string,\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null\r\n): void {\r\n const [pathname] = url.split(\"?\");\r\n const matched = matchRouteClient(pathname, routes);\r\n \r\n if (!matched) {\r\n // If no match, might be not-found route\r\n if (notFoundRoute) {\r\n const existing = prefetchedRoutes.get(notFoundRoute);\r\n if (!existing) {\r\n const promise = notFoundRoute.load();\r\n prefetchedRoutes.set(notFoundRoute, promise);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Prefetch the matched route if not already prefetched\r\n const existing = prefetchedRoutes.get(matched.route);\r\n if (!existing) {\r\n const promise = matched.route.load();\r\n prefetchedRoutes.set(matched.route, promise);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a hover handler for prefetching routes on link hover.\r\n */\r\nexport function createHoverHandler(\r\n routes: ClientRouteLoaded[],\r\n notFoundRoute: ClientRouteLoaded | null\r\n): (ev: MouseEvent) => void {\r\n return function handleHover(ev: MouseEvent) {\r\n try {\r\n const target = ev.target as HTMLElement | null;\r\n if (!target) return;\r\n\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) return;\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) return;\r\n if (href.startsWith(\"#\")) return;\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) return;\r\n if (anchor.target && anchor.target !== \"_self\") return;\r\n\r\n const nextUrl = url.pathname + url.search;\r\n const currentUrl = window.location.pathname + window.location.search;\r\n if (nextUrl === currentUrl) return;\r\n\r\n // Prefetch the route\r\n prefetchRoute(nextUrl, routes, notFoundRoute);\r\n } catch (error) {\r\n // Silently fail - prefetch is an optimization, not critical\r\n }\r\n };\r\n}\r\n\r\nexport function createClickHandler(\r\n navigate: (url: string, options?: NavigateOptions) => void\r\n): (ev: MouseEvent) => void {\r\n return function handleClick(ev: MouseEvent) {\r\n try {\r\n // Exit early if event was already prevented\r\n if (ev.defaultPrevented) return;\r\n \r\n // Verify it's a real mouse event (not synthetic or keyboard)\r\n if (ev.type !== \"click\") return;\r\n if (ev.button !== 0) return;\r\n if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;\r\n \r\n // Verify event has valid coordinates (real mouse events have them)\r\n const target = ev.target as HTMLElement | null;\r\n if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {\r\n // Could be a synthetic event, be more cautious\r\n if (target) {\r\n const tagName = target.tagName.toLowerCase();\r\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"button\" || tagName === \"select\") {\r\n return; // It's an input, don't process synthetic events\r\n }\r\n }\r\n }\r\n\r\n if (!target) return;\r\n\r\n // Check FIRST if target is an interactive element (faster)\r\n const tagName = target.tagName.toLowerCase();\r\n if (\r\n tagName === \"input\" ||\r\n tagName === \"textarea\" ||\r\n tagName === \"button\" ||\r\n tagName === \"select\" ||\r\n target.isContentEditable ||\r\n target.getAttribute(\"contenteditable\") === \"true\"\r\n ) {\r\n return; // It's an interactive element, don't process\r\n }\r\n\r\n // Check if it's inside an interactive element using closest (more efficient than composedPath)\r\n const interactiveParent = target.closest(\"input, textarea, button, select, [contenteditable], label\");\r\n if (interactiveParent) {\r\n // If parent is a label, check if it has an associated control\r\n if (interactiveParent.tagName.toLowerCase() === \"label\") {\r\n const label = interactiveParent as HTMLLabelElement;\r\n if (label.control) {\r\n return; // Label has an associated control (input, etc)\r\n }\r\n } else {\r\n return; // It's inside an interactive element\r\n }\r\n }\r\n\r\n // Only search for anchor if it's not an interactive element\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) return;\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) return;\r\n if (href.startsWith(\"#\")) return;\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) return;\r\n if (anchor.target && anchor.target !== \"_self\") return;\r\n\r\n ev.preventDefault();\r\n\r\n const nextUrl = url.pathname + url.search;\r\n const currentUrl = window.location.pathname + window.location.search;\r\n if (nextUrl === currentUrl) return;\r\n\r\n // Detect if link has data-revalidate to force revalidation\r\n const shouldRevalidate =\r\n anchor.hasAttribute(\"data-revalidate\") &&\r\n anchor.getAttribute(\"data-revalidate\") !== \"false\";\r\n\r\n window.history.pushState({}, \"\", nextUrl);\r\n navigate(nextUrl, shouldRevalidate ? { revalidate: true } : undefined);\r\n } catch (error) {\r\n // Silenciar errores para evitar bloquear el navegador\r\n console.error(\"[navigation] Error in click handler:\", error);\r\n }\r\n };\r\n}\r\n\r\nexport function createPopStateHandler(\r\n navigate: (url: string, options?: NavigateOptions) => void\r\n): () => void {\r\n return function handlePopState() {\r\n const nextUrl = window.location.pathname + window.location.search;\r\n navigate(nextUrl);\r\n };\r\n}\r\n\r\n","import { createContext, useContext } from \"react\";\r\n\r\nexport type NavigateFunction = (\r\n url: string,\r\n options?: { revalidate?: boolean; replace?: boolean }\r\n) => Promise<void>;\r\n\r\nexport interface RouterContextValue {\r\n navigate: NavigateFunction;\r\n}\r\n\r\nexport const RouterContext = createContext<RouterContextValue | null>(null);\r\n\r\nexport function useRouterContext(): RouterContextValue {\r\n const context = useContext(RouterContext);\r\n if (!context) {\r\n throw new Error(\r\n \"useRouter must be used within a RouterProvider. Make sure you're using it inside a Loly app.\"\r\n );\r\n }\r\n return context;\r\n}\r\n","/**\r\n * Sets up hot reload via Server-Sent Events (SSE) in development mode.\r\n * Listens for file changes and reloads the page when needed.\r\n * \r\n * This module is separate from bootstrap to keep concerns separated\r\n * and make the code more maintainable.\r\n */\r\nexport function setupHotReload(): void {\r\n // process.env.NODE_ENV is replaced by DefinePlugin at build time\r\n // DefinePlugin replaces this with a string literal: \"development\" or \"production\"\r\n // @ts-expect-error - process.env.NODE_ENV is replaced at build time by DefinePlugin\r\n const nodeEnv: string = process.env.NODE_ENV || \"production\";\r\n const isDev = nodeEnv === \"development\";\r\n \r\n if (!isDev) {\r\n // Silently skip in production - no logging\r\n return;\r\n }\r\n \r\n console.log(\"[hot-reload] Setting up hot reload client...\");\r\n\r\n let eventSource: EventSource | null = null;\r\n let reloadTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let reconnectAttempts = 0;\r\n const MAX_RECONNECT_ATTEMPTS = 10;\r\n const RECONNECT_DELAY = 1000; // 1 second\r\n const RELOAD_DELAY = 100; // Reduced from 500ms to 100ms for faster reload\r\n\r\n function connect(): void {\r\n try {\r\n if (eventSource) {\r\n console.log(\"[hot-reload] Closing existing EventSource connection\");\r\n eventSource.close();\r\n }\r\n\r\n const endpoint = \"/__fw/hot\";\r\n eventSource = new EventSource(endpoint);\r\n \r\n // Register ping listener FIRST (before message) to catch initial ping\r\n eventSource.addEventListener(\"ping\", (event: Event) => {\r\n if ('data' in event) {\r\n console.log(\"[hot-reload] ✅ Connected to hot reload server\");\r\n }\r\n reconnectAttempts = 0;\r\n });\r\n\r\n // Register message listener for reload events\r\n eventSource.addEventListener(\"message\", (event: MessageEvent) => {\r\n const data = event.data;\r\n if (data && typeof data === \"string\" && data.startsWith(\"reload:\")) {\r\n const filePath = data.slice(7);\r\n console.log(`[hot-reload] 📝 File changed: ${filePath}, reloading...`);\r\n\r\n // Clear existing timeout to debounce rapid events\r\n if (reloadTimeout) {\r\n clearTimeout(reloadTimeout);\r\n }\r\n\r\n // Debounce reload - wait a bit in case multiple files change at once\r\n reloadTimeout = setTimeout(() => {\r\n try {\r\n window.location.reload();\r\n } catch (error) {\r\n console.error(\"[hot-reload] ❌ Error reloading page:\", error);\r\n // Fallback: try to reload after a short delay\r\n setTimeout(() => window.location.reload(), 100);\r\n }\r\n }, RELOAD_DELAY);\r\n }\r\n });\r\n\r\n eventSource.onopen = () => {\r\n reconnectAttempts = 0; // Reset on successful connection\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n const states = [\"CONNECTING\", \"OPEN\", \"CLOSED\"];\r\n const state = states[eventSource?.readyState ?? 0] || \"UNKNOWN\";\r\n \r\n if (eventSource?.readyState === EventSource.CONNECTING) {\r\n // Still connecting, this is normal\r\n console.log(\"[hot-reload] ⏳ Still connecting...\");\r\n return;\r\n } else if (eventSource?.readyState === EventSource.OPEN) {\r\n // Connection is open but error occurred (might be temporary)\r\n console.warn(\"[hot-reload] ⚠️ Connection error (but connection is open):\", error);\r\n } else {\r\n // Connection closed, try to reconnect\r\n console.warn(`[hot-reload] ❌ Connection closed (readyState: ${state})`);\r\n \r\n if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {\r\n reconnectAttempts++;\r\n const delay = RECONNECT_DELAY * reconnectAttempts; // Exponential backoff\r\n \r\n if (reconnectTimeout) {\r\n clearTimeout(reconnectTimeout);\r\n }\r\n \r\n reconnectTimeout = setTimeout(() => {\r\n console.log(`[hot-reload] 🔄 Reconnecting... (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);\r\n connect();\r\n }, delay);\r\n } else {\r\n console.error(\"[hot-reload] ❌ Max reconnect attempts reached. Please refresh the page manually.\");\r\n }\r\n }\r\n };\r\n } catch (error) {\r\n console.error(\"[hot-reload] ❌ Failed to create EventSource:\", error);\r\n console.error(\"[hot-reload] EventSource may not be supported in this browser.\");\r\n }\r\n }\r\n\r\n // Initial connection\r\n connect();\r\n}\r\n\r\n"],"mappings":"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","names":["import_react","existing","navigate","tagName","import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/runtime.js
CHANGED
|
@@ -897,9 +897,7 @@ function AppShell({
|
|
|
897
897
|
function setupHotReload() {
|
|
898
898
|
const nodeEnv = process.env.NODE_ENV || "production";
|
|
899
899
|
const isDev = nodeEnv === "development";
|
|
900
|
-
console.log(`[hot-reload] NODE_ENV: ${nodeEnv}, isDev: ${isDev}`);
|
|
901
900
|
if (!isDev) {
|
|
902
|
-
console.log("[hot-reload] Skipping hot reload setup (not in development mode)");
|
|
903
901
|
return;
|
|
904
902
|
}
|
|
905
903
|
console.log("[hot-reload] Setting up hot reload client...");
|