@lolyjs/core 0.1.0-alpha.6 → 0.1.0-alpha.9

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/runtime.cjs CHANGED
@@ -33,7 +33,8 @@ var APP_CONTAINER_ID = "__app";
33
33
 
34
34
  // modules/runtime/client/window-data.ts
35
35
  function getWindowData() {
36
- return window[WINDOW_DATA_KEY] ?? null;
36
+ var _a;
37
+ return (_a = window[WINDOW_DATA_KEY]) != null ? _a : null;
37
38
  }
38
39
  function setWindowData(data) {
39
40
  window[WINDOW_DATA_KEY] = data;
@@ -46,7 +47,8 @@ function setWindowData(data) {
46
47
  }
47
48
  }
48
49
  function getCurrentTheme() {
49
- return getWindowData()?.theme ?? null;
50
+ var _a, _b;
51
+ return (_b = (_a = getWindowData()) == null ? void 0 : _a.theme) != null ? _b : null;
50
52
  }
51
53
 
52
54
  // modules/runtime/client/route-matcher.ts
@@ -114,6 +116,11 @@ var import_react = require("react");
114
116
  // modules/runtime/client/RouterView.tsx
115
117
  var import_jsx_runtime = require("react/jsx-runtime");
116
118
  function RouterView({ state }) {
119
+ console.log("[loly:RouterView] Rendering", {
120
+ url: state.url,
121
+ hasRoute: !!state.route,
122
+ hasComponents: !!state.components
123
+ });
117
124
  if (!state.route) {
118
125
  if (state.components === null) {
119
126
  return null;
@@ -125,6 +132,11 @@ function RouterView({ state }) {
125
132
  }
126
133
  const { Page, layouts } = state.components;
127
134
  const { params, props } = state;
135
+ console.log("[loly:RouterView] Creating page element", {
136
+ hasPage: !!Page,
137
+ layoutsCount: layouts.length,
138
+ paramsKeys: Object.keys(params)
139
+ });
128
140
  let element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Page, { params, ...props });
129
141
  const layoutChain = layouts.slice().reverse();
130
142
  for (const Layout of layoutChain) {
@@ -193,7 +205,7 @@ function evictOldest() {
193
205
  }
194
206
  function setCacheEntry(key, entry) {
195
207
  const existingEntry = dataCache.get(key);
196
- const wasFulfilled = existingEntry?.status === "fulfilled";
208
+ const wasFulfilled = (existingEntry == null ? void 0 : existingEntry.status) === "fulfilled";
197
209
  dataCache.set(key, entry);
198
210
  if (entry.status === "fulfilled") {
199
211
  if (!wasFulfilled) {
@@ -247,7 +259,7 @@ async function fetchRouteDataOnce(url) {
247
259
  }
248
260
  async function getRouteData(url, options) {
249
261
  const key = buildDataUrl(url);
250
- if (options?.revalidate) {
262
+ if (options == null ? void 0 : options.revalidate) {
251
263
  deleteCacheEntry(key);
252
264
  }
253
265
  const entry = dataCache.get(key);
@@ -274,6 +286,7 @@ async function getRouteData(url, options) {
274
286
 
275
287
  // modules/runtime/client/navigation.ts
276
288
  async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
289
+ var _a;
277
290
  try {
278
291
  const components = await errorRoute.load();
279
292
  let theme = "light";
@@ -300,7 +313,7 @@ async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
300
313
  pathname: nextUrl,
301
314
  params: json.params || {},
302
315
  props: errorProps,
303
- metadata: json.metadata ?? null,
316
+ metadata: (_a = json.metadata) != null ? _a : null,
304
317
  theme,
305
318
  notFound: false,
306
319
  error: true
@@ -324,6 +337,7 @@ async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
324
337
  }
325
338
  }
326
339
  async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
340
+ var _a, _b;
327
341
  let theme = "light";
328
342
  if (typeof document !== "undefined") {
329
343
  const cookieMatch = document.cookie.match(/theme=([^;]+)/);
@@ -339,14 +353,14 @@ async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
339
353
  theme = json.theme;
340
354
  }
341
355
  const notFoundProps = {
342
- ...json.props ?? {},
356
+ ...(_a = json.props) != null ? _a : {},
343
357
  theme
344
358
  };
345
359
  const windowData = {
346
360
  pathname: nextUrl,
347
361
  params: {},
348
362
  props: notFoundProps,
349
- metadata: json.metadata ?? null,
363
+ metadata: (_b = json.metadata) != null ? _b : null,
350
364
  theme,
351
365
  notFound: true,
352
366
  error: false
@@ -372,7 +386,8 @@ async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
372
386
  }
373
387
  }
374
388
  async function handleNormalRoute(nextUrl, json, routes, setState) {
375
- applyMetadata(json.metadata ?? null);
389
+ var _a, _b, _c;
390
+ applyMetadata((_a = json.metadata) != null ? _a : null);
376
391
  let theme = "light";
377
392
  if (typeof document !== "undefined") {
378
393
  const cookieMatch = document.cookie.match(/theme=([^;]+)/);
@@ -390,7 +405,7 @@ async function handleNormalRoute(nextUrl, json, routes, setState) {
390
405
  theme = json.theme;
391
406
  }
392
407
  const newProps = {
393
- ...json.props ?? {},
408
+ ...(_b = json.props) != null ? _b : {},
394
409
  theme
395
410
  // Always include theme
396
411
  };
@@ -403,7 +418,7 @@ async function handleNormalRoute(nextUrl, json, routes, setState) {
403
418
  pathname: nextUrl,
404
419
  params: matched.params,
405
420
  props: newProps,
406
- metadata: json.metadata ?? null,
421
+ metadata: (_c = json.metadata) != null ? _c : null,
407
422
  theme,
408
423
  notFound: false,
409
424
  error: false
@@ -427,7 +442,7 @@ async function navigate(nextUrl, handlers, options) {
427
442
  const { setState, routes, notFoundRoute, errorRoute } = handlers;
428
443
  try {
429
444
  const { ok, json } = await getRouteData(nextUrl, {
430
- revalidate: options?.revalidate
445
+ revalidate: options == null ? void 0 : options.revalidate
431
446
  });
432
447
  if (json && json.error) {
433
448
  console.log("[client] Error detected in response:", json);
@@ -473,11 +488,11 @@ async function navigate(nextUrl, handlers, options) {
473
488
  function createClickHandler(navigate2) {
474
489
  return function handleClick(ev) {
475
490
  const target = ev.target;
476
- const tagName = target?.tagName.toLowerCase() || "unknown";
491
+ const tagName = (target == null ? void 0 : target.tagName.toLowerCase()) || "unknown";
477
492
  console.log("[loly:click] Click event received", {
478
493
  type: ev.type,
479
494
  tagName,
480
- target: target?.tagName,
495
+ target: target == null ? void 0 : target.tagName,
481
496
  defaultPrevented: ev.defaultPrevented,
482
497
  button: ev.button,
483
498
  clientX: ev.clientX,
@@ -595,6 +610,10 @@ function AppShell({
595
610
  notFoundRoute,
596
611
  errorRoute
597
612
  }) {
613
+ console.log("[loly:AppShell] Component rendering", {
614
+ url: initialState.url,
615
+ hasRoute: !!initialState.route
616
+ });
598
617
  const [state, setState] = (0, import_react.useState)(initialState);
599
618
  const handlersRef = (0, import_react.useRef)({
600
619
  setState,
@@ -603,6 +622,11 @@ function AppShell({
603
622
  errorRoute
604
623
  });
605
624
  (0, import_react.useEffect)(() => {
625
+ console.log("[loly:AppShell] Updating handlersRef", {
626
+ routesCount: routes.length,
627
+ hasNotFound: !!notFoundRoute,
628
+ hasError: !!errorRoute
629
+ });
606
630
  handlersRef.current = {
607
631
  setState,
608
632
  routes,
@@ -611,7 +635,8 @@ function AppShell({
611
635
  };
612
636
  }, [routes, notFoundRoute, errorRoute]);
613
637
  (0, import_react.useEffect)(() => {
614
- console.log("[loly:AppShell] Setting up event listeners");
638
+ const effectId = Math.random().toString(36).substring(7);
639
+ console.log("[loly:AppShell] Setting up event listeners", { effectId });
615
640
  let isMounted = true;
616
641
  let listenerCount = 0;
617
642
  async function handleNavigate(nextUrl, options) {
@@ -634,6 +659,7 @@ function AppShell({
634
659
  });
635
660
  return () => {
636
661
  console.log("[loly:AppShell] Cleaning up event listeners", {
662
+ effectId,
637
663
  wasMounted: isMounted,
638
664
  listenersToRemove: listenerCount
639
665
  });
@@ -651,15 +677,17 @@ function AppShell({
651
677
 
652
678
  // modules/runtime/client/bootstrap.tsx
653
679
  var import_jsx_runtime3 = require("react/jsx-runtime");
680
+ var __loly_hydrated = false;
654
681
  async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute, errorRoute) {
655
- const isInitialNotFound = initialData?.notFound === true;
656
- const isInitialError = initialData?.error === true;
682
+ var _a, _b;
683
+ const isInitialNotFound = (initialData == null ? void 0 : initialData.notFound) === true;
684
+ const isInitialError = (initialData == null ? void 0 : initialData.error) === true;
657
685
  let initialRoute = null;
658
686
  let initialParams = {};
659
687
  let initialComponents = null;
660
688
  if (isInitialError && errorRoute) {
661
689
  initialRoute = errorRoute;
662
- initialParams = initialData?.params ?? {};
690
+ initialParams = (_a = initialData == null ? void 0 : initialData.params) != null ? _a : {};
663
691
  initialComponents = await errorRoute.load();
664
692
  } else if (isInitialNotFound && notFoundRoute) {
665
693
  initialRoute = notFoundRoute;
@@ -677,7 +705,7 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
677
705
  initialComponents = await notFoundRoute.load();
678
706
  } else {
679
707
  console.warn(
680
- `[client] No route match found for ${initialUrl}. Available routes:`,
708
+ `[client] No route match found for ${initialUrl}. Routes:`,
681
709
  routes.map((r) => r.pattern)
682
710
  );
683
711
  }
@@ -687,25 +715,28 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
687
715
  route: initialRoute,
688
716
  params: initialParams,
689
717
  components: initialComponents,
690
- props: initialData?.props ?? {}
718
+ props: (_b = initialData == null ? void 0 : initialData.props) != null ? _b : {}
691
719
  };
692
720
  }
693
721
  function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
694
- console.log("[loly:runtime] bootstrapClient called", {
695
- routesCount: routes.length,
696
- hasNotFound: !!notFoundRoute,
697
- hasError: !!errorRoute
698
- });
722
+ if (__loly_hydrated) {
723
+ console.warn("[loly:runtime] bootstrapClient SKIPPED (already hydrated)");
724
+ return;
725
+ }
726
+ __loly_hydrated = true;
727
+ console.log("[loly:runtime] bootstrapClient START");
699
728
  (async function bootstrap() {
700
729
  const container = document.getElementById(APP_CONTAINER_ID);
701
730
  const initialData = getWindowData();
702
731
  console.log("[loly:runtime] bootstrap starting", {
703
732
  hasContainer: !!container,
704
- containerId: APP_CONTAINER_ID,
705
- hasInitialData: !!initialData
733
+ hasInitialData: !!initialData,
734
+ containerId: APP_CONTAINER_ID
706
735
  });
707
736
  if (!container) {
708
- console.error(`[loly:runtime] Container #${APP_CONTAINER_ID} not found for hydration`);
737
+ console.error(
738
+ `[loly:runtime] Container #${APP_CONTAINER_ID} not found.`
739
+ );
709
740
  return;
710
741
  }
711
742
  const initialUrl = window.location.pathname + window.location.search;
@@ -723,7 +754,7 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
723
754
  hasRoute: !!initialState.route,
724
755
  hasComponents: !!initialState.components
725
756
  });
726
- if (initialData?.metadata) {
757
+ if (initialData == null ? void 0 : initialData.metadata) {
727
758
  applyMetadata(initialData.metadata);
728
759
  }
729
760
  console.log("[loly:runtime] Hydrating React app");
@@ -739,19 +770,11 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
739
770
  }
740
771
  )
741
772
  );
742
- console.log("[loly:runtime] React app hydrated successfully");
773
+ console.log("[loly:runtime] Hydrated successfully");
743
774
  } catch (error) {
744
- console.error(
745
- "[loly:runtime] Error loading initial route components for",
746
- initialUrl,
747
- error
748
- );
775
+ console.error("[loly:runtime] Error during hydration:", error);
749
776
  window.location.reload();
750
777
  }
751
778
  })();
752
779
  }
753
- // Annotate the CommonJS export names for ESM import in node:
754
- 0 && (module.exports = {
755
- bootstrapClient
756
- });
757
780
  //# sourceMappingURL=runtime.cjs.map
@@ -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"],"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 } from \"./window-data\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { AppShell } from \"./AppShell\";\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 * Bootstraps the client-side application.\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 console.log(\"[loly:runtime] bootstrapClient called\", {\r\n routesCount: routes.length,\r\n hasNotFound: !!notFoundRoute,\r\n hasError: !!errorRoute,\r\n });\r\n\r\n (async function bootstrap() {\r\n const container = document.getElementById(APP_CONTAINER_ID);\r\n const initialData = getWindowData();\r\n\r\n console.log(\"[loly:runtime] bootstrap starting\", {\r\n hasContainer: !!container,\r\n containerId: APP_CONTAINER_ID,\r\n hasInitialData: !!initialData,\r\n });\r\n\r\n if (!container) {\r\n console.error(`[loly:runtime] Container #${APP_CONTAINER_ID} not found for hydration`);\r\n return;\r\n }\r\n\r\n const initialUrl = window.location.pathname + window.location.search;\r\n console.log(\"[loly:runtime] Loading initial route\", { initialUrl });\r\n\r\n try {\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 console.log(\"[loly:runtime] Initial route loaded\", {\r\n url: initialState.url,\r\n hasRoute: !!initialState.route,\r\n hasComponents: !!initialState.components,\r\n });\r\n\r\n if (initialData?.metadata) {\r\n applyMetadata(initialData.metadata);\r\n }\r\n\r\n console.log(\"[loly:runtime] Hydrating React app\");\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 console.log(\"[loly:runtime] React app hydrated successfully\");\r\n } catch (error) {\r\n console.error(\r\n \"[loly:runtime] Error loading initial route components for\",\r\n initialUrl,\r\n error\r\n );\r\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 APP_CONTAINER_ID = \"__app\";\r\n\r\n","import { WINDOW_DATA_KEY } from \"./constants\";\r\nimport type { InitialData } from \"./types\";\r\n\r\nexport function getWindowData(): InitialData | null {\r\n return ((window as any)[WINDOW_DATA_KEY] as InitialData | undefined) ?? null;\r\n}\r\n\r\nexport function setWindowData(data: InitialData): void {\r\n (window as any)[WINDOW_DATA_KEY] = data;\r\n \r\n // Dispatch event for components to listen to (e.g., usePageProps, 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 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","export function applyMetadata(\r\n md?: { title?: string; description?: string } | null\r\n) {\r\n if (!md) return;\r\n\r\n if (md.title) {\r\n document.title = md.title;\r\n }\r\n\r\n if (md.description) {\r\n let meta = document.querySelector(\r\n 'meta[name=\"description\"]'\r\n ) as HTMLMetaElement | null;\r\n\r\n if (!meta) {\r\n meta = document.createElement(\"meta\");\r\n meta.name = \"description\";\r\n document.head.appendChild(meta);\r\n }\r\n\r\n meta.content = md.description;\r\n }\r\n}\r\n\r\n","import { useEffect, useState, useRef } from \"react\";\r\nimport { RouterView } from \"./RouterView\";\r\nimport {\r\n navigate,\r\n createClickHandler,\r\n createPopStateHandler,\r\n type NavigationHandlers,\r\n} from \"./navigation\";\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 // Mantener handlersRef actualizado\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 useEffect(() => {\r\n console.log(\"[loly:AppShell] Setting up event listeners\");\r\n \r\n // Flag para evitar múltiples listeners (por si React Strict Mode ejecuta dos veces)\r\n let isMounted = true;\r\n let listenerCount = 0;\r\n\r\n async function handleNavigate(\r\n nextUrl: string,\r\n options?: { revalidate?: boolean }\r\n ) {\r\n if (!isMounted) {\r\n console.warn(\"[loly:AppShell] navigate called but component is unmounted\");\r\n return;\r\n }\r\n console.log(\"[loly:AppShell] Navigating to\", nextUrl, options);\r\n await navigate(nextUrl, handlersRef.current, options);\r\n }\r\n\r\n const handleClick = createClickHandler(handleNavigate);\r\n const handlePopState = createPopStateHandler(handleNavigate);\r\n\r\n // Usar capture: false (burbujeo) para que los eventos del input se manejen primero\r\n window.addEventListener(\"click\", handleClick, false);\r\n window.addEventListener(\"popstate\", handlePopState, false);\r\n listenerCount = 2;\r\n \r\n console.log(\"[loly:AppShell] Event listeners added\", {\r\n clickListener: true,\r\n popStateListener: true,\r\n totalListeners: listenerCount,\r\n });\r\n\r\n return () => {\r\n console.log(\"[loly:AppShell] Cleaning up event listeners\", {\r\n wasMounted: isMounted,\r\n listenersToRemove: listenerCount,\r\n });\r\n isMounted = false;\r\n window.removeEventListener(\"click\", handleClick, false);\r\n window.removeEventListener(\"popstate\", handlePopState, false);\r\n };\r\n }, []); // Solo ejecutar una vez al montar\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 <RouterView key={routeKey} state={state} />;\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","type RouteData = {\n ok: boolean;\n status: number;\n json: any;\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(url: string): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const res = await fetch(dataUrl, {\n headers: {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n },\n });\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): 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\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 */\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 const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n revalidatePath(pathname);\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 (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: freshData.json.props || currentData.props || {},\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}\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 const promise = fetchRouteDataOnce(url)\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 if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry) {\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 entry.promise;\n }\n }\n\n // No entry in cache, fetch it\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n return promise;\n}\n","import { getRouteData } from \"../../react/cache/index\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { setWindowData, getCurrentTheme } from \"./window-data\";\r\nimport type {\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n InitialData,\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: any,\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 const errorProps = {\r\n ...(json.props || {\r\n error: json.message || \"An error occurred\",\r\n }),\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 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(\r\n \"[client] Error loading error route components:\",\r\n loadError\r\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: any,\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 const notFoundProps = {\r\n ...(json.props ?? {}),\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 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: any,\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 // Include theme in props so layouts receive it during SPA navigation\r\n const newProps = {\r\n ...(json.props ?? {}),\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: newProps,\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 const components = await matched.route.load();\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: newProps,\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 console.log(\"[client] Error detected in response:\", json);\r\n\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 && (json as any).redirect) {\r\n window.location.href = (json as any).redirect.destination;\r\n return;\r\n }\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n\r\n // Redirección vía JSON\r\n if (json.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n\r\n // Manejo de notFound\r\n if (json.notFound) {\r\n await handleNotFoundRoute(nextUrl, json, notFoundRoute, setState);\r\n return;\r\n }\r\n\r\n // Ruta normal\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\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 const target = ev.target as HTMLElement | null;\r\n const tagName = target?.tagName.toLowerCase() || \"unknown\";\r\n \r\n console.log(\"[loly:click] Click event received\", {\r\n type: ev.type,\r\n tagName,\r\n target: target?.tagName,\r\n defaultPrevented: ev.defaultPrevented,\r\n button: ev.button,\r\n clientX: ev.clientX,\r\n clientY: ev.clientY,\r\n });\r\n\r\n try {\r\n // Salir temprano si el evento ya fue prevenido\r\n if (ev.defaultPrevented) {\r\n console.log(\"[loly:click] Event already prevented, skipping\");\r\n return;\r\n }\r\n \r\n // Verificar que sea un evento de mouse real (no sintético o de teclado)\r\n if (ev.type !== \"click\") {\r\n console.log(\"[loly:click] Not a click event, skipping\", { type: ev.type });\r\n return;\r\n }\r\n if (ev.button !== 0) {\r\n console.log(\"[loly:click] Not left button, skipping\", { button: ev.button });\r\n return;\r\n }\r\n if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {\r\n console.log(\"[loly:click] Modifier keys pressed, skipping\");\r\n return;\r\n }\r\n \r\n // Verificar que el evento tenga coordenadas válidas (eventos de mouse reales las tienen)\r\n if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {\r\n // Podría ser un evento sintético, ser más cauteloso\r\n if (target) {\r\n const tagName = target.tagName.toLowerCase();\r\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"button\" || tagName === \"select\") {\r\n console.log(\"[loly:click] Synthetic event on interactive element, skipping\", { tagName });\r\n return; // Es un input, no procesar eventos sintéticos\r\n }\r\n }\r\n }\r\n\r\n if (!target) {\r\n console.log(\"[loly:click] No target, skipping\");\r\n return;\r\n }\r\n\r\n // Verificar PRIMERO si el target es un elemento interactivo (más rápido)\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 console.log(\"[loly:click] Target is interactive element, skipping\", { tagName });\r\n return; // Es un elemento interactivo, no procesar\r\n }\r\n\r\n // Verificar si está dentro de un elemento interactivo usando closest (más eficiente que composedPath)\r\n const interactiveParent = target.closest(\"input, textarea, button, select, [contenteditable], label\");\r\n if (interactiveParent) {\r\n // Si el parent es un label, verificar si tiene un control asociado\r\n if (interactiveParent.tagName.toLowerCase() === \"label\") {\r\n const label = interactiveParent as HTMLLabelElement;\r\n if (label.control) {\r\n console.log(\"[loly:click] Inside label with control, skipping\");\r\n return; // El label tiene un control asociado (input, etc)\r\n }\r\n } else {\r\n console.log(\"[loly:click] Inside interactive parent, skipping\", {\r\n parentTag: interactiveParent.tagName.toLowerCase(),\r\n });\r\n return; // Está dentro de un elemento interactivo\r\n }\r\n }\r\n\r\n // Solo buscar anchor si no es un elemento interactivo\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) {\r\n console.log(\"[loly:click] No anchor found, skipping\");\r\n return;\r\n }\r\n \r\n console.log(\"[loly:click] Anchor found, processing navigation\", {\r\n href: anchor.getAttribute(\"href\"),\r\n });\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) {\r\n console.log(\"[loly:click] No href attribute, skipping\");\r\n return;\r\n }\r\n if (href.startsWith(\"#\")) {\r\n console.log(\"[loly:click] Hash link, skipping\");\r\n return;\r\n }\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) {\r\n console.log(\"[loly:click] External link, skipping\", { origin: url.origin });\r\n return;\r\n }\r\n if (anchor.target && anchor.target !== \"_self\") {\r\n console.log(\"[loly:click] Link has target, skipping\", { target: anchor.target });\r\n return;\r\n }\r\n\r\n ev.preventDefault();\r\n console.log(\"[loly:click] Prevented default, navigating\");\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) {\r\n console.log(\"[loly:click] Same URL, skipping\", { nextUrl });\r\n return;\r\n }\r\n\r\n // Detectar si el link tiene data-revalidate para forzar revalidación\r\n const shouldRevalidate =\r\n anchor.hasAttribute(\"data-revalidate\") &&\r\n anchor.getAttribute(\"data-revalidate\") !== \"false\";\r\n\r\n console.log(\"[loly:click] Pushing state and navigating\", {\r\n nextUrl,\r\n currentUrl,\r\n shouldRevalidate,\r\n });\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(\"[loly:click] 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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAA4B;;;ACCrB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;;;ACCzB,SAAS,gBAAoC;AAClD,SAAS,OAAe,eAAe,KAAiC;AAC1E;AAEO,SAAS,cAAc,MAAyB;AACrD,EAAC,OAAe,eAAe,IAAI;AAInC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,MACL,IAAI,YAAY,mBAAmB;AAAA,QACjC,QAAQ,EAAE,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEO,SAAS,kBAAiC;AAC/C,SAAO,cAAc,GAAG,SAAS;AACnC;;;ACrBO,SAAS,4BAA4B,SAAyB;AACnE,QAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,QAAM,aAAuB,CAAC;AAE9B,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,MAAM,SAAS,CAAC;AAGtB,QAAI,IAAI,WAAW,MAAM,KAAK,IAAI,SAAS,GAAG,GAAG;AAC/C,UAAI,MAAM,SAAS,SAAS,GAAG;AAC7B,cAAM,IAAI;AAAA,UACR,sBAAsB,GAAG,SAAS,OAAO;AAAA,QAC3C;AAAA,MACF;AACA,iBAAW,KAAK,MAAM;AACtB;AAAA,IACF;AAGA,QAAI,IAAI,WAAW,GAAG,KAAK,IAAI,SAAS,GAAG,GAAG;AAC5C,iBAAW,KAAK,SAAS;AACzB;AAAA,IACF;AAGA,UAAM,UAAU,IAAI,QAAQ,uBAAuB,MAAM;AACzD,eAAW,KAAK,OAAO;AAAA,EACzB;AAEA,QAAM,cAAc,OAAO,WAAW,KAAK,GAAG,IAAI;AAClD,SAAO,IAAI,OAAO,WAAW;AAC/B;AAEO,SAAS,iBACd,gBACA,QACyB;AACzB,QAAM,CAAC,QAAQ,IAAI,eAAe,MAAM,GAAG;AAC3C,aAAW,KAAK,QAAQ;AACtB,UAAM,QAAQ,4BAA4B,EAAE,OAAO;AACnD,UAAM,QAAQ,MAAM,KAAK,QAAQ;AACjC,QAAI,CAAC,MAAO;AAEZ,UAAM,SAAiC,CAAC;AACxC,MAAE,WAAW,QAAQ,CAAC,MAAM,QAAQ;AAClC,aAAO,IAAI,IAAI,mBAAmB,MAAM,MAAM,CAAC,KAAK,EAAE;AAAA,IACxD,CAAC;AAED,WAAO,EAAE,OAAO,GAAG,OAAO;AAAA,EAC5B;AACA,SAAO;AACT;;;ACrDO,SAAS,cACd,IACA;AACA,MAAI,CAAC,GAAI;AAET,MAAI,GAAG,OAAO;AACZ,aAAS,QAAQ,GAAG;AAAA,EACtB;AAEA,MAAI,GAAG,aAAa;AAClB,QAAI,OAAO,SAAS;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,CAAC,MAAM;AACT,aAAO,SAAS,cAAc,MAAM;AACpC,WAAK,OAAO;AACZ,eAAS,KAAK,YAAY,IAAI;AAAA,IAChC;AAEA,SAAK,UAAU,GAAG;AAAA,EACpB;AACF;;;ACtBA,mBAA4C;;;ACQjC;AANJ,SAAS,WAAW,EAAE,MAAM,GAA8B;AAC/D,MAAI,CAAC,MAAM,OAAO;AAEhB,QAAI,MAAM,eAAe,MAAM;AAC7B,aAAO;AAAA,IACT;AACA,WAAO,4CAAC,QAAG,mCAAqB;AAAA,EAClC;AAEA,MAAI,CAAC,MAAM,YAAY;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,QAAQ,IAAI,MAAM;AAChC,QAAM,EAAE,QAAQ,MAAM,IAAI;AAE1B,MAAI,UAAU,4CAAC,QAAK,QAAiB,GAAG,OAAO;AAE/C,QAAM,cAAc,QAAQ,MAAM,EAAE,QAAQ;AAC5C,aAAW,UAAU,aAAa;AAChC,cACE,4CAAC,UAAO,QAAiB,GAAG,OACzB,mBACH;AAAA,EAEJ;AAEA,SAAO;AACT;;;ACjBA,IAAM,YAAY;AAGlB,IAAM,iBAAiB;AAQvB,SAAS,gBAA4B;AACnC,MAAI,OAAO,WAAW,aAAa;AACjC,QAAI,CAAE,OAAe,SAAS,GAAG;AAC/B,MAAC,OAAe,SAAS,IAAI;AAAA,QAC3B,MAAM,oBAAI,IAAwB;AAAA,QAClC,OAAO,oBAAI,IAAyB;AAAA,QACpC,KAAK,CAAC;AAAA,MACR;AAAA,IACF;AACA,WAAQ,OAAe,SAAS;AAAA,EAClC;AAEA,SAAO;AAAA,IACL,MAAM,oBAAI,IAAwB;AAAA,IAClC,OAAO,oBAAI,IAAyB;AAAA,IACpC,KAAK,CAAC;AAAA,EACR;AACF;AAEA,IAAM,aAAa,cAAc;AACjC,IAAM,YAAY,WAAW;AAC7B,IAAM,YAAY,WAAW;AAC7B,IAAM,MAAM,WAAW;AAOvB,SAAS,gBAAgB,KAAqB;AAC5C,SAAO,IAAI,MAAM,GAAG,EAAE,CAAC;AACzB;AAKA,SAAS,WAAW,KAAmB;AACrC,QAAM,WAAW,gBAAgB,GAAG;AACpC,MAAI,CAAC,UAAU,IAAI,QAAQ,GAAG;AAC5B,cAAU,IAAI,UAAU,oBAAI,IAAI,CAAC;AAAA,EACnC;AACA,YAAU,IAAI,QAAQ,EAAG,IAAI,GAAG;AAClC;AAKA,SAAS,gBAAgB,KAAmB;AAC1C,QAAM,WAAW,gBAAgB,GAAG;AACpC,QAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,MAAI,MAAM;AACR,SAAK,OAAO,GAAG;AACf,QAAI,KAAK,SAAS,GAAG;AACnB,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;AAKA,SAAS,UAAU,KAAmB;AACpC,QAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,MAAI,UAAU,IAAI;AAChB,QAAI,OAAO,OAAO,CAAC;AAAA,EACrB;AACA,MAAI,KAAK,GAAG;AACd;AAKA,SAAS,cAAoB;AAC3B,SAAO,IAAI,UAAU,kBAAkB,IAAI,SAAS,GAAG;AACrD,UAAM,YAAY,IAAI,MAAM;AAC5B,cAAU,OAAO,SAAS;AAC1B,oBAAgB,SAAS;AAAA,EAC3B;AACF;AAKA,SAAS,cAAc,KAAa,OAAyB;AAC3D,QAAM,gBAAgB,UAAU,IAAI,GAAG;AACvC,QAAM,eAAe,eAAe,WAAW;AAE/C,YAAU,IAAI,KAAK,KAAK;AAGxB,MAAI,MAAM,WAAW,aAAa;AAEhC,QAAI,CAAC,cAAc;AACjB,iBAAW,GAAG;AAAA,IAChB;AACA,cAAU,GAAG;AACb,gBAAY;AAAA,EACd,WAAW,cAAc;AAEvB,oBAAgB,GAAG;AAAA,EACrB;AACF;AAKA,SAAS,iBAAiB,KAAmB;AAC3C,MAAI,UAAU,IAAI,GAAG,GAAG;AACtB,cAAU,OAAO,GAAG;AACpB,oBAAgB,GAAG;AACnB,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,IAAI;AACnB,UAAI,OAAO,UAAU,CAAC;AAAA,IACxB;AAAA,EACF;AACF;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,OAAO,IAAI,SAAS,GAAG,IAAI,MAAM,OAAO;AACjD;AAEA,eAAe,mBAAmB,KAAiC;AACjE,QAAM,UAAU,aAAa,GAAG;AAEhC,QAAM,MAAM,MAAM,MAAM,SAAS;AAAA,IAC/B,SAAS;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,MAAI,OAAY,CAAC;AAEjB,MAAI;AACF,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,MAAM;AACR,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB;AAAA,EACF,SAAS,YAAY;AACnB,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAoB;AAAA,IACxB,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;AAuKA,eAAsB,aACpB,KACA,SACoB;AACpB,QAAM,MAAM,aAAa,GAAG;AAG5B,MAAI,SAAS,YAAY;AACvB,qBAAiB,GAAG;AAAA,EACtB;AAEA,QAAM,QAAQ,UAAU,IAAI,GAAG;AAE/B,MAAI,OAAO;AACT,QAAI,MAAM,WAAW,aAAa;AAEhC,gBAAU,GAAG;AACb,aAAO,MAAM;AAAA,IACf;AACA,QAAI,MAAM,WAAW,WAAW;AAC9B,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAGA,QAAM,UAAU,mBAAmB,GAAG,EACnC,KAAK,CAAC,UAAU;AACf,kBAAc,KAAK,EAAE,QAAQ,aAAa,MAAM,CAAC;AACjD,WAAO;AAAA,EACT,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,YAAQ,MAAM,8CAA8C,KAAK;AACjE,cAAU,IAAI,KAAK,EAAE,QAAQ,YAAY,MAAM,CAAC;AAChD,UAAM;AAAA,EACR,CAAC;AAEH,YAAU,IAAI,KAAK,EAAE,QAAQ,WAAW,QAAQ,CAAC;AACjD,SAAO;AACT;;;AC5WA,eAAe,iBACb,SACA,MACA,YACA,UACkB;AAClB,MAAI;AACF,UAAM,aAAa,MAAM,WAAW,KAAK;AAGzC,QAAI,QAAgB;AACpB,QAAI,OAAO,aAAa,aAAa;AACnC,YAAM,cAAc,SAAS,OAAO,MAAM,eAAe;AACzD,UAAI,aAAa;AACf,gBAAQ,YAAY,CAAC;AAAA,MACvB,WAAW,KAAK,OAAO;AACrB,gBAAQ,KAAK;AAAA,MACf,OAAO;AACL,cAAM,eAAe,gBAAgB;AACrC,YAAI,aAAc,SAAQ;AAAA,MAC5B;AAAA,IACF,WAAW,KAAK,OAAO;AACrB,cAAQ,KAAK;AAAA,IACf;AAEA,UAAM,aAAa;AAAA,MACjB,GAAI,KAAK,SAAS;AAAA,QAChB,OAAO,KAAK,WAAW;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,aAA0B;AAAA,MAC9B,UAAU;AAAA,MACV,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB,OAAO;AAAA,MACP,UAAU,KAAK,YAAY;AAAA,MAC3B;AAAA,MACA,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAEA,kBAAc,UAAU;AAExB,aAAS;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,KAAK,UAAU,CAAC;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT,SAAS,WAAW;AAClB,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,IACF;AACA,WAAO,SAAS,OAAO;AACvB,WAAO;AAAA,EACT;AACF;AAEA,eAAe,oBACb,SACA,MACA,eACA,UACe;AAEf,MAAI,QAAgB;AACpB,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,cAAc,SAAS,OAAO,MAAM,eAAe;AACzD,QAAI,aAAa;AACf,cAAQ,YAAY,CAAC;AAAA,IACvB,WAAW,KAAK,OAAO;AACrB,cAAQ,KAAK;AAAA,IACf,OAAO;AACL,YAAM,eAAe,gBAAgB;AACrC,UAAI,aAAc,SAAQ;AAAA,IAC5B;AAAA,EACF,WAAW,KAAK,OAAO;AACrB,YAAQ,KAAK;AAAA,EACf;AAEA,QAAM,gBAAgB;AAAA,IACpB,GAAI,KAAK,SAAS,CAAC;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,aAA0B;AAAA,IAC9B,UAAU;AAAA,IACV,QAAQ,CAAC;AAAA,IACT,OAAO;AAAA,IACP,UAAU,KAAK,YAAY;AAAA,IAC3B;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAEA,gBAAc,UAAU;AAExB,MAAI,eAAe;AACjB,UAAM,aAAa,MAAM,cAAc,KAAK;AAC5C,aAAS;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAAA,EACH,OAAO;AACL,aAAS;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,MACT,YAAY;AAAA,MACZ,OAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AACF;AAEA,eAAe,kBACb,SACA,MACA,QACA,UACkB;AAClB,gBAAc,KAAK,YAAY,IAAI;AAInC,MAAI,QAAgB;AACpB,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,cAAc,SAAS,OAAO,MAAM,eAAe;AACzD,QAAI,aAAa;AACf,cAAQ,YAAY,CAAC;AAAA,IACvB,WAAW,KAAK,OAAO;AACrB,cAAQ,KAAK;AAAA,IACf,OAAO;AACL,YAAM,eAAe,gBAAgB;AACrC,UAAI,cAAc;AAChB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,WAAW,KAAK,OAAO;AACrB,YAAQ,KAAK;AAAA,EACf;AAGA,QAAM,WAAW;AAAA,IACf,GAAI,KAAK,SAAS,CAAC;AAAA,IACnB;AAAA;AAAA,EACF;AAEA,QAAM,UAAU,iBAAiB,SAAS,MAAM;AAEhD,MAAI,CAAC,SAAS;AACZ,WAAO,SAAS,OAAO;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,aAA0B;AAAA,IAC9B,UAAU;AAAA,IACV,QAAQ,QAAQ;AAAA,IAChB,OAAO;AAAA,IACP,UAAU,KAAK,YAAY;AAAA,IAC3B;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAEA,gBAAc,UAAU;AAExB,QAAM,aAAa,MAAM,QAAQ,MAAM,KAAK;AAE5C,SAAO,SAAS;AAAA,IACd,KAAK;AAAA,IACL,UAAU;AAAA,EACZ,CAAC;AAED,WAAS;AAAA,IACP,KAAK;AAAA,IACL,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA,OAAO;AAAA,EACT,CAAC;AAED,SAAO;AACT;AAWA,eAAsB,SACpB,SACA,UACA,SACe;AACf,QAAM,EAAE,UAAU,QAAQ,eAAe,WAAW,IAAI;AAExD,MAAI;AACF,UAAM,EAAE,IAAI,KAAK,IAAI,MAAM,aAAa,SAAS;AAAA,MAC/C,YAAY,SAAS;AAAA,IACvB,CAAC;AAED,QAAI,QAAQ,KAAK,OAAO;AACtB,cAAQ,IAAI,wCAAwC,IAAI;AAExD,UAAI,YAAY;AACd,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,YAAI,QAAS;AAAA,MACf,OAAO;AACL,gBAAQ;AAAA,UACN;AAAA,UACA;AAAA,QACF;AACA,eAAO,SAAS,OAAO;AACvB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,IAAI;AACP,UAAI,QAAS,KAAa,UAAU;AAClC,eAAO,SAAS,OAAQ,KAAa,SAAS;AAC9C;AAAA,MACF;AACA,aAAO,SAAS,OAAO;AACvB;AAAA,IACF;AAGA,QAAI,KAAK,UAAU;AACjB,aAAO,SAAS,OAAO,KAAK,SAAS;AACrC;AAAA,IACF;AAGA,QAAI,KAAK,UAAU;AACjB,YAAM,oBAAoB,SAAS,MAAM,eAAe,QAAQ;AAChE;AAAA,IACF;AAGA,UAAM,kBAAkB,SAAS,MAAM,QAAQ,QAAQ;AAAA,EACzD,SAAS,KAAK;AACZ,YAAQ,MAAM,oCAAoC,GAAG;AACrD,WAAO,SAAS,OAAO;AAAA,EACzB;AACF;AAEO,SAAS,mBACdA,WAC0B;AAC1B,SAAO,SAAS,YAAY,IAAgB;AAC1C,UAAM,SAAS,GAAG;AAClB,UAAM,UAAU,QAAQ,QAAQ,YAAY,KAAK;AAEjD,YAAQ,IAAI,qCAAqC;AAAA,MAC/C,MAAM,GAAG;AAAA,MACT;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,kBAAkB,GAAG;AAAA,MACrB,QAAQ,GAAG;AAAA,MACX,SAAS,GAAG;AAAA,MACZ,SAAS,GAAG;AAAA,IACd,CAAC;AAED,QAAI;AAEF,UAAI,GAAG,kBAAkB;AACvB,gBAAQ,IAAI,gDAAgD;AAC5D;AAAA,MACF;AAGA,UAAI,GAAG,SAAS,SAAS;AACvB,gBAAQ,IAAI,4CAA4C,EAAE,MAAM,GAAG,KAAK,CAAC;AACzE;AAAA,MACF;AACA,UAAI,GAAG,WAAW,GAAG;AACnB,gBAAQ,IAAI,0CAA0C,EAAE,QAAQ,GAAG,OAAO,CAAC;AAC3E;AAAA,MACF;AACA,UAAI,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,QAAQ;AACxD,gBAAQ,IAAI,8CAA8C;AAC1D;AAAA,MACF;AAGA,UAAI,GAAG,YAAY,KAAK,GAAG,YAAY,KAAK,GAAG,WAAW,GAAG;AAE3D,YAAI,QAAQ;AACV,gBAAMC,WAAU,OAAO,QAAQ,YAAY;AAC3C,cAAIA,aAAY,WAAWA,aAAY,cAAcA,aAAY,YAAYA,aAAY,UAAU;AACjG,oBAAQ,IAAI,iEAAiE,EAAE,SAAAA,SAAQ,CAAC;AACxF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,QAAQ;AACX,gBAAQ,IAAI,kCAAkC;AAC9C;AAAA,MACF;AAGA,YAAMA,WAAU,OAAO,QAAQ,YAAY;AAC3C,UACEA,aAAY,WACZA,aAAY,cACZA,aAAY,YACZA,aAAY,YACZ,OAAO,qBACP,OAAO,aAAa,iBAAiB,MAAM,QAC3C;AACA,gBAAQ,IAAI,wDAAwD,EAAE,SAAAA,SAAQ,CAAC;AAC/E;AAAA,MACF;AAGA,YAAM,oBAAoB,OAAO,QAAQ,2DAA2D;AACpG,UAAI,mBAAmB;AAErB,YAAI,kBAAkB,QAAQ,YAAY,MAAM,SAAS;AACvD,gBAAM,QAAQ;AACd,cAAI,MAAM,SAAS;AACjB,oBAAQ,IAAI,kDAAkD;AAC9D;AAAA,UACF;AAAA,QACF,OAAO;AACL,kBAAQ,IAAI,oDAAoD;AAAA,YAC9D,WAAW,kBAAkB,QAAQ,YAAY;AAAA,UACnD,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAGA,YAAM,SAAS,OAAO,QAAQ,SAAS;AACvC,UAAI,CAAC,QAAQ;AACX,gBAAQ,IAAI,wCAAwC;AACpD;AAAA,MACF;AAEA,cAAQ,IAAI,oDAAoD;AAAA,QAC9D,MAAM,OAAO,aAAa,MAAM;AAAA,MAClC,CAAC;AAEH,YAAM,OAAO,OAAO,aAAa,MAAM;AACvC,UAAI,CAAC,MAAM;AACT,gBAAQ,IAAI,0CAA0C;AACtD;AAAA,MACF;AACA,UAAI,KAAK,WAAW,GAAG,GAAG;AACxB,gBAAQ,IAAI,kCAAkC;AAC9C;AAAA,MACF;AAEA,YAAM,MAAM,IAAI,IAAI,MAAM,OAAO,SAAS,IAAI;AAC9C,UAAI,IAAI,WAAW,OAAO,SAAS,QAAQ;AACzC,gBAAQ,IAAI,wCAAwC,EAAE,QAAQ,IAAI,OAAO,CAAC;AAC1E;AAAA,MACF;AACA,UAAI,OAAO,UAAU,OAAO,WAAW,SAAS;AAC9C,gBAAQ,IAAI,0CAA0C,EAAE,QAAQ,OAAO,OAAO,CAAC;AAC/E;AAAA,MACF;AAEA,SAAG,eAAe;AAClB,cAAQ,IAAI,4CAA4C;AAExD,YAAM,UAAU,IAAI,WAAW,IAAI;AACnC,YAAM,aAAa,OAAO,SAAS,WAAW,OAAO,SAAS;AAC9D,UAAI,YAAY,YAAY;AAC1B,gBAAQ,IAAI,mCAAmC,EAAE,QAAQ,CAAC;AAC1D;AAAA,MACF;AAGA,YAAM,mBACJ,OAAO,aAAa,iBAAiB,KACrC,OAAO,aAAa,iBAAiB,MAAM;AAE7C,cAAQ,IAAI,6CAA6C;AAAA,QACvD;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,QAAQ,UAAU,CAAC,GAAG,IAAI,OAAO;AACxC,MAAAD,UAAS,SAAS,mBAAmB,EAAE,YAAY,KAAK,IAAI,MAAS;AAAA,IACrE,SAAS,OAAO;AAEd,cAAQ,MAAM,wCAAwC,KAAK;AAAA,IAC7D;AAAA,EACF;AACF;AAEO,SAAS,sBACdA,WACY;AACZ,SAAO,SAAS,iBAAiB;AAC/B,UAAM,UAAU,OAAO,SAAS,WAAW,OAAO,SAAS;AAC3D,IAAAA,UAAS,OAAO;AAAA,EAClB;AACF;;;AHtVS,IAAAE,sBAAA;AAzEF,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAyB,YAAY;AAC/D,QAAM,kBAAc,qBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,8BAAU,MAAM;AACd,gBAAY,UAAU;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,eAAe,UAAU,CAAC;AAEtC,8BAAU,MAAM;AACd,YAAQ,IAAI,4CAA4C;AAGxD,QAAI,YAAY;AAChB,QAAI,gBAAgB;AAEpB,mBAAe,eACb,SACA,SACA;AACA,UAAI,CAAC,WAAW;AACd,gBAAQ,KAAK,4DAA4D;AACzE;AAAA,MACF;AACA,cAAQ,IAAI,iCAAiC,SAAS,OAAO;AAC7D,YAAM,SAAS,SAAS,YAAY,SAAS,OAAO;AAAA,IACtD;AAEA,UAAM,cAAc,mBAAmB,cAAc;AACrD,UAAM,iBAAiB,sBAAsB,cAAc;AAG3D,WAAO,iBAAiB,SAAS,aAAa,KAAK;AACnD,WAAO,iBAAiB,YAAY,gBAAgB,KAAK;AACzD,oBAAgB;AAEhB,YAAQ,IAAI,yCAAyC;AAAA,MACnD,eAAe;AAAA,MACf,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,IAClB,CAAC;AAED,WAAO,MAAM;AACX,cAAQ,IAAI,+CAA+C;AAAA,QACzD,YAAY;AAAA,QACZ,mBAAmB;AAAA,MACrB,CAAC;AACD,kBAAY;AACZ,aAAO,oBAAoB,SAAS,aAAa,KAAK;AACtD,aAAO,oBAAoB,YAAY,gBAAgB,KAAK;AAAA,IAC9D;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM,UAAU;AAChC,QAAM,aAAa,MAAM,UAAU;AACnC,QAAM,YAAY,UAAU,UAAU,aAAa,aAAa;AAChE,QAAM,WAAW,GAAG,MAAM,GAAG,IAAI,SAAS;AAE1C,SAAO,6CAAC,cAA0B,SAAV,QAAwB;AAClD;;;ALyBQ,IAAAC,sBAAA;AA3GR,eAAsB,iBACpB,YACA,aACA,QACA,eACA,YACyB;AACzB,QAAM,oBAAoB,aAAa,aAAa;AACpD,QAAM,iBAAiB,aAAa,UAAU;AAE9C,MAAI,eAAyC;AAC7C,MAAI,gBAAwC,CAAC;AAC7C,MAAI,oBAAoB;AAExB,MAAI,kBAAkB,YAAY;AAChC,mBAAe;AACf,oBAAgB,aAAa,UAAU,CAAC;AACxC,wBAAoB,MAAM,WAAW,KAAK;AAAA,EAC5C,WAAW,qBAAqB,eAAe;AAC7C,mBAAe;AACf,oBAAgB,CAAC;AACjB,wBAAoB,MAAM,cAAc,KAAK;AAAA,EAC/C,OAAO;AACL,UAAM,QAAQ,iBAAiB,YAAY,MAAM;AACjD,QAAI,OAAO;AACT,qBAAe,MAAM;AACrB,sBAAgB,MAAM;AACtB,0BAAoB,MAAM,MAAM,MAAM,KAAK;AAAA,IAC7C,WAAW,eAAe;AACxB,qBAAe;AACf,sBAAgB,CAAC;AACjB,0BAAoB,MAAM,cAAc,KAAK;AAAA,IAC/C,OAAO;AACL,cAAQ;AAAA,QACN,qCAAqC,UAAU;AAAA,QAC/C,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,OAAO,aAAa,SAAS,CAAC;AAAA,EAChC;AACF;AASO,SAAS,gBACd,QACA,eACA,aAAuC,MACjC;AACN,UAAQ,IAAI,yCAAyC;AAAA,IACnD,aAAa,OAAO;AAAA,IACpB,aAAa,CAAC,CAAC;AAAA,IACf,UAAU,CAAC,CAAC;AAAA,EACd,CAAC;AAED,GAAC,eAAe,YAAY;AAC1B,UAAM,YAAY,SAAS,eAAe,gBAAgB;AAC1D,UAAM,cAAc,cAAc;AAElC,YAAQ,IAAI,qCAAqC;AAAA,MAC/C,cAAc,CAAC,CAAC;AAAA,MAChB,aAAa;AAAA,MACb,gBAAgB,CAAC,CAAC;AAAA,IACpB,CAAC;AAED,QAAI,CAAC,WAAW;AACd,cAAQ,MAAM,6BAA6B,gBAAgB,0BAA0B;AACrF;AAAA,IACF;AAEA,UAAM,aAAa,OAAO,SAAS,WAAW,OAAO,SAAS;AAC9D,YAAQ,IAAI,wCAAwC,EAAE,WAAW,CAAC;AAElE,QAAI;AACF,YAAM,eAAe,MAAM;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,cAAQ,IAAI,uCAAuC;AAAA,QACjD,KAAK,aAAa;AAAA,QAClB,UAAU,CAAC,CAAC,aAAa;AAAA,QACzB,eAAe,CAAC,CAAC,aAAa;AAAA,MAChC,CAAC;AAED,UAAI,aAAa,UAAU;AACzB,sBAAc,YAAY,QAAQ;AAAA,MACpC;AAEA,cAAQ,IAAI,oCAAoC;AAChD;AAAA,QACE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,gDAAgD;AAAA,IAC9D,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACF,GAAG;AACL;","names":["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"],"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 } from \"./window-data\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { AppShell } from \"./AppShell\";\r\nimport type {\r\n InitialData,\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n} from \"./types\";\r\n\r\n// 🚨 EVITA HIDRATACIÓN DOBLE — FIX CRÍTICO\r\nlet __loly_hydrated = false;\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}. 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 * Bootstraps the client-side application.\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\r\n // 🚨 FIX: NO EJECUTAR 2 VECES\r\n if (__loly_hydrated) {\r\n console.warn(\"[loly:runtime] bootstrapClient SKIPPED (already hydrated)\");\r\n return;\r\n }\r\n __loly_hydrated = true;\r\n\r\n console.log(\"[loly:runtime] bootstrapClient START\");\r\n\r\n (async function bootstrap() {\r\n const container = document.getElementById(APP_CONTAINER_ID);\r\n const initialData = getWindowData();\r\n\r\n console.log(\"[loly:runtime] bootstrap starting\", {\r\n hasContainer: !!container,\r\n hasInitialData: !!initialData,\r\n containerId: APP_CONTAINER_ID,\r\n });\r\n\r\n if (!container) {\r\n console.error(\r\n `[loly:runtime] Container #${APP_CONTAINER_ID} not found.`\r\n );\r\n return;\r\n }\r\n\r\n const initialUrl = window.location.pathname + window.location.search;\r\n console.log(\"[loly:runtime] Loading initial route\", { initialUrl });\r\n\r\n try {\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 console.log(\"[loly:runtime] Initial route loaded\", {\r\n url: initialState.url,\r\n hasRoute: !!initialState.route,\r\n hasComponents: !!initialState.components,\r\n });\r\n\r\n if (initialData?.metadata) {\r\n applyMetadata(initialData.metadata);\r\n }\r\n\r\n console.log(\"[loly:runtime] Hydrating React app\");\r\n\r\n // 🔥 React 18 hydration seguro — solo se ejecuta UNA vez\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\r\n console.log(\"[loly:runtime] Hydrated successfully\");\r\n } catch (error) {\r\n console.error(\"[loly:runtime] Error during hydration:\", error);\r\n\r\n // fallback seguro\r\n window.location.reload();\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 APP_CONTAINER_ID = \"__app\";\r\n\r\n","import { WINDOW_DATA_KEY } from \"./constants\";\r\nimport type { InitialData } from \"./types\";\r\n\r\nexport function getWindowData(): InitialData | null {\r\n return ((window as any)[WINDOW_DATA_KEY] as InitialData | undefined) ?? null;\r\n}\r\n\r\nexport function setWindowData(data: InitialData): void {\r\n (window as any)[WINDOW_DATA_KEY] = data;\r\n \r\n // Dispatch event for components to listen to (e.g., usePageProps, 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 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","export function applyMetadata(\r\n md?: { title?: string; description?: string } | null\r\n) {\r\n if (!md) return;\r\n\r\n if (md.title) {\r\n document.title = md.title;\r\n }\r\n\r\n if (md.description) {\r\n let meta = document.querySelector(\r\n 'meta[name=\"description\"]'\r\n ) as HTMLMetaElement | null;\r\n\r\n if (!meta) {\r\n meta = document.createElement(\"meta\");\r\n meta.name = \"description\";\r\n document.head.appendChild(meta);\r\n }\r\n\r\n meta.content = md.description;\r\n }\r\n}\r\n\r\n","import { useEffect, useState, useRef } from \"react\";\r\nimport { RouterView } from \"./RouterView\";\r\nimport {\r\n navigate,\r\n createClickHandler,\r\n createPopStateHandler,\r\n type NavigationHandlers,\r\n} from \"./navigation\";\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 console.log(\"[loly:AppShell] Component rendering\", {\r\n url: initialState.url,\r\n hasRoute: !!initialState.route,\r\n });\r\n\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 // Mantener handlersRef actualizado\r\n useEffect(() => {\r\n console.log(\"[loly:AppShell] Updating handlersRef\", {\r\n routesCount: routes.length,\r\n hasNotFound: !!notFoundRoute,\r\n hasError: !!errorRoute,\r\n });\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 useEffect(() => {\r\n const effectId = Math.random().toString(36).substring(7);\r\n console.log(\"[loly:AppShell] Setting up event listeners\", { effectId });\r\n \r\n // Flag para evitar múltiples listeners (por si React Strict Mode ejecuta dos veces)\r\n let isMounted = true;\r\n let listenerCount = 0;\r\n\r\n async function handleNavigate(\r\n nextUrl: string,\r\n options?: { revalidate?: boolean }\r\n ) {\r\n if (!isMounted) {\r\n console.warn(\"[loly:AppShell] navigate called but component is unmounted\");\r\n return;\r\n }\r\n console.log(\"[loly:AppShell] Navigating to\", nextUrl, options);\r\n await navigate(nextUrl, handlersRef.current, options);\r\n }\r\n\r\n const handleClick = createClickHandler(handleNavigate);\r\n const handlePopState = createPopStateHandler(handleNavigate);\r\n\r\n // Usar capture: false (burbujeo) para que los eventos del input se manejen primero\r\n window.addEventListener(\"click\", handleClick, false);\r\n window.addEventListener(\"popstate\", handlePopState, false);\r\n listenerCount = 2;\r\n \r\n console.log(\"[loly:AppShell] Event listeners added\", {\r\n clickListener: true,\r\n popStateListener: true,\r\n totalListeners: listenerCount,\r\n });\r\n\r\n return () => {\r\n console.log(\"[loly:AppShell] Cleaning up event listeners\", {\r\n effectId,\r\n wasMounted: isMounted,\r\n listenersToRemove: listenerCount,\r\n });\r\n isMounted = false;\r\n window.removeEventListener(\"click\", handleClick, false);\r\n window.removeEventListener(\"popstate\", handlePopState, false);\r\n };\r\n }, []); // Solo ejecutar una vez al montar\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 <RouterView key={routeKey} state={state} />;\r\n}\r\n\r\n","import type { RouteViewState } from \"./types\";\r\n\r\nexport function RouterView({ state }: { state: RouteViewState }) {\r\n console.log(\"[loly:RouterView] Rendering\", {\r\n url: state.url,\r\n hasRoute: !!state.route,\r\n hasComponents: !!state.components,\r\n });\r\n\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 console.log(\"[loly:RouterView] Creating page element\", {\r\n hasPage: !!Page,\r\n layoutsCount: layouts.length,\r\n paramsKeys: Object.keys(params),\r\n });\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","type RouteData = {\n ok: boolean;\n status: number;\n json: any;\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(url: string): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const res = await fetch(dataUrl, {\n headers: {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n },\n });\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): 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\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 */\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 const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n revalidatePath(pathname);\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 (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: freshData.json.props || currentData.props || {},\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}\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 const promise = fetchRouteDataOnce(url)\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 if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry) {\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 entry.promise;\n }\n }\n\n // No entry in cache, fetch it\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n return promise;\n}\n","import { getRouteData } from \"../../react/cache/index\";\r\nimport { matchRouteClient } from \"./route-matcher\";\r\nimport { applyMetadata } from \"./metadata\";\r\nimport { setWindowData, getCurrentTheme } from \"./window-data\";\r\nimport type {\r\n ClientRouteLoaded,\r\n RouteViewState,\r\n InitialData,\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: any,\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 const errorProps = {\r\n ...(json.props || {\r\n error: json.message || \"An error occurred\",\r\n }),\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 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(\r\n \"[client] Error loading error route components:\",\r\n loadError\r\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: any,\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 const notFoundProps = {\r\n ...(json.props ?? {}),\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 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: any,\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 // Include theme in props so layouts receive it during SPA navigation\r\n const newProps = {\r\n ...(json.props ?? {}),\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: newProps,\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 const components = await matched.route.load();\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: newProps,\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 console.log(\"[client] Error detected in response:\", json);\r\n\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 && (json as any).redirect) {\r\n window.location.href = (json as any).redirect.destination;\r\n return;\r\n }\r\n window.location.href = nextUrl;\r\n return;\r\n }\r\n\r\n // Redirección vía JSON\r\n if (json.redirect) {\r\n window.location.href = json.redirect.destination;\r\n return;\r\n }\r\n\r\n // Manejo de notFound\r\n if (json.notFound) {\r\n await handleNotFoundRoute(nextUrl, json, notFoundRoute, setState);\r\n return;\r\n }\r\n\r\n // Ruta normal\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\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 const target = ev.target as HTMLElement | null;\r\n const tagName = target?.tagName.toLowerCase() || \"unknown\";\r\n \r\n console.log(\"[loly:click] Click event received\", {\r\n type: ev.type,\r\n tagName,\r\n target: target?.tagName,\r\n defaultPrevented: ev.defaultPrevented,\r\n button: ev.button,\r\n clientX: ev.clientX,\r\n clientY: ev.clientY,\r\n });\r\n\r\n try {\r\n // Salir temprano si el evento ya fue prevenido\r\n if (ev.defaultPrevented) {\r\n console.log(\"[loly:click] Event already prevented, skipping\");\r\n return;\r\n }\r\n \r\n // Verificar que sea un evento de mouse real (no sintético o de teclado)\r\n if (ev.type !== \"click\") {\r\n console.log(\"[loly:click] Not a click event, skipping\", { type: ev.type });\r\n return;\r\n }\r\n if (ev.button !== 0) {\r\n console.log(\"[loly:click] Not left button, skipping\", { button: ev.button });\r\n return;\r\n }\r\n if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {\r\n console.log(\"[loly:click] Modifier keys pressed, skipping\");\r\n return;\r\n }\r\n \r\n // Verificar que el evento tenga coordenadas válidas (eventos de mouse reales las tienen)\r\n if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {\r\n // Podría ser un evento sintético, ser más cauteloso\r\n if (target) {\r\n const tagName = target.tagName.toLowerCase();\r\n if (tagName === \"input\" || tagName === \"textarea\" || tagName === \"button\" || tagName === \"select\") {\r\n console.log(\"[loly:click] Synthetic event on interactive element, skipping\", { tagName });\r\n return; // Es un input, no procesar eventos sintéticos\r\n }\r\n }\r\n }\r\n\r\n if (!target) {\r\n console.log(\"[loly:click] No target, skipping\");\r\n return;\r\n }\r\n\r\n // Verificar PRIMERO si el target es un elemento interactivo (más rápido)\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 console.log(\"[loly:click] Target is interactive element, skipping\", { tagName });\r\n return; // Es un elemento interactivo, no procesar\r\n }\r\n\r\n // Verificar si está dentro de un elemento interactivo usando closest (más eficiente que composedPath)\r\n const interactiveParent = target.closest(\"input, textarea, button, select, [contenteditable], label\");\r\n if (interactiveParent) {\r\n // Si el parent es un label, verificar si tiene un control asociado\r\n if (interactiveParent.tagName.toLowerCase() === \"label\") {\r\n const label = interactiveParent as HTMLLabelElement;\r\n if (label.control) {\r\n console.log(\"[loly:click] Inside label with control, skipping\");\r\n return; // El label tiene un control asociado (input, etc)\r\n }\r\n } else {\r\n console.log(\"[loly:click] Inside interactive parent, skipping\", {\r\n parentTag: interactiveParent.tagName.toLowerCase(),\r\n });\r\n return; // Está dentro de un elemento interactivo\r\n }\r\n }\r\n\r\n // Solo buscar anchor si no es un elemento interactivo\r\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\r\n if (!anchor) {\r\n console.log(\"[loly:click] No anchor found, skipping\");\r\n return;\r\n }\r\n \r\n console.log(\"[loly:click] Anchor found, processing navigation\", {\r\n href: anchor.getAttribute(\"href\"),\r\n });\r\n\r\n const href = anchor.getAttribute(\"href\");\r\n if (!href) {\r\n console.log(\"[loly:click] No href attribute, skipping\");\r\n return;\r\n }\r\n if (href.startsWith(\"#\")) {\r\n console.log(\"[loly:click] Hash link, skipping\");\r\n return;\r\n }\r\n\r\n const url = new URL(href, window.location.href);\r\n if (url.origin !== window.location.origin) {\r\n console.log(\"[loly:click] External link, skipping\", { origin: url.origin });\r\n return;\r\n }\r\n if (anchor.target && anchor.target !== \"_self\") {\r\n console.log(\"[loly:click] Link has target, skipping\", { target: anchor.target });\r\n return;\r\n }\r\n\r\n ev.preventDefault();\r\n console.log(\"[loly:click] Prevented default, navigating\");\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) {\r\n console.log(\"[loly:click] Same URL, skipping\", { nextUrl });\r\n return;\r\n }\r\n\r\n // Detectar si el link tiene data-revalidate para forzar revalidación\r\n const shouldRevalidate =\r\n anchor.hasAttribute(\"data-revalidate\") &&\r\n anchor.getAttribute(\"data-revalidate\") !== \"false\";\r\n\r\n console.log(\"[loly:click] Pushing state and navigating\", {\r\n nextUrl,\r\n currentUrl,\r\n shouldRevalidate,\r\n });\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(\"[loly:click] 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"],"mappings":"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","names":["navigate","tagName","import_jsx_runtime","import_jsx_runtime"]}
@@ -1,5 +1,47 @@
1
- import { R as RouteViewState, C as ClientRouteLoaded } from './bootstrap-BiCQmSkx.mjs';
2
- export { a as ClientLoadedComponents, b as ClientRouteMatch, I as InitialData, c as bootstrapClient } from './bootstrap-BiCQmSkx.mjs';
1
+ declare const WINDOW_DATA_KEY = "__FW_DATA__";
2
+
3
+ type InitialData = {
4
+ pathname: string;
5
+ params: Record<string, string>;
6
+ props: Record<string, any>;
7
+ metadata?: {
8
+ title?: string;
9
+ description?: string;
10
+ } | null;
11
+ notFound?: boolean;
12
+ error?: boolean;
13
+ theme?: string;
14
+ };
15
+ declare global {
16
+ interface Window {
17
+ [WINDOW_DATA_KEY]?: InitialData;
18
+ }
19
+ }
20
+ type ClientLoadedComponents = {
21
+ Page: React.ComponentType<any>;
22
+ layouts: React.ComponentType<any>[];
23
+ };
24
+ type ClientRouteLoaded = {
25
+ pattern: string;
26
+ paramNames: string[];
27
+ load: () => Promise<ClientLoadedComponents>;
28
+ };
29
+ type ClientRouteMatch = {
30
+ route: ClientRouteLoaded;
31
+ params: Record<string, string>;
32
+ };
33
+ type RouteViewState = {
34
+ url: string;
35
+ route: ClientRouteLoaded | null;
36
+ params: Record<string, string>;
37
+ components: ClientLoadedComponents | null;
38
+ props: Record<string, any>;
39
+ };
40
+
41
+ /**
42
+ * Bootstraps the client-side application.
43
+ */
44
+ declare function bootstrapClient(routes: ClientRouteLoaded[], notFoundRoute: ClientRouteLoaded | null, errorRoute?: ClientRouteLoaded | null): void;
3
45
 
4
46
  interface AppShellProps {
5
47
  initialState: RouteViewState;
@@ -8,4 +50,4 @@ interface AppShellProps {
8
50
  errorRoute: ClientRouteLoaded | null;
9
51
  }
10
52
 
11
- export { type AppShellProps, ClientRouteLoaded, RouteViewState };
53
+ export { type AppShellProps, type ClientLoadedComponents, type ClientRouteLoaded, type ClientRouteMatch, type InitialData, type RouteViewState, bootstrapClient };