@lolyjs/core 0.1.0-alpha.9 → 0.2.0-alpha.0

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/index.cjs CHANGED
@@ -1407,24 +1407,69 @@ function createClientConfig(projectRoot, mode) {
1407
1407
  var import_path15 = __toESM(require("path"));
1408
1408
  var import_fs12 = __toESM(require("fs"));
1409
1409
  init_globals();
1410
- function startClientBundler(projectRoot) {
1411
- const { config, outDir } = createClientConfig(projectRoot, "production");
1410
+ function startClientBundler(projectRoot, mode = "development") {
1411
+ const { config, outDir } = createClientConfig(projectRoot, mode);
1412
1412
  copyStaticAssets(projectRoot, outDir);
1413
1413
  const compiler = (0, import_core2.rspack)(config);
1414
+ let isBuilding = false;
1415
+ let buildResolve = null;
1416
+ let buildPromise = null;
1417
+ let lastBuildTime = Date.now();
1418
+ compiler.hooks.compile.tap("HotReload", () => {
1419
+ isBuilding = true;
1420
+ buildPromise = new Promise((resolve3) => {
1421
+ buildResolve = resolve3;
1422
+ });
1423
+ });
1414
1424
  compiler.watch({}, (err, stats) => {
1415
1425
  if (err) {
1416
1426
  console.error("[framework][client] Rspack error:", err);
1427
+ isBuilding = false;
1428
+ lastBuildTime = Date.now();
1429
+ if (buildResolve) {
1430
+ buildResolve();
1431
+ buildResolve = null;
1432
+ buildPromise = null;
1433
+ }
1434
+ return;
1435
+ }
1436
+ if (!stats) {
1437
+ isBuilding = false;
1438
+ lastBuildTime = Date.now();
1417
1439
  return;
1418
1440
  }
1419
- if (!stats) return;
1420
1441
  if (stats.hasErrors()) {
1421
1442
  console.error(
1422
1443
  "[framework][client] Build with errors:\n",
1423
1444
  stats.toString("errors-only")
1424
1445
  );
1446
+ } else {
1447
+ console.log("[framework][client] \u2713 Client bundle rebuilt successfully");
1448
+ }
1449
+ isBuilding = false;
1450
+ lastBuildTime = Date.now();
1451
+ if (buildResolve) {
1452
+ buildResolve();
1453
+ buildResolve = null;
1454
+ buildPromise = null;
1425
1455
  }
1426
1456
  });
1427
- return { outDir };
1457
+ return {
1458
+ outDir,
1459
+ waitForBuild: async () => {
1460
+ if (isBuilding && buildPromise) {
1461
+ await buildPromise;
1462
+ await new Promise((resolve3) => setTimeout(resolve3, 100));
1463
+ return;
1464
+ }
1465
+ const timeSinceLastBuild = Date.now() - lastBuildTime;
1466
+ if (timeSinceLastBuild < 500) {
1467
+ await new Promise((resolve3) => setTimeout(resolve3, 200));
1468
+ return;
1469
+ }
1470
+ return Promise.resolve();
1471
+ }
1472
+ };
1428
1473
  }
1429
1474
  function buildClientBundle(projectRoot) {
1430
1475
  const { config, outDir } = createClientConfig(projectRoot, "production");
@@ -3155,7 +3200,9 @@ init_globals();
3155
3200
  function setupHotReload({
3156
3201
  app,
3157
3202
  appDir,
3158
- route = "/__fw/hot"
3203
+ route = "/__fw/hot",
3204
+ waitForBuild,
3205
+ onFileChange
3159
3206
  }) {
3160
3207
  const clients = /* @__PURE__ */ new Set();
3161
3208
  app.get(route, (req, res) => {
@@ -3176,9 +3223,25 @@ data: connected
3176
3223
  ignoreInitial: true,
3177
3224
  ignored: ["**/node_modules/**", `**/${BUILD_FOLDER_NAME}/**`, "**/.git/**"]
3178
3225
  });
3179
- function broadcastReload(reason, filePath) {
3226
+ async function broadcastReload(reason, filePath) {
3180
3227
  const rel = import_path16.default.relative(appDir, filePath);
3181
3228
  console.log(`[hot-reload] ${reason}: ${rel}`);
3229
+ if (onFileChange) {
3230
+ try {
3231
+ await onFileChange(filePath);
3232
+ } catch (error) {
3233
+ console.warn("[hot-reload] Error in onFileChange callback:", error);
3234
+ }
3235
+ }
3236
+ if (waitForBuild) {
3237
+ try {
3238
+ console.log("[hot-reload] Waiting for client bundle to finish...");
3239
+ await waitForBuild();
3240
+ console.log("[hot-reload] Client bundle ready, sending reload event");
3241
+ } catch (error) {
3242
+ console.warn("[hot-reload] Error waiting for build:", error);
3243
+ }
3244
+ }
3182
3245
  for (const res of clients) {
3183
3246
  res.write(`event: message
3184
3247
  data: reload:${rel}
@@ -3317,14 +3380,29 @@ function setupServer(app, options) {
3317
3380
  };
3318
3381
  };
3319
3382
  var getRoutes = getRoutes2;
3320
- setupHotReload({ app, appDir });
3383
+ const { outDir, waitForBuild } = startClientBundler(projectRoot, "development");
3384
+ const onFileChange = async (filePath) => {
3385
+ const rel = import_path19.default.relative(appDir, filePath);
3386
+ const isPageFile = filePath.includes("page.tsx") || filePath.includes("page.ts") || filePath.includes("layout.tsx") || filePath.includes("layout.ts") || filePath.includes("_not-found") || filePath.includes("_error");
3387
+ const isTsFile = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
3388
+ if (isTsFile) {
3389
+ clearAppRequireCache(appDir);
3390
+ console.log(`[hot-reload] Cleared require cache for: ${rel}`);
3391
+ }
3392
+ if (isPageFile) {
3393
+ const loader = new FilesystemRouteLoader(appDir);
3394
+ const newRoutes = loader.loadRoutes();
3395
+ writeClientRoutesManifest(newRoutes, projectRoot);
3396
+ console.log("[hot-reload] Client routes manifest reloaded");
3397
+ }
3398
+ };
3399
+ setupHotReload({ app, appDir, waitForBuild, onFileChange });
3400
+ app.use("/static", import_express.default.static(outDir));
3321
3401
  const routes = routeLoader.loadRoutes();
3322
3402
  const wssRoutes = routeLoader.loadWssRoutes();
3323
3403
  const notFoundPage = routeLoader.loadNotFoundRoute();
3324
3404
  const errorPage = routeLoader.loadErrorRoute();
3325
3405
  writeClientRoutesManifest(routes, projectRoot);
3326
- const { outDir } = startClientBundler(projectRoot);
3327
- app.use("/static", import_express.default.static(outDir));
3328
3406
  return {
3329
3407
  routes,
3330
3408
  wssRoutes,
@@ -4022,7 +4100,7 @@ async function handlePageRequest(options) {
4022
4100
  const { errorPage, req, res, routeChunks, theme, projectRoot } = options;
4023
4101
  const reqLogger = getRequestLogger(req);
4024
4102
  if (errorPage) {
4025
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot);
4103
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env);
4026
4104
  } else {
4027
4105
  reqLogger.error("Unhandled error in page request", error, {
4028
4106
  urlPath: options.urlPath,
@@ -4050,9 +4128,9 @@ async function handlePageRequestInternal(options) {
4050
4128
  theme,
4051
4129
  projectRoot
4052
4130
  } = options;
4053
- const clientJsPath = projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
4054
- const clientCssPath = projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
4055
- const assetManifest = projectRoot ? loadAssetManifest(projectRoot) : null;
4131
+ const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
4132
+ const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
4133
+ const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
4056
4134
  const isDataReq = isDataRequest(req);
4057
4135
  if (env === "prod" && ssgOutDir) {
4058
4136
  if (isDataReq) {
@@ -4108,7 +4186,7 @@ async function handlePageRequestInternal(options) {
4108
4186
  const reqLogger = getRequestLogger(req);
4109
4187
  reqLogger.error("SSR shell error", err, { route: "not-found" });
4110
4188
  if (!res.headersSent && errorPage) {
4111
- renderErrorPageWithStream(errorPage, req, res, err, routeChunks);
4189
+ renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
4112
4190
  } else if (!res.headersSent) {
4113
4191
  res.statusCode = 500;
4114
4192
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -4155,7 +4233,7 @@ async function handlePageRequestInternal(options) {
4155
4233
  return;
4156
4234
  } else {
4157
4235
  if (errorPage) {
4158
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot);
4236
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env);
4159
4237
  return;
4160
4238
  } else {
4161
4239
  throw error;
@@ -4217,7 +4295,7 @@ async function handlePageRequestInternal(options) {
4217
4295
  const reqLogger = getRequestLogger(req);
4218
4296
  reqLogger.error("SSR shell error", err, { route: matched?.route?.pattern || "unknown" });
4219
4297
  if (!res.headersSent && errorPage) {
4220
- renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot);
4298
+ renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
4221
4299
  } else if (!res.headersSent) {
4222
4300
  res.statusCode = 500;
4223
4301
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -4235,7 +4313,7 @@ async function handlePageRequestInternal(options) {
4235
4313
  abort();
4236
4314
  });
4237
4315
  }
4238
- async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot) {
4316
+ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev") {
4239
4317
  try {
4240
4318
  const isDataReq = isDataRequest(req);
4241
4319
  const ctx = {
@@ -4264,9 +4342,9 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
4264
4342
  return;
4265
4343
  }
4266
4344
  const appTree = buildAppTree(errorPage, { error: String(error) }, initialData.props);
4267
- const clientJsPath = projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
4268
- const clientCssPath = projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
4269
- const assetManifest = projectRoot ? loadAssetManifest(projectRoot) : null;
4345
+ const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
4346
+ const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
4347
+ const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
4270
4348
  const chunkName = routeChunks[ERROR_CHUNK_KEY];
4271
4349
  let chunkHref = null;
4272
4350
  if (chunkName != null) {
@@ -5141,11 +5219,6 @@ var import_react2 = require("react");
5141
5219
  // modules/runtime/client/RouterView.tsx
5142
5220
  var import_jsx_runtime = require("react/jsx-runtime");
5143
5221
  function RouterView({ state }) {
5144
- console.log("[loly:RouterView] Rendering", {
5145
- url: state.url,
5146
- hasRoute: !!state.route,
5147
- hasComponents: !!state.components
5148
- });
5149
5222
  if (!state.route) {
5150
5223
  if (state.components === null) {
5151
5224
  return null;
@@ -5157,11 +5230,6 @@ function RouterView({ state }) {
5157
5230
  }
5158
5231
  const { Page, layouts } = state.components;
5159
5232
  const { params, props } = state;
5160
- console.log("[loly:RouterView] Creating page element", {
5161
- hasPage: !!Page,
5162
- layoutsCount: layouts.length,
5163
- paramsKeys: Object.keys(params)
5164
- });
5165
5233
  let element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Page, { params, ...props });
5166
5234
  const layoutChain = layouts.slice().reverse();
5167
5235
  for (const Layout of layoutChain) {
@@ -5467,7 +5535,6 @@ async function navigate(nextUrl, handlers, options) {
5467
5535
  revalidate: options?.revalidate
5468
5536
  });
5469
5537
  if (json && json.error) {
5470
- console.log("[client] Error detected in response:", json);
5471
5538
  if (errorRoute) {
5472
5539
  const handled = await handleErrorRoute(
5473
5540
  nextUrl,
@@ -5509,50 +5576,23 @@ async function navigate(nextUrl, handlers, options) {
5509
5576
  }
5510
5577
  function createClickHandler(navigate2) {
5511
5578
  return function handleClick(ev) {
5512
- const target = ev.target;
5513
- const tagName = target?.tagName.toLowerCase() || "unknown";
5514
- console.log("[loly:click] Click event received", {
5515
- type: ev.type,
5516
- tagName,
5517
- target: target?.tagName,
5518
- defaultPrevented: ev.defaultPrevented,
5519
- button: ev.button,
5520
- clientX: ev.clientX,
5521
- clientY: ev.clientY
5522
- });
5523
5579
  try {
5524
- if (ev.defaultPrevented) {
5525
- console.log("[loly:click] Event already prevented, skipping");
5526
- return;
5527
- }
5528
- if (ev.type !== "click") {
5529
- console.log("[loly:click] Not a click event, skipping", { type: ev.type });
5530
- return;
5531
- }
5532
- if (ev.button !== 0) {
5533
- console.log("[loly:click] Not left button, skipping", { button: ev.button });
5534
- return;
5535
- }
5536
- if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {
5537
- console.log("[loly:click] Modifier keys pressed, skipping");
5538
- return;
5539
- }
5580
+ if (ev.defaultPrevented) return;
5581
+ if (ev.type !== "click") return;
5582
+ if (ev.button !== 0) return;
5583
+ if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
5584
+ const target = ev.target;
5540
5585
  if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {
5541
5586
  if (target) {
5542
- const tagName3 = target.tagName.toLowerCase();
5543
- if (tagName3 === "input" || tagName3 === "textarea" || tagName3 === "button" || tagName3 === "select") {
5544
- console.log("[loly:click] Synthetic event on interactive element, skipping", { tagName: tagName3 });
5587
+ const tagName2 = target.tagName.toLowerCase();
5588
+ if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select") {
5545
5589
  return;
5546
5590
  }
5547
5591
  }
5548
5592
  }
5549
- if (!target) {
5550
- console.log("[loly:click] No target, skipping");
5551
- return;
5552
- }
5553
- const tagName2 = target.tagName.toLowerCase();
5554
- if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
5555
- console.log("[loly:click] Target is interactive element, skipping", { tagName: tagName2 });
5593
+ if (!target) return;
5594
+ const tagName = target.tagName.toLowerCase();
5595
+ if (tagName === "input" || tagName === "textarea" || tagName === "button" || tagName === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
5556
5596
  return;
5557
5597
  }
5558
5598
  const interactiveParent = target.closest("input, textarea, button, select, [contenteditable], label");
@@ -5560,60 +5600,29 @@ function createClickHandler(navigate2) {
5560
5600
  if (interactiveParent.tagName.toLowerCase() === "label") {
5561
5601
  const label = interactiveParent;
5562
5602
  if (label.control) {
5563
- console.log("[loly:click] Inside label with control, skipping");
5564
5603
  return;
5565
5604
  }
5566
5605
  } else {
5567
- console.log("[loly:click] Inside interactive parent, skipping", {
5568
- parentTag: interactiveParent.tagName.toLowerCase()
5569
- });
5570
5606
  return;
5571
5607
  }
5572
5608
  }
5573
5609
  const anchor = target.closest("a[href]");
5574
- if (!anchor) {
5575
- console.log("[loly:click] No anchor found, skipping");
5576
- return;
5577
- }
5578
- console.log("[loly:click] Anchor found, processing navigation", {
5579
- href: anchor.getAttribute("href")
5580
- });
5610
+ if (!anchor) return;
5581
5611
  const href = anchor.getAttribute("href");
5582
- if (!href) {
5583
- console.log("[loly:click] No href attribute, skipping");
5584
- return;
5585
- }
5586
- if (href.startsWith("#")) {
5587
- console.log("[loly:click] Hash link, skipping");
5588
- return;
5589
- }
5612
+ if (!href) return;
5613
+ if (href.startsWith("#")) return;
5590
5614
  const url = new URL(href, window.location.href);
5591
- if (url.origin !== window.location.origin) {
5592
- console.log("[loly:click] External link, skipping", { origin: url.origin });
5593
- return;
5594
- }
5595
- if (anchor.target && anchor.target !== "_self") {
5596
- console.log("[loly:click] Link has target, skipping", { target: anchor.target });
5597
- return;
5598
- }
5615
+ if (url.origin !== window.location.origin) return;
5616
+ if (anchor.target && anchor.target !== "_self") return;
5599
5617
  ev.preventDefault();
5600
- console.log("[loly:click] Prevented default, navigating");
5601
5618
  const nextUrl = url.pathname + url.search;
5602
5619
  const currentUrl = window.location.pathname + window.location.search;
5603
- if (nextUrl === currentUrl) {
5604
- console.log("[loly:click] Same URL, skipping", { nextUrl });
5605
- return;
5606
- }
5620
+ if (nextUrl === currentUrl) return;
5607
5621
  const shouldRevalidate = anchor.hasAttribute("data-revalidate") && anchor.getAttribute("data-revalidate") !== "false";
5608
- console.log("[loly:click] Pushing state and navigating", {
5609
- nextUrl,
5610
- currentUrl,
5611
- shouldRevalidate
5612
- });
5613
5622
  window.history.pushState({}, "", nextUrl);
5614
5623
  navigate2(nextUrl, shouldRevalidate ? { revalidate: true } : void 0);
5615
5624
  } catch (error) {
5616
- console.error("[loly:click] Error in click handler:", error);
5625
+ console.error("[navigation] Error in click handler:", error);
5617
5626
  }
5618
5627
  };
5619
5628
  }
@@ -5632,10 +5641,6 @@ function AppShell({
5632
5641
  notFoundRoute,
5633
5642
  errorRoute
5634
5643
  }) {
5635
- console.log("[loly:AppShell] Component rendering", {
5636
- url: initialState.url,
5637
- hasRoute: !!initialState.route
5638
- });
5639
5644
  const [state, setState] = (0, import_react2.useState)(initialState);
5640
5645
  const handlersRef = (0, import_react2.useRef)({
5641
5646
  setState,
@@ -5644,11 +5649,6 @@ function AppShell({
5644
5649
  errorRoute
5645
5650
  });
5646
5651
  (0, import_react2.useEffect)(() => {
5647
- console.log("[loly:AppShell] Updating handlersRef", {
5648
- routesCount: routes.length,
5649
- hasNotFound: !!notFoundRoute,
5650
- hasError: !!errorRoute
5651
- });
5652
5652
  handlersRef.current = {
5653
5653
  setState,
5654
5654
  routes,
@@ -5657,34 +5657,16 @@ function AppShell({
5657
5657
  };
5658
5658
  }, [routes, notFoundRoute, errorRoute]);
5659
5659
  (0, import_react2.useEffect)(() => {
5660
- const effectId = Math.random().toString(36).substring(7);
5661
- console.log("[loly:AppShell] Setting up event listeners", { effectId });
5662
5660
  let isMounted = true;
5663
- let listenerCount = 0;
5664
5661
  async function handleNavigate(nextUrl, options) {
5665
- if (!isMounted) {
5666
- console.warn("[loly:AppShell] navigate called but component is unmounted");
5667
- return;
5668
- }
5669
- console.log("[loly:AppShell] Navigating to", nextUrl, options);
5662
+ if (!isMounted) return;
5670
5663
  await navigate(nextUrl, handlersRef.current, options);
5671
5664
  }
5672
5665
  const handleClick = createClickHandler(handleNavigate);
5673
5666
  const handlePopState = createPopStateHandler(handleNavigate);
5674
5667
  window.addEventListener("click", handleClick, false);
5675
5668
  window.addEventListener("popstate", handlePopState, false);
5676
- listenerCount = 2;
5677
- console.log("[loly:AppShell] Event listeners added", {
5678
- clickListener: true,
5679
- popStateListener: true,
5680
- totalListeners: listenerCount
5681
- });
5682
5669
  return () => {
5683
- console.log("[loly:AppShell] Cleaning up event listeners", {
5684
- effectId,
5685
- wasMounted: isMounted,
5686
- listenersToRemove: listenerCount
5687
- });
5688
5670
  isMounted = false;
5689
5671
  window.removeEventListener("click", handleClick, false);
5690
5672
  window.removeEventListener("popstate", handlePopState, false);
@@ -5699,7 +5681,6 @@ function AppShell({
5699
5681
 
5700
5682
  // modules/runtime/client/bootstrap.tsx
5701
5683
  var import_jsx_runtime3 = require("react/jsx-runtime");
5702
- var __loly_hydrated = false;
5703
5684
  async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute, errorRoute) {
5704
5685
  const isInitialNotFound = initialData?.notFound === true;
5705
5686
  const isInitialError = initialData?.error === true;
@@ -5726,7 +5707,7 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
5726
5707
  initialComponents = await notFoundRoute.load();
5727
5708
  } else {
5728
5709
  console.warn(
5729
- `[client] No route match found for ${initialUrl}. Routes:`,
5710
+ `[client] No route match found for ${initialUrl}. Available routes:`,
5730
5711
  routes.map((r) => r.pattern)
5731
5712
  );
5732
5713
  }
@@ -5739,29 +5720,57 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
5739
5720
  props: initialData?.props ?? {}
5740
5721
  };
5741
5722
  }
5742
- function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5743
- if (__loly_hydrated) {
5744
- console.warn("[loly:runtime] bootstrapClient SKIPPED (already hydrated)");
5745
- return;
5723
+ function setupHotReload2() {
5724
+ try {
5725
+ console.log("[hot-reload] Attempting to connect to /__fw/hot...");
5726
+ const eventSource = new EventSource("/__fw/hot");
5727
+ let reloadTimeout = null;
5728
+ eventSource.addEventListener("message", (event) => {
5729
+ const data = event.data;
5730
+ if (data && data.startsWith("reload:")) {
5731
+ const filePath = data.slice(7);
5732
+ console.log(`[hot-reload] File changed: ${filePath}`);
5733
+ if (reloadTimeout) {
5734
+ clearTimeout(reloadTimeout);
5735
+ }
5736
+ reloadTimeout = setTimeout(() => {
5737
+ console.log("[hot-reload] Reloading page...");
5738
+ window.location.reload();
5739
+ }, 500);
5740
+ }
5741
+ });
5742
+ eventSource.addEventListener("ping", () => {
5743
+ console.log("[hot-reload] \u2713 Connected to hot reload server");
5744
+ });
5745
+ eventSource.onopen = () => {
5746
+ console.log("[hot-reload] \u2713 SSE connection opened");
5747
+ };
5748
+ eventSource.onerror = (error) => {
5749
+ const states = ["CONNECTING", "OPEN", "CLOSED"];
5750
+ const state = states[eventSource.readyState] || "UNKNOWN";
5751
+ if (eventSource.readyState === EventSource.CONNECTING) {
5752
+ console.log("[hot-reload] Connecting...");
5753
+ } else if (eventSource.readyState === EventSource.OPEN) {
5754
+ console.warn("[hot-reload] Connection error (but connection is open):", error);
5755
+ } else {
5756
+ console.log("[hot-reload] Connection closed (readyState:", state, ")");
5757
+ }
5758
+ };
5759
+ } catch (error) {
5760
+ console.log("[hot-reload] EventSource not supported or error:", error);
5746
5761
  }
5747
- __loly_hydrated = true;
5748
- console.log("[loly:runtime] bootstrapClient START");
5762
+ }
5763
+ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5764
+ console.log("[client] Bootstrap starting, setting up hot reload...");
5765
+ setupHotReload2();
5749
5766
  (async function bootstrap() {
5750
5767
  const container = document.getElementById(APP_CONTAINER_ID2);
5751
5768
  const initialData = getWindowData();
5752
- console.log("[loly:runtime] bootstrap starting", {
5753
- hasContainer: !!container,
5754
- hasInitialData: !!initialData,
5755
- containerId: APP_CONTAINER_ID2
5756
- });
5757
5769
  if (!container) {
5758
- console.error(
5759
- `[loly:runtime] Container #${APP_CONTAINER_ID2} not found.`
5760
- );
5770
+ console.error(`Container #${APP_CONTAINER_ID2} not found for hydration`);
5761
5771
  return;
5762
5772
  }
5763
5773
  const initialUrl = window.location.pathname + window.location.search;
5764
- console.log("[loly:runtime] Loading initial route", { initialUrl });
5765
5774
  try {
5766
5775
  const initialState = await loadInitialRoute(
5767
5776
  initialUrl,
@@ -5770,15 +5779,9 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5770
5779
  notFoundRoute,
5771
5780
  errorRoute
5772
5781
  );
5773
- console.log("[loly:runtime] Initial route loaded", {
5774
- url: initialState.url,
5775
- hasRoute: !!initialState.route,
5776
- hasComponents: !!initialState.components
5777
- });
5778
5782
  if (initialData?.metadata) {
5779
5783
  applyMetadata(initialData.metadata);
5780
5784
  }
5781
- console.log("[loly:runtime] Hydrating React app");
5782
5785
  (0, import_client5.hydrateRoot)(
5783
5786
  container,
5784
5787
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -5791,9 +5794,12 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5791
5794
  }
5792
5795
  )
5793
5796
  );
5794
- console.log("[loly:runtime] Hydrated successfully");
5795
5797
  } catch (error) {
5796
- console.error("[loly:runtime] Error during hydration:", error);
5798
+ console.error(
5799
+ "[client] Error loading initial route components for",
5800
+ initialUrl,
5801
+ error
5802
+ );
5797
5803
  window.location.reload();
5798
5804
  }
5799
5805
  })();