@lolyjs/core 0.1.0-alpha.5 → 0.1.0-alpha.8

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.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import http from 'http';
2
2
  import { Request, Response } from 'express';
3
3
  import { Socket, Server } from 'socket.io';
4
- export { c as bootstrapClient } from './bootstrap-BiCQmSkx.mjs';
5
4
  import { ZodSchema, z } from 'zod';
6
5
  import * as express_rate_limit from 'express-rate-limit';
7
6
  import pino, { Logger as Logger$1 } from 'pino';
@@ -216,6 +215,44 @@ interface BuildAppOptions {
216
215
  }
217
216
  declare function buildApp(options?: BuildAppOptions): Promise<void>;
218
217
 
218
+ declare const WINDOW_DATA_KEY = "__FW_DATA__";
219
+
220
+ type InitialData = {
221
+ pathname: string;
222
+ params: Record<string, string>;
223
+ props: Record<string, any>;
224
+ metadata?: {
225
+ title?: string;
226
+ description?: string;
227
+ } | null;
228
+ notFound?: boolean;
229
+ error?: boolean;
230
+ theme?: string;
231
+ };
232
+ declare global {
233
+ interface Window {
234
+ [WINDOW_DATA_KEY]?: InitialData;
235
+ }
236
+ }
237
+ type ClientLoadedComponents = {
238
+ Page: React.ComponentType<any>;
239
+ layouts: React.ComponentType<any>[];
240
+ };
241
+ type ClientRouteLoaded = {
242
+ pattern: string;
243
+ paramNames: string[];
244
+ load: () => Promise<ClientLoadedComponents>;
245
+ };
246
+
247
+ /**
248
+ * Bootstraps the client-side application.
249
+ *
250
+ * @param routes - Array of client routes
251
+ * @param notFoundRoute - Not-found route definition
252
+ * @param errorRoute - Error route definition
253
+ */
254
+ declare function bootstrapClient(routes: ClientRouteLoaded[], notFoundRoute: ClientRouteLoaded | null, errorRoute?: ClientRouteLoaded | null): void;
255
+
219
256
  declare function withCache(fn: any, options: any): any;
220
257
 
221
258
  /**
@@ -442,4 +479,4 @@ declare function requestLoggerMiddleware(options?: {
442
479
  */
443
480
  declare function getRequestLogger(req: Request): Logger;
444
481
 
445
- export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
482
+ export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, bootstrapClient, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import http from 'http';
2
2
  import { Request, Response } from 'express';
3
3
  import { Socket, Server } from 'socket.io';
4
- export { c as bootstrapClient } from './bootstrap-BiCQmSkx.js';
5
4
  import { ZodSchema, z } from 'zod';
6
5
  import * as express_rate_limit from 'express-rate-limit';
7
6
  import pino, { Logger as Logger$1 } from 'pino';
@@ -216,6 +215,44 @@ interface BuildAppOptions {
216
215
  }
217
216
  declare function buildApp(options?: BuildAppOptions): Promise<void>;
218
217
 
218
+ declare const WINDOW_DATA_KEY = "__FW_DATA__";
219
+
220
+ type InitialData = {
221
+ pathname: string;
222
+ params: Record<string, string>;
223
+ props: Record<string, any>;
224
+ metadata?: {
225
+ title?: string;
226
+ description?: string;
227
+ } | null;
228
+ notFound?: boolean;
229
+ error?: boolean;
230
+ theme?: string;
231
+ };
232
+ declare global {
233
+ interface Window {
234
+ [WINDOW_DATA_KEY]?: InitialData;
235
+ }
236
+ }
237
+ type ClientLoadedComponents = {
238
+ Page: React.ComponentType<any>;
239
+ layouts: React.ComponentType<any>[];
240
+ };
241
+ type ClientRouteLoaded = {
242
+ pattern: string;
243
+ paramNames: string[];
244
+ load: () => Promise<ClientLoadedComponents>;
245
+ };
246
+
247
+ /**
248
+ * Bootstraps the client-side application.
249
+ *
250
+ * @param routes - Array of client routes
251
+ * @param notFoundRoute - Not-found route definition
252
+ * @param errorRoute - Error route definition
253
+ */
254
+ declare function bootstrapClient(routes: ClientRouteLoaded[], notFoundRoute: ClientRouteLoaded | null, errorRoute?: ClientRouteLoaded | null): void;
255
+
219
256
  declare function withCache(fn: any, options: any): any;
220
257
 
221
258
  /**
@@ -442,4 +479,4 @@ declare function requestLoggerMiddleware(options?: {
442
479
  */
443
480
  declare function getRequestLogger(req: Request): Logger;
444
481
 
