@lolyjs/core 0.2.0-alpha.23 → 0.2.0-alpha.25

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
@@ -11538,22 +11538,36 @@ function copyStaticAssets(projectRoot, outDir) {
11538
11538
  const assetsSrc = import_path13.default.join(projectRoot, "assets");
11539
11539
  const assetsDest = import_path13.default.join(outDir, "assets");
11540
11540
  copyDirRecursive(assetsSrc, assetsDest);
11541
- const appDir = import_path13.default.join(projectRoot, "app");
11541
+ const publicDir = import_path13.default.join(projectRoot, "public");
11542
11542
  const candidates = ["favicon.ico", "favicon.png"];
11543
11543
  for (const name of candidates) {
11544
- const fromApp = import_path13.default.join(appDir, name);
11545
- const fromRoot = import_path13.default.join(projectRoot, name);
11546
- let src = null;
11547
- if (import_fs11.default.existsSync(fromApp)) src = fromApp;
11548
- else if (import_fs11.default.existsSync(fromRoot)) src = fromRoot;
11549
- if (src) {
11544
+ const fromPublic = import_path13.default.join(publicDir, name);
11545
+ if (import_fs11.default.existsSync(fromPublic)) {
11550
11546
  const dest = import_path13.default.join(outDir, name);
11551
11547
  ensureDir(import_path13.default.dirname(dest));
11552
- import_fs11.default.copyFileSync(src, dest);
11548
+ import_fs11.default.copyFileSync(fromPublic, dest);
11553
11549
  break;
11554
11550
  }
11555
11551
  }
11556
11552
  }
11553
+ function getFaviconInfo(projectRoot, staticDir = "public", isDev = false) {
11554
+ const candidates = [
11555
+ { name: "favicon.ico", type: "image/x-icon" },
11556
+ { name: "favicon.png", type: "image/png" }
11557
+ ];
11558
+ const publicDir = import_path13.default.join(projectRoot, staticDir);
11559
+ for (const candidate of candidates) {
11560
+ const publicPath = import_path13.default.join(publicDir, candidate.name);
11561
+ if (import_fs11.default.existsSync(publicPath)) {
11562
+ return {
11563
+ path: `/${candidate.name}`,
11564
+ // Served at root from public/
11565
+ type: candidate.type
11566
+ };
11567
+ }
11568
+ }
11569
+ return null;
11570
+ }
11557
11571
  function generateAssetManifest(outDir, stats) {
11558
11572
  const manifest = {
11559
11573
  client: {
@@ -14652,8 +14666,12 @@ function createDocumentTree(options) {
14652
14666
  clientJsPath = "/static/client.js",
14653
14667
  clientCssPath = "/static/client.css",
14654
14668
  nonce,
14655
- includeInlineScripts = true
14669
+ includeInlineScripts = true,
14656
14670
  // Default true - scripts inline in body for both SSR and SSG
14671
+ faviconPath = FAVICON_PATH,
14672
+ // Default to /static/favicon.png for backward compatibility
14673
+ faviconType = "image/png"
14674
+ // Default to PNG for backward compatibility
14657
14675
  } = options;
14658
14676
  const metaObj = meta ?? null;
14659
14677
  const title = metaObj?.title ?? titleFallback ?? "My Framework Dev";
@@ -14960,10 +14978,11 @@ function createDocumentTree(options) {
14960
14978
  href: chunkHref,
14961
14979
  as: "script"
14962
14980
  }),
14963
- import_react.default.createElement("link", {
14981
+ faviconPath && import_react.default.createElement("link", {
14982
+ key: "favicon",
14964
14983
  rel: "icon",
14965
- href: FAVICON_PATH,
14966
- type: "image/png"
14984
+ href: faviconPath,
14985
+ type: faviconType || (faviconPath.endsWith(".ico") ? "image/x-icon" : "image/png")
14967
14986
  }),
14968
14987
  import_react.default.createElement("link", {
14969
14988
  rel: "stylesheet",
@@ -15245,7 +15264,7 @@ async function handlePageRequest(options) {
15245
15264
  const { errorPage, req, res, routeChunks, theme, projectRoot } = options;
15246
15265
  const reqLogger = getRequestLogger(req);
15247
15266
  if (errorPage) {
15248
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env);
15267
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env, options.config);
15249
15268
  } else {
15250
15269
  reqLogger.error("Unhandled error in page request", error, {
15251
15270
  urlPath: options.urlPath,
@@ -15271,11 +15290,13 @@ async function handlePageRequestInternal(options) {
15271
15290
  env = "dev",
15272
15291
  ssgOutDir,
15273
15292
  theme,
15274
- projectRoot
15293
+ projectRoot,
15294
+ config
15275
15295
  } = options;
15276
15296
  const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
15277
15297
  const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
15278
15298
  const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
15299
+ const faviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
15279
15300
  const isDataReq = isDataRequest(req);
15280
15301
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
15281
15302
  if (env === "prod" && ssgOutDir) {
@@ -15390,7 +15411,9 @@ async function handlePageRequestInternal(options) {
15390
15411
  theme,
15391
15412
  clientJsPath,
15392
15413
  clientCssPath,
15393
- nonce: nonce2
15414
+ nonce: nonce2,
15415
+ faviconPath: faviconInfo?.path || null,
15416
+ faviconType: faviconInfo?.type || null
15394
15417
  });
15395
15418
  let didError2 = false;
15396
15419
  const { pipe: pipe2, abort: abort2 } = (0, import_server.renderToPipeableStream)(documentTree2, {
@@ -15405,7 +15428,7 @@ async function handlePageRequestInternal(options) {
15405
15428
  const reqLogger2 = getRequestLogger(req);
15406
15429
  reqLogger2.error("SSR shell error", err, { route: "not-found" });
15407
15430
  if (!res.headersSent && errorPage) {
15408
- renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
15431
+ renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env, config);
15409
15432
  } else if (!res.headersSent) {
15410
15433
  res.statusCode = 500;
15411
15434
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -15520,7 +15543,7 @@ async function handlePageRequestInternal(options) {
15520
15543
  return;
15521
15544
  } else {
15522
15545
  if (errorPage) {
15523
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env);
15546
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env, config);
15524
15547
  return;
15525
15548
  } else {
15526
15549
  throw error;
@@ -15598,7 +15621,9 @@ async function handlePageRequestInternal(options) {
15598
15621
  theme,
15599
15622
  clientJsPath,
15600
15623
  clientCssPath,
15601
- nonce
15624
+ nonce,
15625
+ faviconPath: faviconInfo?.path || null,
15626
+ faviconType: faviconInfo?.type || null
15602
15627
  });
15603
15628
  let didError = false;
15604
15629
  const { pipe, abort } = (0, import_server.renderToPipeableStream)(documentTree, {
@@ -15646,7 +15671,7 @@ async function handlePageRequestInternal(options) {
15646
15671
  abort();
15647
15672
  });
15648
15673
  }
15649
- async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev") {
15674
+ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev", config) {
15650
15675
  try {
15651
15676
  const isDataReq = isDataRequest(req);
15652
15677
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
@@ -15657,6 +15682,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15657
15682
  pathname: req.path,
15658
15683
  locals: { error }
15659
15684
  };
15685
+ const faviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
15660
15686
  const layoutProps = {};
15661
15687
  const reqLogger = getRequestLogger(req);
15662
15688
  if (!skipLayoutHooks && errorPage.layoutServerHooks && errorPage.layoutServerHooks.length > 0) {
@@ -15762,7 +15788,9 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15762
15788
  theme,
15763
15789
  clientJsPath,
15764
15790
  clientCssPath,
15765
- nonce
15791
+ nonce,
15792
+ faviconPath: faviconInfo?.path || null,
15793
+ faviconType: faviconInfo?.type || null
15766
15794
  });
15767
15795
  let didError = false;
15768
15796
  const { pipe, abort } = (0, import_server.renderToPipeableStream)(documentTree, {
@@ -16019,7 +16047,8 @@ function setupRoutes(options) {
16019
16047
  env: isDev ? "dev" : "prod",
16020
16048
  ssgOutDir,
16021
16049
  theme: req.cookies?.theme || "light",
16022
- projectRoot
16050
+ projectRoot,
16051
+ config
16023
16052
  });
16024
16053
  });
16025
16054
  }
@@ -16633,7 +16662,6 @@ async function executeGuard(guardFn, ctx) {
16633
16662
  const guardCtx = {
16634
16663
  user: ctx.user,
16635
16664
  req: ctx.req,
16636
- socket: ctx.socket,
16637
16665
  namespace: ctx.pathname
16638
16666
  };
16639
16667
  const result = await guardFn(guardCtx);
@@ -16740,9 +16768,6 @@ var generateActions = (socket, namespace, presence) => {
16740
16768
  return {
16741
16769
  emit: async (event, payload) => {
16742
16770
  if (!presence) {
16743
- console.warn(
16744
- "[loly:realtime] toUser() requires presence manager. Make sure realtime is properly configured."
16745
- );
16746
16771
  return;
16747
16772
  }
16748
16773
  const socketIds = await presence.getSocketsForUser(userId);
@@ -16845,19 +16870,12 @@ async function setupWssEvents(options) {
16845
16870
  const subClient = pubClient.duplicate();
16846
16871
  io.adapter(createAdapter(pubClient, subClient));
16847
16872
  } catch (error) {
16848
- console.error(
16849
- "[loly:realtime] Failed to setup Redis adapter:",
16850
- error instanceof Error ? error.message : String(error)
16851
- );
16852
16873
  throw error;
16853
16874
  }
16854
16875
  }
16855
16876
  for (const wssRoute of wssRoutes) {
16856
16877
  const normalized = wssRoute.normalized;
16857
16878
  if (!normalized) {
16858
- console.warn(
16859
- `[loly:realtime] Skipping route ${wssRoute.pattern}: No normalized route definition`
16860
- );
16861
16879
  continue;
16862
16880
  }
16863
16881
  let namespacePath = normalized.namespace || wssRoute.pattern.replace(/^\/wss/, "");
@@ -16868,9 +16886,7 @@ async function setupWssEvents(options) {
16868
16886
  namespacePath = "/";
16869
16887
  }
16870
16888
  const namespace = io.of(namespacePath);
16871
- console.log(`[loly:realtime] Registered namespace: ${namespacePath} (from pattern: ${wssRoute.pattern})`);
16872
16889
  namespace.on("connection", async (socket) => {
16873
- console.log(`[loly:realtime] Client connected to namespace ${namespacePath}, socket: ${socket.id}`);
16874
16890
  const requestId = generateRequestId();
16875
16891
  socket.requestId = requestId;
16876
16892
  const log = createWssLogger(namespacePath, socket);
@@ -16882,8 +16898,6 @@ async function setupWssEvents(options) {
16882
16898
  await presence.addSocketForUser(String(user.id), socket.id);
16883
16899
  }
16884
16900
  const baseCtx = {
16885
- socket,
16886
- io: namespace.server,
16887
16901
  req: {
16888
16902
  headers: socket.handshake.headers,
16889
16903
  ip: socket.handshake.address,
@@ -17342,11 +17356,12 @@ var import_fs20 = __toESM(require("fs"));
17342
17356
  var import_path27 = __toESM(require("path"));
17343
17357
  var import_server3 = require("react-dom/server");
17344
17358
  init_globals();
17345
- async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params) {
17359
+ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params, config) {
17346
17360
  const routeChunks = loadChunksFromManifest(projectRoot);
17347
17361
  const assetManifest = loadAssetManifest(projectRoot);
17348
17362
  const clientJsPath = getClientJsPath(projectRoot);
17349
17363
  const clientCssPath = getClientCssPath(projectRoot);
17364
+ const faviconInfo = config ? getFaviconInfo(projectRoot, config.directories.static, false) : null;
17350
17365
  const chunkName = routeChunks[route.pattern];
17351
17366
  let chunkHref = null;
17352
17367
  if (chunkName != null) {
@@ -17454,8 +17469,10 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params)
17454
17469
  entrypointFiles,
17455
17470
  clientJsPath,
17456
17471
  clientCssPath,
17457
- includeInlineScripts: true
17472
+ includeInlineScripts: true,
17458
17473
  // SSG needs inline scripts (renderToString doesn't support bootstrapScripts)
17474
+ faviconPath: faviconInfo?.path || null,
17475
+ faviconType: faviconInfo?.type || null
17459
17476
  });
17460
17477
  const html = "<!DOCTYPE html>" + (0, import_server3.renderToString)(documentTree);
17461
17478
  const dir = pathToOutDir(ssgOutDir, urlPath);
@@ -17468,7 +17485,7 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params)
17468
17485
 
17469
17486
  // modules/build/ssg/builder.ts
17470
17487
  init_globals();
17471
- async function buildStaticPages(projectRoot, routes) {
17488
+ async function buildStaticPages(projectRoot, routes, config) {
17472
17489
  const ssgOutDir = import_path29.default.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
17473
17490
  ensureDir(ssgOutDir);
17474
17491
  for (const route of routes) {
@@ -17517,7 +17534,7 @@ async function buildStaticPages(projectRoot, routes) {
17517
17534
  }
17518
17535
  for (const params of allParams) {
17519
17536
  const urlPath = buildPathFromPattern(route.pattern, params);
17520
- await renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params);
17537
+ await renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params, config);
17521
17538
  }
17522
17539
  }
17523
17540
  console.log(`\u2705 [framework][ssg] Finished building all static pages`);
@@ -17738,7 +17755,7 @@ async function buildApp(options = {}) {
17738
17755
  writeClientBoostrapManifest(projectRoot);
17739
17756
  writeClientRoutesManifest(routes, projectRoot);
17740
17757
  await buildClientBundle(projectRoot);
17741
- await buildStaticPages(projectRoot, routes);
17758
+ await buildStaticPages(projectRoot, routes, config);
17742
17759
  delete process.env.LOLY_BUILD;
17743
17760
  console.log(`[framework][build] Build completed successfully`);
17744
17761
  }