@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.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import http from 'http';
2
2
  export { a as ApiContext, A as ApiMiddleware, G as GenerateStaticParams, L as LoaderResult, M as MetadataLoader, R as RouteMiddleware, S as ServerContext, b as ServerLoader, W as WssActions } from './index.types-DMOO-uvF.mjs';
3
- import { Server, Socket } from 'socket.io';
3
+ import { Socket } from 'socket.io';
4
4
  export { c as bootstrapClient } from './bootstrap-BfGTMUkj.mjs';
5
5
  import { ZodSchema, z } from 'zod';
6
6
  import * as express_rate_limit from 'express-rate-limit';
@@ -153,7 +153,6 @@ interface RateLimitCfg {
153
153
  type GuardFn<TUser = any> = (ctx: {
154
154
  user: TUser | null;
155
155
  req: AuthContext["req"];
156
- socket: Socket;
157
156
  namespace: string;
158
157
  }) => boolean | Promise<boolean>;
159
158
  /**
@@ -279,10 +278,6 @@ interface WssActions {
279
278
  * Extended WssContext with full RFC support.
280
279
  */
281
280
  interface WssContext<TData = any, TUser = any> {
282
- /** Socket.IO server instance */
283
- io: Server;
284
- /** Socket.IO socket instance */
285
- socket: Socket;
286
281
  /** Request metadata */
287
282
  req: {
288
283
  headers: Record<string, string | string[] | undefined>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import http from 'http';
2
2
  export { a as ApiContext, A as ApiMiddleware, G as GenerateStaticParams, L as LoaderResult, M as MetadataLoader, R as RouteMiddleware, S as ServerContext, b as ServerLoader, W as WssActions } from './index.types-DMOO-uvF.js';
3
- import { Server, Socket } from 'socket.io';
3
+ import { Socket } from 'socket.io';
4
4
  export { c as bootstrapClient } from './bootstrap-BfGTMUkj.js';
5
5
  import { ZodSchema, z } from 'zod';
6
6
  import * as express_rate_limit from 'express-rate-limit';
@@ -153,7 +153,6 @@ interface RateLimitCfg {
153
153
  type GuardFn<TUser = any> = (ctx: {
154
154
  user: TUser | null;
155
155
  req: AuthContext["req"];
156
- socket: Socket;
157
156
  namespace: string;
158
157
  }) => boolean | Promise<boolean>;
159
158
  /**
@@ -279,10 +278,6 @@ interface WssActions {
279
278
  * Extended WssContext with full RFC support.
280
279
  */
281
280
  interface WssContext<TData = any, TUser = any> {
282
- /** Socket.IO server instance */
283
- io: Server;
284
- /** Socket.IO socket instance */
285
- socket: Socket;
286
281
  /** Request metadata */
287
282
  req: {
288
283
  headers: Record<string, string | string[] | undefined>;
package/dist/index.js CHANGED
@@ -11505,22 +11505,36 @@ function copyStaticAssets(projectRoot, outDir) {
11505
11505
  const assetsSrc = path11.join(projectRoot, "assets");
11506
11506
  const assetsDest = path11.join(outDir, "assets");
11507
11507
  copyDirRecursive(assetsSrc, assetsDest);
11508
- const appDir = path11.join(projectRoot, "app");
11508
+ const publicDir = path11.join(projectRoot, "public");
11509
11509
  const candidates = ["favicon.ico", "favicon.png"];
11510
11510
  for (const name of candidates) {
11511
- const fromApp = path11.join(appDir, name);
11512
- const fromRoot = path11.join(projectRoot, name);
11513
- let src = null;
11514
- if (fs11.existsSync(fromApp)) src = fromApp;
11515
- else if (fs11.existsSync(fromRoot)) src = fromRoot;
11516
- if (src) {
11511
+ const fromPublic = path11.join(publicDir, name);
11512
+ if (fs11.existsSync(fromPublic)) {
11517
11513
  const dest = path11.join(outDir, name);
11518
11514
  ensureDir(path11.dirname(dest));
11519
- fs11.copyFileSync(src, dest);
11515
+ fs11.copyFileSync(fromPublic, dest);
11520
11516
  break;
11521
11517
  }
11522
11518
  }
11523
11519
  }
11520
+ function getFaviconInfo(projectRoot, staticDir = "public", isDev = false) {
11521
+ const candidates = [
11522
+ { name: "favicon.ico", type: "image/x-icon" },
11523
+ { name: "favicon.png", type: "image/png" }
11524
+ ];
11525
+ const publicDir = path11.join(projectRoot, staticDir);
11526
+ for (const candidate of candidates) {
11527
+ const publicPath = path11.join(publicDir, candidate.name);
11528
+ if (fs11.existsSync(publicPath)) {
11529
+ return {
11530
+ path: `/${candidate.name}`,
11531
+ // Served at root from public/
11532
+ type: candidate.type
11533
+ };
11534
+ }
11535
+ }
11536
+ return null;
11537
+ }
11524
11538
  function generateAssetManifest(outDir, stats) {
11525
11539
  const manifest = {
11526
11540
  client: {
@@ -14619,8 +14633,12 @@ function createDocumentTree(options) {
14619
14633
  clientJsPath = "/static/client.js",
14620
14634
  clientCssPath = "/static/client.css",
14621
14635
  nonce,
14622
- includeInlineScripts = true
14636
+ includeInlineScripts = true,
14623
14637
  // Default true - scripts inline in body for both SSR and SSG
14638
+ faviconPath = FAVICON_PATH,
14639
+ // Default to /static/favicon.png for backward compatibility
14640
+ faviconType = "image/png"
14641
+ // Default to PNG for backward compatibility
14624
14642
  } = options;
14625
14643
  const metaObj = meta ?? null;
14626
14644
  const title = metaObj?.title ?? titleFallback ?? "My Framework Dev";
@@ -14927,10 +14945,11 @@ function createDocumentTree(options) {
14927
14945
  href: chunkHref,
14928
14946
  as: "script"
14929
14947
  }),
14930
- React.createElement("link", {
14948
+ faviconPath && React.createElement("link", {
14949
+ key: "favicon",
14931
14950
  rel: "icon",
14932
- href: FAVICON_PATH,
14933
- type: "image/png"
14951
+ href: faviconPath,
14952
+ type: faviconType || (faviconPath.endsWith(".ico") ? "image/x-icon" : "image/png")
14934
14953
  }),
14935
14954
  React.createElement("link", {
14936
14955
  rel: "stylesheet",
@@ -15212,7 +15231,7 @@ async function handlePageRequest(options) {
15212
15231
  const { errorPage, req, res, routeChunks, theme, projectRoot } = options;
15213
15232
  const reqLogger = getRequestLogger(req);
15214
15233
  if (errorPage) {
15215
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env);
15234
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks || {}, theme, projectRoot, options.env, options.config);
15216
15235
  } else {
15217
15236
  reqLogger.error("Unhandled error in page request", error, {
15218
15237
  urlPath: options.urlPath,
@@ -15238,11 +15257,13 @@ async function handlePageRequestInternal(options) {
15238
15257
  env = "dev",
15239
15258
  ssgOutDir,
15240
15259
  theme,
15241
- projectRoot
15260
+ projectRoot,
15261
+ config
15242
15262
  } = options;
15243
15263
  const clientJsPath = env === "dev" ? "/static/client.js" : projectRoot ? getClientJsPath(projectRoot) : "/static/client.js";
15244
15264
  const clientCssPath = env === "dev" ? "/static/client.css" : projectRoot ? getClientCssPath(projectRoot) : "/static/client.css";
15245
15265
  const assetManifest = env === "prod" && projectRoot ? loadAssetManifest(projectRoot) : null;
15266
+ const faviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
15246
15267
  const isDataReq = isDataRequest(req);
15247
15268
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
15248
15269
  if (env === "prod" && ssgOutDir) {
@@ -15357,7 +15378,9 @@ async function handlePageRequestInternal(options) {
15357
15378
  theme,
15358
15379
  clientJsPath,
15359
15380
  clientCssPath,
15360
- nonce: nonce2
15381
+ nonce: nonce2,
15382
+ faviconPath: faviconInfo?.path || null,
15383
+ faviconType: faviconInfo?.type || null
15361
15384
  });
15362
15385
  let didError2 = false;
15363
15386
  const { pipe: pipe2, abort: abort2 } = renderToPipeableStream(documentTree2, {
@@ -15372,7 +15395,7 @@ async function handlePageRequestInternal(options) {
15372
15395
  const reqLogger2 = getRequestLogger(req);
15373
15396
  reqLogger2.error("SSR shell error", err, { route: "not-found" });
15374
15397
  if (!res.headersSent && errorPage) {
15375
- renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
15398
+ renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env, config);
15376
15399
  } else if (!res.headersSent) {
15377
15400
  res.statusCode = 500;
15378
15401
  res.setHeader("Content-Type", "text/html; charset=utf-8");
@@ -15487,7 +15510,7 @@ async function handlePageRequestInternal(options) {
15487
15510
  return;
15488
15511
  } else {
15489
15512
  if (errorPage) {
15490
- await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env);
15513
+ await renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env, config);
15491
15514
  return;
15492
15515
  } else {
15493
15516
  throw error;
@@ -15565,7 +15588,9 @@ async function handlePageRequestInternal(options) {
15565
15588
  theme,
15566
15589
  clientJsPath,
15567
15590
  clientCssPath,
15568
- nonce
15591
+ nonce,
15592
+ faviconPath: faviconInfo?.path || null,
15593
+ faviconType: faviconInfo?.type || null
15569
15594
  });
15570
15595
  let didError = false;
15571
15596
  const { pipe, abort } = renderToPipeableStream(documentTree, {
@@ -15613,7 +15638,7 @@ async function handlePageRequestInternal(options) {
15613
15638
  abort();
15614
15639
  });
15615
15640
  }
15616
- async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev") {
15641
+ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks, theme, projectRoot, env = "dev", config) {
15617
15642
  try {
15618
15643
  const isDataReq = isDataRequest(req);
15619
15644
  const skipLayoutHooks = isDataReq && req.headers["x-skip-layout-hooks"] === "true";
@@ -15624,6 +15649,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15624
15649
  pathname: req.path,
15625
15650
  locals: { error }
15626
15651
  };
15652
+ const faviconInfo = projectRoot && config ? getFaviconInfo(projectRoot, config.directories.static, env === "dev") : null;
15627
15653
  const layoutProps = {};
15628
15654
  const reqLogger = getRequestLogger(req);
15629
15655
  if (!skipLayoutHooks && errorPage.layoutServerHooks && errorPage.layoutServerHooks.length > 0) {
@@ -15729,7 +15755,9 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
15729
15755
  theme,
15730
15756
  clientJsPath,
15731
15757
  clientCssPath,
15732
- nonce
15758
+ nonce,
15759
+ faviconPath: faviconInfo?.path || null,
15760
+ faviconType: faviconInfo?.type || null
15733
15761
  });
15734
15762
  let didError = false;
15735
15763
  const { pipe, abort } = renderToPipeableStream(documentTree, {
@@ -15986,7 +16014,8 @@ function setupRoutes(options) {
15986
16014
  env: isDev ? "dev" : "prod",
15987
16015
  ssgOutDir,
15988
16016
  theme: req.cookies?.theme || "light",
15989
- projectRoot
16017
+ projectRoot,
16018
+ config
15990
16019
  });
15991
16020
  });
15992
16021
  }
@@ -16600,7 +16629,6 @@ async function executeGuard(guardFn, ctx) {
16600
16629
  const guardCtx = {
16601
16630
  user: ctx.user,
16602
16631
  req: ctx.req,
16603
- socket: ctx.socket,
16604
16632
  namespace: ctx.pathname
16605
16633
  };
16606
16634
  const result = await guardFn(guardCtx);
@@ -16707,9 +16735,6 @@ var generateActions = (socket, namespace, presence) => {
16707
16735
  return {
16708
16736
  emit: async (event, payload) => {
16709
16737
  if (!presence) {
16710
- console.warn(
16711
- "[loly:realtime] toUser() requires presence manager. Make sure realtime is properly configured."
16712
- );
16713
16738
  return;
16714
16739
  }
16715
16740
  const socketIds = await presence.getSocketsForUser(userId);
@@ -16812,19 +16837,12 @@ async function setupWssEvents(options) {
16812
16837
  const subClient = pubClient.duplicate();
16813
16838
  io.adapter(createAdapter(pubClient, subClient));
16814
16839
  } catch (error) {
16815
- console.error(
16816
- "[loly:realtime] Failed to setup Redis adapter:",
16817
- error instanceof Error ? error.message : String(error)
16818
- );
16819
16840
  throw error;
16820
16841
  }
16821
16842
  }
16822
16843
  for (const wssRoute of wssRoutes) {
16823
16844
  const normalized = wssRoute.normalized;
16824
16845
  if (!normalized) {
16825
- console.warn(
16826
- `[loly:realtime] Skipping route ${wssRoute.pattern}: No normalized route definition`
16827
- );
16828
16846
  continue;
16829
16847
  }
16830
16848
  let namespacePath = normalized.namespace || wssRoute.pattern.replace(/^\/wss/, "");
@@ -16835,9 +16853,7 @@ async function setupWssEvents(options) {
16835
16853
  namespacePath = "/";
16836
16854
  }
16837
16855
  const namespace = io.of(namespacePath);
16838
- console.log(`[loly:realtime] Registered namespace: ${namespacePath} (from pattern: ${wssRoute.pattern})`);
16839
16856
  namespace.on("connection", async (socket) => {
16840
- console.log(`[loly:realtime] Client connected to namespace ${namespacePath}, socket: ${socket.id}`);
16841
16857
  const requestId = generateRequestId();
16842
16858
  socket.requestId = requestId;
16843
16859
  const log = createWssLogger(namespacePath, socket);
@@ -16849,8 +16865,6 @@ async function setupWssEvents(options) {
16849
16865
  await presence.addSocketForUser(String(user.id), socket.id);
16850
16866
  }
16851
16867
  const baseCtx = {
16852
- socket,
16853
- io: namespace.server,
16854
16868
  req: {
16855
16869
  headers: socket.handshake.headers,
16856
16870
  ip: socket.handshake.address,
@@ -17309,11 +17323,12 @@ import fs18 from "fs";
17309
17323
  import path25 from "path";
17310
17324
  import { renderToString } from "react-dom/server";
17311
17325
  init_globals();
17312
- async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params) {
17326
+ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params, config) {
17313
17327
  const routeChunks = loadChunksFromManifest(projectRoot);
17314
17328
  const assetManifest = loadAssetManifest(projectRoot);
17315
17329
  const clientJsPath = getClientJsPath(projectRoot);
17316
17330
  const clientCssPath = getClientCssPath(projectRoot);
17331
+ const faviconInfo = config ? getFaviconInfo(projectRoot, config.directories.static, false) : null;
17317
17332
  const chunkName = routeChunks[route.pattern];
17318
17333
  let chunkHref = null;
17319
17334
  if (chunkName != null) {
@@ -17421,8 +17436,10 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params)
17421
17436
  entrypointFiles,
17422
17437
  clientJsPath,
17423
17438
  clientCssPath,
17424
- includeInlineScripts: true
17439
+ includeInlineScripts: true,
17425
17440
  // SSG needs inline scripts (renderToString doesn't support bootstrapScripts)
17441
+ faviconPath: faviconInfo?.path || null,
17442
+ faviconType: faviconInfo?.type || null
17426
17443
  });
17427
17444
  const html = "<!DOCTYPE html>" + renderToString(documentTree);
17428
17445
  const dir = pathToOutDir(ssgOutDir, urlPath);
@@ -17435,7 +17452,7 @@ async function renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params)
17435
17452
 
17436
17453
  // modules/build/ssg/builder.ts
17437
17454
  init_globals();
17438
- async function buildStaticPages(projectRoot, routes) {
17455
+ async function buildStaticPages(projectRoot, routes, config) {
17439
17456
  const ssgOutDir = path26.join(projectRoot, BUILD_FOLDER_NAME, "ssg");
17440
17457
  ensureDir(ssgOutDir);
17441
17458
  for (const route of routes) {
@@ -17484,7 +17501,7 @@ async function buildStaticPages(projectRoot, routes) {
17484
17501
  }
17485
17502
  for (const params of allParams) {
17486
17503
  const urlPath = buildPathFromPattern(route.pattern, params);
17487
- await renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params);
17504
+ await renderStaticRoute(projectRoot, ssgOutDir, route, urlPath, params, config);
17488
17505
  }
17489
17506
  }
17490
17507
  console.log(`\u2705 [framework][ssg] Finished building all static pages`);
@@ -17705,7 +17722,7 @@ async function buildApp(options = {}) {
17705
17722
  writeClientBoostrapManifest(projectRoot);
17706
17723
  writeClientRoutesManifest(routes, projectRoot);
17707
17724
  await buildClientBundle(projectRoot);
17708
- await buildStaticPages(projectRoot, routes);
17725
+ await buildStaticPages(projectRoot, routes, config);
17709
17726
  delete process.env.LOLY_BUILD;
17710
17727
  console.log(`[framework][build] Build completed successfully`);
17711
17728
  }