445
- export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
482
+ export { type ApiContext, type ApiMiddleware, DEFAULT_CONFIG, type FrameworkConfig, type GenerateStaticParams, type InitServerData, type LoaderResult, type LogLevel, Logger, type LoggerContext, type LoggerOptions, type MetadataLoader, type RouteMiddleware, type ServerConfig, type ServerContext, type ServerLoader, ValidationError, type WssContext, bootstrapClient, buildApp, commonSchemas, createModuleLogger, createRateLimiter, defaultRateLimiter, generateRequestId, getAppDir, getBuildDir, getLogger, getRequestLogger, getStaticDir, lenientRateLimiter, loadConfig, logger, requestLoggerMiddleware, resetLogger, safeValidate, sanitizeObject, sanitizeParams, sanitizeQuery, sanitizeString, setLogger, startDevServer, startProdServer, strictRateLimiter, validate, withCache };
package/dist/index.js CHANGED
@@ -1353,9 +1353,6 @@ function createClientConfig(projectRoot, mode) {
1353
1353
  filename: mode === "production" ? "client.[contenthash].css" : "client.css"
1354
1354
  })
1355
1355
  ],
1356
- externals: {
1357
- "@lolyjs/core/runtime": "@lolyjs/core/runtime"
1358
- },
1359
1356
  infrastructureLogging: {
1360
1357
  level: "error"
1361
1358
  },
@@ -5102,6 +5099,11 @@ import { useEffect, useState, useRef } from "react";
5102
5099
  // modules/runtime/client/RouterView.tsx
5103
5100
  import { jsx } from "react/jsx-runtime";
