@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/runtime.cjs CHANGED
@@ -33,8 +33,7 @@ var APP_CONTAINER_ID = "__app";
33
33
 
34
34
  // modules/runtime/client/window-data.ts
35
35
  function getWindowData() {
36
- var _a;
37
- return (_a = window[WINDOW_DATA_KEY]) != null ? _a : null;
36
+ return window[WINDOW_DATA_KEY] ?? null;
38
37
  }
39
38
  function setWindowData(data) {
40
39
  window[WINDOW_DATA_KEY] = data;
@@ -47,8 +46,7 @@ function setWindowData(data) {
47
46
  }
48
47
  }
49
48
  function getCurrentTheme() {
50
- var _a, _b;
51
- return (_b = (_a = getWindowData()) == null ? void 0 : _a.theme) != null ? _b : null;
49
+ return getWindowData()?.theme ?? null;
52
50
  }
53
51
 
54
52
  // modules/runtime/client/route-matcher.ts
@@ -116,11 +114,6 @@ var import_react = require("react");
116
114
  // modules/runtime/client/RouterView.tsx
117
115
  var import_jsx_runtime = require("react/jsx-runtime");
118
116
  function RouterView({ state }) {
119
- console.log("[loly:RouterView] Rendering", {
120
- url: state.url,
121
- hasRoute: !!state.route,
122
- hasComponents: !!state.components
123
- });
124
117
  if (!state.route) {
125
118
  if (state.components === null) {
126
119
  return null;
@@ -132,11 +125,6 @@ function RouterView({ state }) {
132
125
  }
133
126
  const { Page, layouts } = state.components;
134
127
  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
- });
140
128
  let element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Page, { params, ...props });
141
129
  const layoutChain = layouts.slice().reverse();