5104
5101
  function RouterView({ state }) {
5102
+ console.log("[loly:RouterView] Rendering", {
5103
+ url: state.url,
5104
+ hasRoute: !!state.route,
5105
+ hasComponents: !!state.components
5106
+ });
5105
5107
  if (!state.route) {
5106
5108
  if (state.components === null) {
5107
5109
  return null;
@@ -5113,6 +5115,11 @@ function RouterView({ state }) {
5113
5115
  }
5114
5116
  const { Page, layouts } = state.components;
5115
5117
  const { params, props } = state;
5118
+ console.log("[loly:RouterView] Creating page element", {
5119
+ hasPage: !!Page,
5120
+ layoutsCount: layouts.length,
5121
+ paramsKeys: Object.keys(params)
5122
+ });
5116
5123
  let element = /* @__PURE__ */ jsx(Page, { params, ...props });
5117
5124
  const layoutChain = layouts.slice().reverse();
5118
5125
  for (const Layout of layoutChain) {
@@ -5460,24 +5467,50 @@ async function navigate(nextUrl, handlers, options) {
5460
5467
  }
5461
5468
  function createClickHandler(navigate2) {
5462
5469
  return function handleClick(ev) {
5470
+ const target = ev.target;
5471
+ const tagName = target?.tagName.toLowerCase() || "unknown";
5472
+ console.log("[loly:click] Click event received", {
5473
+ type: ev.type,
5474
+ tagName,
5475
+ target: target?.tagName,
5476
+ defaultPrevented: ev.defaultPrevented,
5477
+ button: ev.button,
5478
+ clientX: ev.clientX,
5479
+ clientY: ev.clientY
5480
+ });
5463
5481
  try {
5464
- if (ev.defaultPrevented) return;
5465
- if (ev.type !== "click") return;
5466
- if (ev.button !== 0) return;
5467
- if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
5482
+ if (ev.defaultPrevented) {
5483
+ console.log("[loly:click] Event already prevented, skipping");
5484
+ return;
5485
+ }
5486
+ if (ev.type !== "click") {
5487
+ console.log("[loly:click] Not a click event, skipping", { type: ev.type });
5488
+ return;
5489
+ }
5490
+ if (ev.button !== 0) {
5491
+ console.log("[loly:click] Not left button, skipping", { button: ev.button });
5492
+ return;
5493
+ }
5494
+ if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) {
5495
+ console.log("[loly:click] Modifier keys pressed, skipping");
5496
+ return;
5497
+ }
5468
5498
  if (ev.clientX === 0 && ev.clientY === 0 && ev.detail === 0) {
5469
- const target2 = ev.target;
5470
- if (target2) {
5471
- const tagName2 = target2.tagName.toLowerCase();
5472
- if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select") {
5499
+ if (target) {
5500
+ const tagName3 = target.tagName.toLowerCase();
5501
+ if (tagName3 === "input" || tagName3 === "textarea" || tagName3 === "button" || tagName3 === "select") {
5502
+ console.log("[loly:click] Synthetic event on interactive element, skipping", { tagName: tagName3 });
5473
5503
  return;
5474
5504
  }
5475
5505
  }
5476
5506
  }
5477
- const target = ev.target;
5478
- if (!target) return;
5479
- const tagName = target.tagName.toLowerCase();
5480
- if (tagName === "input" || tagName === "textarea" || tagName === "button" || tagName === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
5507
+ if (!target) {
5508
+ console.log("[loly:click] No target, skipping");
5509
+ return;
5510
+ }
5511
+ const tagName2 = target.tagName.toLowerCase();
5512
+ if (tagName2 === "input" || tagName2 === "textarea" || tagName2 === "button" || tagName2 === "select" || target.isContentEditable || target.getAttribute("contenteditable") === "true") {
5513
+ console.log("[loly:click] Target is interactive element, skipping", { tagName: tagName2 });
5481
5514
  return;
5482
5515
  }
5483
5516
  const interactiveParent = target.closest("input, textarea, button, select, [contenteditable], label");
@@ -5485,29 +5518,60 @@ function createClickHandler(navigate2) {
5485
5518
  if (interactiveParent.tagName.toLowerCase() === "label") {
5486
5519
  const label = interactiveParent;
5487
5520
  if (label.control) {
5521
+ console.log("[loly:click] Inside label with control, skipping");
5488
5522
  return;
5489
5523
  }
5490
5524
  } else {
5525
+ console.log("[loly:click] Inside interactive parent, skipping", {
5526
+ parentTag: interactiveParent.tagName.toLowerCase()
5527
+ });
5491
5528
  return;
5492
5529
  }
5493
5530
  }
5494
5531
  const anchor = target.closest("a[href]");
5495
- if (!anchor) return;
5532
+ if (!anchor) {
5533
+ console.log("[loly:click] No anchor found, skipping");
5534
+ return;
5535
+ }
5536
+ console.log("[loly:click] Anchor found, processing navigation", {
5537
+ href: anchor.getAttribute("href")
5538
+ });
5496
5539
  const href = anchor.getAttribute("href");
5497
- if (!href) return;
5498
- if (href.startsWith("#")) return;
5540
+ if (!href) {
5541
+ console.log("[loly:click] No href attribute, skipping");
5542
+ return;
5543
+ }
5544
+ if (href.startsWith("#")) {
5545
+ console.log("[loly:click] Hash link, skipping");
5546
+ return;
5547
+ }
5499
5548
  const url = new URL(href, window.location.href);
5500
- if (url.origin !== window.location.origin) return;
5501
- if (anchor.target && anchor.target !== "_self") return;
5549
+ if (url.origin !== window.location.origin) {
5550
+ console.log("[loly:click] External link, skipping", { origin: url.origin });
5551
+ return;
5552
+ }
5553
+ if (anchor.target && anchor.target !== "_self") {
5554
+ console.log("[loly:click] Link has target, skipping", { target: anchor.target });
5555
+ return;
5556
+ }
5502
5557
  ev.preventDefault();
5558
+ console.log("[loly:click] Prevented default, navigating");
5503
5559
  const nextUrl = url.pathname + url.search;
5504
5560
  const currentUrl = window.location.pathname + window.location.search;
5505
- if (nextUrl === currentUrl) return;
5561
+ if (nextUrl === currentUrl) {
5562
+ console.log("[loly:click] Same URL, skipping", { nextUrl });
5563
+ return;
5564
+ }
5506
5565
  const shouldRevalidate = anchor.hasAttribute("data-revalidate") && anchor.getAttribute("data-revalidate") !== "false";
5566
+ console.log("[loly:click] Pushing state and navigating", {
5567
+ nextUrl,
5568
+ currentUrl,
5569
+ shouldRevalidate
5570
+ });
5507
5571
  window.history.pushState({}, "", nextUrl);
5508
5572
  navigate2(nextUrl, shouldRevalidate ? { revalidate: true } : void 0);
5509
5573
  } catch (error) {
5510
- console.error("[navigation] Error in click handler:", error);
5574
+ console.error("[loly:click] Error in click handler:", error);
5511
5575
  }
5512
5576
  };
5513
5577
  }
@@ -5526,6 +5590,10 @@ function AppShell({
5526
5590
  notFoundRoute,
5527
5591
  errorRoute
5528
5592
  }) {
5593
+ console.log("[loly:AppShell] Component rendering", {
5594
+ url: initialState.url,
5595
+ hasRoute: !!initialState.route
5596
+ });
5529
5597
  const [state, setState] = useState(initialState);
5530
5598
  const handlersRef = useRef({
5531
5599
  setState,
@@ -5534,6 +5602,11 @@ function AppShell({
5534
5602
  errorRoute
5535
5603
  });
5536
5604
  useEffect(() => {
5605
+ console.log("[loly:AppShell] Updating handlersRef", {
5606
+ routesCount: routes.length,
5607
+ hasNotFound: !!notFoundRoute,
5608
+ hasError: !!errorRoute
5609
+ });
5537
5610
  handlersRef.current = {
5538
5611
  setState,
5539
5612
  routes,
@@ -5542,16 +5615,34 @@ function AppShell({
5542
5615
  };
5543
5616
  }, [routes, notFoundRoute, errorRoute]);
5544
5617
  useEffect(() => {
5618
+ const effectId = Math.random().toString(36).substring(7);
5619
+ console.log("[loly:AppShell] Setting up event listeners", { effectId });
5545
5620
  let isMounted = true;
5621
+ let listenerCount = 0;
5546
5622
  async function handleNavigate(nextUrl, options) {
5547
- if (!isMounted) return;
5623
+ if (!isMounted) {
5624
+ console.warn("[loly:AppShell] navigate called but component is unmounted");
5625
+ return;
5626
+ }
5627
+ console.log("[loly:AppShell] Navigating to", nextUrl, options);
5548
5628
  await navigate(nextUrl, handlersRef.current, options);
5549
5629
  }
5550
5630
  const handleClick = createClickHandler(handleNavigate);
5551
5631
  const handlePopState = createPopStateHandler(handleNavigate);
5552
5632
  window.addEventListener("click", handleClick, false);
5553
5633
  window.addEventListener("popstate", handlePopState, false);
5634
+ listenerCount = 2;
5635
+ console.log("[loly:AppShell] Event listeners added", {
5636
+ clickListener: true,
5637
+ popStateListener: true,
5638
+ totalListeners: listenerCount
5639
+ });
5554
5640
  return () => {
5641
+ console.log("[loly:AppShell] Cleaning up event listeners", {
5642
+ effectId,
5643
+ wasMounted: isMounted,
5644
+ listenersToRemove: listenerCount
5645
+ });
5555
5646
  isMounted = false;
5556
5647
  window.removeEventListener("click", handleClick, false);
5557
5648
  window.removeEventListener("popstate", handlePopState, false);
@@ -5606,14 +5697,25 @@ async function loadInitialRoute(initialUrl, initialData, routes, notFoundRoute,
5606
5697
  };
5607
5698
  }
5608
5699
  function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5700
+ console.log("[loly:runtime] bootstrapClient called", {
5701
+ routesCount: routes.length,
5702
+ hasNotFound: !!notFoundRoute,
5703
+ hasError: !!errorRoute
5704
+ });
5609
5705
  (async function bootstrap() {
5610
5706
  const container = document.getElementById(APP_CONTAINER_ID2);
5611
5707
  const initialData = getWindowData();
5708
+ console.log("[loly:runtime] bootstrap starting", {
5709
+ hasContainer: !!container,
5710
+ containerId: APP_CONTAINER_ID2,
5711
+ hasInitialData: !!initialData
5712
+ });
5612
5713
  if (!container) {
5613
- console.error(`Container #${APP_CONTAINER_ID2} not found for hydration`);
5714
+ console.error(`[loly:runtime] Container #${APP_CONTAINER_ID2} not found for hydration`);
5614
5715
  return;
5615
5716
  }
5616
5717
  const initialUrl = window.location.pathname + window.location.search;
5718
+ console.log("[loly:runtime] Loading initial route", { initialUrl });
5617
5719
  try {
5618
5720
  const initialState = await loadInitialRoute(
5619
5721
  initialUrl,
@@ -5622,9 +5724,15 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5622
5724
  notFoundRoute,
5623
5725
  errorRoute
5624
5726
  );
5727
+ console.log("[loly:runtime] Initial route loaded", {
5728
+ url: initialState.url,
5729
+ hasRoute: !!initialState.route,
5730
+ hasComponents: !!initialState.components
5731
+ });
5625
5732
  if (initialData?.metadata) {
5626
5733
  applyMetadata(initialData.metadata);
5627
5734
  }
5735
+ console.log("[loly:runtime] Hydrating React app");
5628
5736
  hydrateRoot(
5629
5737
  container,
5630
5738
  /* @__PURE__ */ jsx3(
@@ -5637,9 +5745,10 @@ function bootstrapClient(routes, notFoundRoute, errorRoute = null) {
5637
5745
  }
5638
5746
  )
5639
5747
  );
5748
+ console.log("[loly:runtime] React app hydrated successfully");
5640
5749
  } catch (error) {
5641
5750
  console.error(
5642
- "[client] Error loading initial route components for",
5751
+ "[loly:runtime] Error loading initial route components for",
5643
5752
  initialUrl,
5644
5753
  error
5645
5754
  );