142
130
  for (const Layout of layoutChain) {
@@ -205,7 +193,7 @@ function evictOldest() {
205
193
  }
206
194
  function setCacheEntry(key, entry) {
207
195
  const existingEntry = dataCache.get(key);
208
- const wasFulfilled = (existingEntry == null ? void 0 : existingEntry.status) === "fulfilled";
196
+ const wasFulfilled = existingEntry?.status === "fulfilled";
209
197
  dataCache.set(key, entry);
210
198
  if (entry.status === "fulfilled") {
211
199
  if (!wasFulfilled) {
@@ -259,7 +247,7 @@ async function fetchRouteDataOnce(url) {
259
247
  }
260
248
  async function getRouteData(url, options) {
261
249
  const key = buildDataUrl(url);
262
- if (options == null ? void 0 : options.revalidate) {
250
+ if (options?.revalidate) {
263
251
  deleteCacheEntry(key);
264
252
  }
265
253
  const entry = dataCache.get(key);
@@ -286,7 +274,6 @@ async function getRouteData(url, options) {
286
274
 
287
275
  // modules/runtime/client/navigation.ts
288
276
  async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
289
- var _a;
290
277
  try {
291
278
  const components = await errorRoute.load();
292
279
  let theme = "light";
@@ -313,7 +300,7 @@ async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
313
300
  pathname: nextUrl,
314
301
  params: json.params || {},
315
302
  props: errorProps,
316
- metadata: (_a = json.metadata) != null ? _a : null,
303
+ metadata: json.metadata ?? null,
317
304
  theme,
318
305
  notFound: false,
319
306
  error: true
@@ -337,7 +324,6 @@ async function handleErrorRoute(nextUrl, json, errorRoute, setState) {
337
324
  }
338
325
  }
339
326
  async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
340
- var _a, _b;
341
327
  let theme = "light";
342
328
  if (typeof document !== "undefined") {
343
329
  const cookieMatch = document.cookie.match(/theme=([^;]+)/);
@@ -353,14 +339,14 @@ async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
353
339
  theme = json.theme;
354
340
  }
355
341
  const notFoundProps = {
356
- ...(_a = json.props) != null ? _a : {},
342
+ ...json.props ?? {},
357
343
  theme
358
344
  };
359
345
  const windowData = {
360
346
  pathname: nextUrl,
361
347
  params: {},
362
348
  props: notFoundProps,
363
- metadata: (_b = json.metadata) != null ? _b : null,
349
+ metadata: json.metadata ?? null,
364
350
  theme,
365
351
  notFound: true,
366
352
  error: false
@@ -386,8 +372,7 @@ async function handleNotFoundRoute(nextUrl, json, notFoundRoute, setState) {
386
372
  }
387
373
  }
388
374
  async function handleNormalRoute(nextUrl, json, routes, setState) {
389
- var _a, _b, _c;
390
- applyMetadata((_a = json.metadata) != null ? _a : null);
375
+ applyMetadata(json.metadata ?? null);
391
376
  let theme = "light";
392
377
  if (typeof document !== "undefined") {
393
378
  const cookieMatch = document.cookie.match(/theme=([^;]+)/);
@@ -405,7 +390,7 @@ async function handleNormalRoute(nextUrl, json, routes, setState) {
405
390
  theme = json.theme;
406
391
  }
407
392
  const newProps = {
408
- ...(_b = json.props) != null ? _b : {},
393
+ ...json.props ?? {},
409
394
  theme
410
395
  // Always include theme
411
396
  };
@@ -418,7 +403,7 @@ async function handleNormalRoute(nextUrl, json, routes, setState) {
418
403
  pathname: nextUrl,
419
404
  params: matched.params,
420
405
  props: newProps,
421
- metadata: (_c = json.metadata) != null ? _c : null,
406
+ metadata: json.metadata ?? null,
422
407
  theme,
423
408
  notFound: false,
424
409
  error: false
@@ -442,10 +427,9 @@ async function navigate(nextUrl, handlers, options) {
442
427
  const { setState, routes, notFoundRoute, errorRoute } = handlers;
443
428
  try {
444
429
  const { ok, json } = await getRouteData(nextUrl, {
445
- revalidate: options == null ? void 0 : options.revalidate
430
+ revalidate: options?.revalidate
446
431
  });
447
432
  if (json && json.error) {
448
- console.log("[client] Error detected in response:", json);
449
433
  if (errorRoute) {
450
434
  const handled = await handleErrorRoute(
451
435
  nextUrl,
@@ -487,50 +471,23 @@ async function navigate(nextUrl, handlers, options) {
487
471
  }
488
472
  function createClickHandler(navigate2) {
489
473
  return function handleClick(ev) {
490
- const target = ev.target;
491
- const tagName = (target == null ? void 0 : target.tagName.toLowerCase()) || "unknown";
492
- console.log("[loly:click] Click event received", {
493
- type: ev.type,
494
- tagName,
495
- target: target == null ? void 0 : target.tagName,
496
- defaultPrevented: ev.defaultPrevented,
497
- button: ev.button,
498
- clientX: ev.clientX,
499
- clientY: ev.clientY
500
- });
501
474
  try {
502
- if (ev.defaultPrevented) {
503
- console.log("[loly:click] Event already prevented, skipping");
504
- return;
505
- }
506
- if (ev.type !== "click") {
507
- console.log("[loly:click] Not a click event, skipping", { type: ev.type });
508
- return;
509
- }
510
- if (ev.button !== 0) {
511
- console.log("[loly:click] Not left button, skipping", { button: ev.button });
512
- return;
513
- }
514
- if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {
515
- console.log("[loly:click] Modifier keys pressed, skipping");
516
- return;
517
- }
475
+ if (ev.defaultPrevented) return;
476
+ if (ev.type !== "click") return;
477
+ if (ev.button !== 0) return;
478
+ if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
479
+ const target = ev.target;
518
480
  if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {
519
481
  if (target) {
520
- const tagName3 = target.tagName.toLowerCase();
521
- if (tagName3 === "input" || tagName3 === "textarea" || tagName3 === "button" || tagName3 === "select") {
522
- console.log("[loly:click] Synthetic event on interactive element, skipping", { tagName: tagName3 });
482
+ const tagName2 = target.tagName.toLowerCase();
483
+ if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select") {
523
484
  return;
524
485
  }
525
486
  }
526
487
  }
527
- if (!target) {
528
- console.log("[loly:click] No target, skipping");
529
- return;
530
- }
531
- const tagName2 = target.tagName.toLowerCase();
532
- if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
533
- console.log("[loly:click] Target is interactive element, skipping", { tagName: tagName2 });
488
+ if (!target) return;
489
+ const tagName = target.tagName.toLowerCase();
490
+ if (tagName === "input" || tagName === "textarea" || tagName === "button" || tagName === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
534
491
  return;
535
492
  }
536
493
  const interactiveParent = target.closest("input, textarea, button, select, [contenteditable], label");
@@ -538,60 +495,29 @@ function createClickHandler(navigate2) {
538
495
  if (interactiveParent.tagName.toLowerCase() === "label") {
539
496
  const label = interactiveParent;
540
497
  if (label.control) {
541
- console.log("[loly:click] Inside label with control, skipping");
542
498
  return;
543
499
  }
544
500
  } else {
545
- console.log("[loly:click] Inside interactive parent, skipping", {
546
- parentTag: interactiveParent.tagName.toLowerCase()
547
- });
548
501
  return;
549
502
  }
550
503
  }
551
504
  const anchor = target.closest("a[href]");
552
- if (!anchor) {
553
- console.log("[loly:click] No anchor found, skipping");
554
- return;
555
- }
556
- console.log("[loly:click] Anchor found, processing navigation", {
557
- href: anchor.getAttribute("href")
558
- });
505
+ if (!anchor) return;
559
506
  const href = anchor.getAttribute("href");
560
- if (!href) {
561
- console.log("[loly:click] No href attribute, skipping");
562
- return;
563
- }
564
- if (href.startsWith("#")) {
565
- console.log("[loly:click] Hash link, skipping");
566
- return;
567
- }
507
+ if (!href) return;
508
+ if (href.startsWith("#")) return;
568
509
  const url = new URL(href, window.location.href);
569
- if (url.origin !== window.location.origin) {
570
- console.log("[loly:click] External link, skipping", { origin: url.origin });
571
- return;
572
- }
573
- if (anchor.target && anchor.target !== "_self") {
574
- console.log("[loly:click] Link has target, skipping", { target: anchor.target });
575
- return;
576
- }
510
+ if (url.origin !== window.location.origin) return;
511
+ if (anchor.target && anchor.target !== "_self") return;
577
512
  ev.preventDefault();
578
- console.log("[loly:click] Prevented default, navigating");
579
513
  const nextUrl = url.pathname + url.search;
580
514
  const currentUrl = window.location.pathname + window.location.search;
581
- if (nextUrl === currentUrl) {
582
- console.log("[loly:click] Same URL, skipping", { nextUrl });
583
- return;
584
- }
515
+ if (nextUrl === currentUrl) return;
585
516
  const shouldRevalidate = anchor.hasAttribute("data-revalidate") && anchor.getAttribute("data-revalidate") !== "false";
586
- console.log("[loly:click] Pushing state and navigating", {
587
- nextUrl,
588
- currentUrl,
589
- shouldRevalidate
590
- });
591
517
  window.history.pushState({}, "", nextUrl);
592
518
  navigate2(nextUrl, shouldRevalidate ? { revalidate: true } : void 0);
593
519
  } catch (error) {
594
- console.error("[loly:click] Error in click handler:", error);
520
+ console.error("[navigation] Error in click handler:", error);
595
521
  }
596
522
  };
597
523
  }
@@ -610,10 +536,6 @@ function AppShell({
610
536
  notFoundRoute,
611
537
  errorRoute
612
538
  }) {
613
- console.log("[loly:AppShell] Component rendering", {
614
- url: initialState.url,
615
- hasRoute: !!initialState.route
616
- });
617
539
  const [state, setState] = (0, import_react.useState)(initialState);
618
540
  const handlersRef = (0, import_react.useRef)({
619
541
  setState,
@@ -622,11 +544,6 @@ function AppShell({
622
544
  errorRoute
623
545
  });
624
546
  (0, import_react.useEffect)(() => {
625
- console.log("[loly:AppShell] Updating handlersRef", {
626
- routesCount: routes.length,
627
- hasNotFound: !!notFoundRoute,
628
- hasError: !!errorRoute
629
- });
630
547
  handlersRef.current = {
631
548
  setState,
632
549
  routes,
@@ -635,34 +552,16 @@ function AppShell({
635
552
  };
636
553
  }, [routes, notFoundRoute, errorRoute]);
637
554
  (0, import_react.useEffect)(() => {
638
- const effectId = Math.random().toString(36).substring(7);
639
- console.log("[loly:AppShell] Setting up event listeners", { effectId });
640
555
  let isMounted = true;
641
- let listenerCount = 0;
642
556
  async function handleNavigate(nextUrl, options) {
643
- if (!isMounted) {
644
- console.warn("[loly:AppShell] navigate called but component is unmounted");
645
- return;
646
- }
647
- console.log("[loly:AppShell] Navigating to", nextUrl, options);
557
+ if (!isMounted) return;
648
558
  await navigate(nextUrl, handlersRef.current, options);
649
559
  }
650
560
  const handleClick = createClickHandler(handleNavigate);
651
561
  const handlePopState = createPopStateHandler(handleNavigate);
652
562
  window.addEventListener("click", handleClick, false);
653
563
  window.addEventListener("popstate", handlePopState, false);
654
- listenerCount = 2;
655
- console.log("[loly:AppShell] Event listeners added", {
656
- clickListener: true,
657
- popStateListener: true,
658
- totalListeners: listenerCount
659
- });
660
564
  return () => {
661
- console.log("[loly:AppShell] Cleaning up event listeners", {
662
- effectId,
663
- wasMounted: isMounted,
664
- listenersToRemove: listenerCount
665
- });
666
565
  isMounted = false;
667
566
  window.removeEventListener("click", handleClick, false);
668
567
  window.removeEventListener("popstate", handlePopState, false);
@@ -677,17 +576,15 @@ function AppShell({
677
576
 
678
577
  // modules/runtime/client/bootstrap.tsx
679
578
  var import_jsx_runtime3 = require("react/jsx-runtime");
680
- var __loly_hydrated = false;
681
579
  async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute, errorRoute) {
682
- var _a, _b;
683
- const isInitialNotFound = (initialData == null ? void 0 : initialData.notFound) === true;
684
- const isInitialError = (initialData == null ? void 0 : initialData.error) === true;
580
+ const isInitialNotFound = initialData?.notFound === true;
581
+ const isInitialError = initialData?.error === true;
685
582
  let initialRoute = null;
686
583
  let initialParams = {};
687
584
  let initialComponents = null;
688
585
  if (isInitialError && errorRoute) {
689
586
  initialRoute = errorRoute;
690
- initialParams = (_a = initialData == null ? void 0 : initialData.params) != null ? _a : {};
587
+ initialParams = initialData?.params ?? {};
691
588
  initialComponents = await errorRoute.load();
692
589
  } else if (isInitialNotFound && notFoundRoute) {
693
590
  initialRoute = notFoundRoute;
@@ -705,7 +602,7 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
705
602
  initialComponents = await notFoundRoute.load();
706
603
  } else {
707
604
  console.warn(
708
- `[client] No route match found for ${initialUrl}. Routes:`,
605
+ `[client] No route match found for ${initialUrl}. Available routes:`,
709
606
  routes.map((r) => r.pattern)
710
607
  );
711
608
  }
@@ -715,32 +612,60 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
715
612
  route: initialRoute,
716
613
  params: initialParams,
717
614
  components: initialComponents,
718
- props: (_b = initialData == null ? void 0 : initialData.props) != null ? _b : {}
615
+ props: initialData?.props ?? {}
719
616
  };
720
617
  }
721
- function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
722
- if (__loly_hydrated) {
723
- console.warn("[loly:runtime] bootstrapClient SKIPPED (already hydrated)");
724
- return;
618
+ function setupHotReload() {
619
+ try {
620
+ console.log("[hot-reload] Attempting to connect to /__fw/hot...");
621
+ const eventSource = new EventSource("/__fw/hot");
622
+ let reloadTimeout = null;
623
+ eventSource.addEventListener("message", (event) => {
624
+ const data = event.data;
625
+ if (data && data.startsWith("reload:")) {
626
+ const filePath = data.slice(7);
627
+ console.log(`[hot-reload] File changed: ${filePath}`);
628
+ if (reloadTimeout) {
629
+ clearTimeout(reloadTimeout);
630
+ }
631
+ reloadTimeout = setTimeout(() => {
632
+ console.log("[hot-reload] Reloading page...");
633
+ window.location.reload();
634
+ }, 500);
635
+ }
636
+ });
637
+ eventSource.addEventListener("ping", () => {
638
+ console.log("[hot-reload] \u2713 Connected to hot reload server");
639
+ });
640
+ eventSource.onopen = () => {
641
+ console.log("[hot-reload] \u2713 SSE connection opened");
642
+ };
643
+ eventSource.onerror = (error) => {
644
+ const states = ["CONNECTING", "OPEN", "CLOSED"];
645
+ const state = states[eventSource.readyState] || "UNKNOWN";
646
+ if (eventSource.readyState === EventSource.CONNECTING) {
647
+ console.log("[hot-reload] Connecting...");
648
+ } else if (eventSource.readyState === EventSource.OPEN) {
649
+ console.warn("[hot-reload] Connection error (but connection is open):", error);
650
+ } else {
651
+ console.log("[hot-reload] Connection closed (readyState:", state, ")");
652
+ }
653
+ };
654
+ } catch (error) {
655
+ console.log("[hot-reload] EventSource not supported or error:", error);
725
656
  }
726
- __loly_hydrated = true;
727
- console.log("[loly:runtime] bootstrapClient START");
657
+ }
658
+ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
659
+ console.log("[client] Bootstrap starting, setting up hot reload...");
660
+ setupHotReload();
728
661
  (async function bootstrap() {
729
662
  const container = document.getElementById(APP_CONTAINER_ID);
730
663
  const initialData = getWindowData();
731
- console.log("[loly:runtime] bootstrap starting", {
732
- hasContainer: !!container,
733
- hasInitialData: !!initialData,
734
- containerId: APP_CONTAINER_ID
735
- });
736
664
  if (!container) {
737
- console.error(
738
- `[loly:runtime] Container #${APP_CONTAINER_ID} not found.`
739
- );
665
+ console.error(`Container #${APP_CONTAINER_ID} not found for hydration`);
740
666
  return;
741
667
  }
742
668
  const initialUrl = window.location.pathname + window.location.search;
743
- console.log("[loly:runtime] Loading initial route", { initialUrl });
744
669
  try {
745
670
  const initialState = await loadInitialRoute(
746
671
  initialUrl,
@@ -749,15 +674,9 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
749
674
  notFoundRoute,
750
675
  errorRoute
751
676
  );
752
- console.log("[loly:runtime] Initial route loaded", {
753
- url: initialState.url,
754
- hasRoute: !!initialState.route,
755
- hasComponents: !!initialState.components
756
- });
757
- if (initialData == null ? void 0 : initialData.metadata) {
677
+ if (initialData?.metadata) {
758
678
  applyMetadata(initialData.metadata);
759
679
  }
760
- console.log("[loly:runtime] Hydrating React app");
761
680
  (0, import_client.hydrateRoot)(
762
681
  container,
763
682
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -770,11 +689,18 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
770
689
  }
771
690
  )
772
691
  );
773
- console.log("[loly:runtime] Hydrated successfully");
774
692
  } catch (error) {
775
- console.error("[loly:runtime] Error during hydration:", error);
693
+ console.error(
694
+ "[client] Error loading initial route components for",
695
+ initialUrl,
696
+ error
697
+ );
776
698
  window.location.reload();
777
699
  }
778
700
  })();
779
701
  }
702
+ // Annotate the CommonJS export names for ESM import in node:
703
+ 0 && (module.exports = {
704
+ bootstrapClient
705
+ });
780
706
  //# sourceMappingURL=runtime.cjs.map