@jay-framework/production-server 0.23.0 → 0.24.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.d.ts CHANGED
@@ -1,11 +1,13 @@
1
- import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-XSavezh8.js';
2
- export { A as ActionEntry, e as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, d as PageModule, P as PluginEntry, n as PreImportedPlugin, b as RouteSegment, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-XSavezh8.js';
1
+ import { B as BuildOptions, R as RouteManifest, a as RouteEntry } from './serve-index-cRXZm8vQ.js';
2
+ export { A as ActionEntry, b as ArtifactStore, c as BuildMetadata, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, P as PageModule, d as PluginEntry, e as PreImportedPlugin, f as RouteSegment, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-cRXZm8vQ.js';
3
3
  import '@jay-framework/ssr-runtime';
4
4
  import '@jay-framework/compiler-shared';
5
5
  import '@jay-framework/stack-server-runtime';
6
6
 
7
7
  declare function buildVersion(options: BuildOptions): Promise<RouteManifest>;
8
8
 
9
+ declare function generateSitemap(manifest: RouteManifest, baseUrl: string, outputPath: string): Promise<number>;
10
+
9
11
  interface MainServerOptions {
10
12
  buildRoot: string;
11
13
  version: string;
@@ -24,6 +26,8 @@ interface RendererServerOptions {
24
26
  pagesRoot: string;
25
27
  tsConfigFilePath?: string;
26
28
  minify?: boolean;
29
+ /** Site base URL for sitemap regeneration on rebuild (e.g. "https://example.com"). */
30
+ siteBaseUrl?: string;
27
31
  }
28
32
  declare function startRendererServer(options: RendererServerOptions): Promise<void>;
29
33
 
@@ -47,6 +51,8 @@ interface RebuildOptions {
47
51
  target: RebuildTarget;
48
52
  tsConfigFilePath?: string;
49
53
  minify?: boolean;
54
+ /** Site base URL for sitemap regeneration (e.g. "https://example.com"). */
55
+ siteBaseUrl?: string;
50
56
  }
51
57
  interface RebuildResult {
52
58
  affected: number;
@@ -69,7 +75,8 @@ declare function rebuildContract(options: {
69
75
  params?: Record<string, string>;
70
76
  tsConfigFilePath?: string;
71
77
  minify?: boolean;
78
+ siteBaseUrl?: string;
72
79
  }): Promise<RebuildResult>;
73
80
  declare function cleanupOrphanedFiles(buildRoot: string, version: string): Promise<number>;
74
81
 
75
- export { BuildOptions, type RebuildOptions, type RebuildResult, type RebuildTarget, type RendererServerOptions, RouteEntry, RouteManifest, buildVersion, cleanupOrphanedFiles, rebuild, rebuildContract, resolveContractToRoutes, startMainServer, startRendererServer };
82
+ export { BuildOptions, type RebuildOptions, type RebuildResult, type RebuildTarget, type RendererServerOptions, RouteEntry, RouteManifest, buildVersion, cleanupOrphanedFiles, generateSitemap, rebuild, rebuildContract, resolveContractToRoutes, startMainServer, startRendererServer };
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ import path from "node:path";
6
6
  import fs from "node:fs/promises";
7
7
  import { createRequire } from "node:module";
8
8
  import { DevSlowlyChangingPhase, slowRenderInstances, scanPlugins, runLoadParams, parseCookies } from "@jay-framework/stack-server-runtime";
9
- import { l as loadProductionPageParts, g as buildPagePartsConfig, d as initializeServices, r as registerActionsFromManifest, i as isActionRequest, a as fetchActionRequest, c as fetchStaticFile, m as matchRequest, f as fetchPageRequest, F as FilesystemArtifactStore } from "./init-services-AtDV4X1i.js";
10
- import { e, b } from "./init-services-AtDV4X1i.js";
9
+ import { l as loadProductionPageParts, g as buildPagePartsConfig, F as FilesystemArtifactStore, i as initializeServices, r as registerActionsFromManifest, d as isActionRequest, f as fetchActionRequest, b as fetchStaticFile, m as matchRequest, a as fetchPageRequest } from "./init-services-Dy2SiHzw.js";
10
+ import { c, e } from "./init-services-Dy2SiHzw.js";
11
11
  import crypto, { createHash } from "node:crypto";
12
12
  import fs$1 from "node:fs";
13
13
  import { jayRuntime } from "@jay-framework/vite-plugin";
@@ -18,8 +18,27 @@ import { transform } from "esbuild";
18
18
  import http from "node:http";
19
19
  import { Readable } from "node:stream";
20
20
  import { isJayWebhook } from "@jay-framework/fullstack-component";
21
- import "@jay-framework/view-state-merge";
22
- import "@jay-framework/ssr-runtime";
21
+ function isCompilableTypeScriptFile(fileName) {
22
+ return fileName.endsWith(".ts") && !fileName.endsWith(".d.ts") && fileName !== "page.ts";
23
+ }
24
+ async function collectTypeScriptEntries(rootDir, entryPrefix, pages) {
25
+ async function walk(currentDir, relativePath) {
26
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ const fullPath = path.join(currentDir, entry.name);
29
+ if (entry.isDirectory()) {
30
+ const nextRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
31
+ await walk(fullPath, nextRelative);
32
+ continue;
33
+ }
34
+ if (!isCompilableTypeScriptFile(entry.name)) continue;
35
+ const stem = entry.name.replace(/\.ts$/, "");
36
+ const entryName = relativePath ? `${entryPrefix}/${relativePath}/${stem}` : `${entryPrefix}/${stem}`;
37
+ pages[entryName] = fullPath;
38
+ }
39
+ }
40
+ await walk(rootDir, "");
41
+ }
23
42
  async function discoverServerEntries(projectRoot, pagesRoot) {
24
43
  const logger = getLogger();
25
44
  const routes = await scanRoutes(pagesRoot, {
@@ -49,18 +68,16 @@ async function discoverServerEntries(projectRoot, pagesRoot) {
49
68
  for (const subDir of ["plugins", "components"]) {
50
69
  const scanDir = path.join(projectRoot, "src", subDir);
51
70
  try {
52
- const dirs = await fs.readdir(scanDir, { withFileTypes: true });
53
- for (const dir of dirs) {
54
- if (!dir.isDirectory())
71
+ const entries2 = await fs.readdir(scanDir, { withFileTypes: true });
72
+ for (const entry of entries2) {
73
+ const entryPath = path.join(scanDir, entry.name);
74
+ if (entry.isDirectory()) {
75
+ await collectTypeScriptEntries(entryPath, `${subDir}/${entry.name}`, pages);
55
76
  continue;
56
- const dirPath = path.join(scanDir, dir.name);
57
- const files = await fs.readdir(dirPath);
58
- for (const file of files) {
59
- if (file.endsWith(".ts") && !file.endsWith(".d.ts") && file !== "page.ts") {
60
- const entryName = `${subDir}/${dir.name}/${file.replace(/\.ts$/, "")}`;
61
- pages[entryName] = path.join(dirPath, file);
62
- }
63
77
  }
78
+ if (!isCompilableTypeScriptFile(entry.name)) continue;
79
+ const stem = entry.name.replace(/\.ts$/, "");
80
+ pages[`${subDir}/${stem}`] = entryPath;
64
81
  }
65
82
  } catch {
66
83
  }
@@ -194,8 +211,7 @@ async function parseViteManifest(outputDir, packages) {
194
211
  }
195
212
  const manifest = {};
196
213
  for (const [, entry] of Object.entries(raw)) {
197
- if (!entry.isEntry)
198
- continue;
214
+ if (!entry.isEntry) continue;
199
215
  const outputBase = path.basename(entry.file, ".js");
200
216
  for (const [varName, pkg] of varNameToPackage) {
201
217
  if (outputBase.startsWith(varName)) {
@@ -218,8 +234,7 @@ function hashParams(params, suffix) {
218
234
  {}
219
235
  );
220
236
  const json = JSON.stringify(sorted);
221
- if (json === "{}" && !suffix)
222
- return "";
237
+ if (json === "{}" && !suffix) return "";
223
238
  const input = suffix ? json + ":" + suffix : json;
224
239
  return "_" + crypto.createHash("md5").update(input).digest("hex").substring(0, 8);
225
240
  }
@@ -245,7 +260,7 @@ async function buildInstance(route, params, pageModule, ctx, routeServerElementP
245
260
  );
246
261
  const contracts = [
247
262
  .../* @__PURE__ */ new Set([
248
- ...pageParts.headlessInstanceComponents.map((c) => c.contractName),
263
+ ...pageParts.headlessInstanceComponents.map((c2) => c2.contractName),
249
264
  ...pageParts.parts.filter((p) => p.contractInfo?.contractName).map((p) => p.contractInfo.contractName)
250
265
  ])
251
266
  ];
@@ -401,8 +416,7 @@ async function discoverActions(actionPaths, serverOutputDir, buildDir, projectRo
401
416
  try {
402
417
  const scannedPlugins = await scanPlugins({ projectRoot });
403
418
  for (const [packageName, plugin] of scannedPlugins) {
404
- if (plugin.isLocal)
405
- continue;
419
+ if (plugin.isLocal) continue;
406
420
  plugins.push({ name: plugin.manifest.name, packageName });
407
421
  const pluginActions = plugin.manifest.actions;
408
422
  if (pluginActions && pluginActions.length > 0) {
@@ -431,6 +445,47 @@ async function writeRouteManifest(manifest, buildDir) {
431
445
  `[Build] Route manifest written: ${manifest.routes.length} routes, ${manifest.routes.reduce((n, r) => n + r.instances.length, 0)} instances`
432
446
  );
433
447
  }
448
+ async function generateSitemap(manifest, baseUrl, outputPath) {
449
+ const base = baseUrl.replace(/\/$/, "");
450
+ const urls = [];
451
+ for (const route of manifest.routes) {
452
+ if (route.devOnly) continue;
453
+ if (route.noIndex) continue;
454
+ if (route.instances.length === 0) {
455
+ const hasDynamic = route.segments.some((s) => s.type !== "static");
456
+ if (!hasDynamic) {
457
+ const urlPath = route.pattern === "/" ? "/" : route.pattern;
458
+ urls.push(`${base}${urlPath}`);
459
+ }
460
+ continue;
461
+ }
462
+ for (const instance of route.instances) {
463
+ const urlPath = buildUrlFromManifest(route.pattern, instance.params);
464
+ urls.push(`${base}${urlPath}`);
465
+ }
466
+ }
467
+ const tmpPath = outputPath + ".tmp";
468
+ const handle = await fs.open(tmpPath, "w");
469
+ try {
470
+ await handle.write('<?xml version="1.0" encoding="UTF-8"?>\n');
471
+ await handle.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n');
472
+ for (const url of urls) {
473
+ await handle.write(` <url><loc>${escapeXml(url)}</loc></url>
474
+ `);
475
+ }
476
+ await handle.write("</urlset>\n");
477
+ } finally {
478
+ await handle.close();
479
+ }
480
+ await fs.rename(tmpPath, outputPath);
481
+ return urls.length;
482
+ }
483
+ function buildUrlFromManifest(pattern, params) {
484
+ return pattern.replace(/\[\[(\w+)\]\]/g, (_, name) => params[name] || "").replace(/\[\.\.\.(\w+)\]/g, (_, name) => params[name] || "").replace(/\[(\w+)\]/g, (_, name) => params[name] || "").replace(/\/\/+/g, "/").replace(/\/$/, "") || "/";
485
+ }
486
+ function escapeXml(str) {
487
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
488
+ }
434
489
  createRequire(import.meta.url);
435
490
  async function scanPluginRoutes(projectRoot, projectRoutes) {
436
491
  const logger = getLogger();
@@ -438,10 +493,8 @@ async function scanPluginRoutes(projectRoot, projectRoutes) {
438
493
  const projectPaths = new Set(projectRoutes.map((r) => r.rawRoute));
439
494
  const pluginRoutes = [];
440
495
  for (const [, plugin] of plugins) {
441
- if (plugin.isLocal)
442
- continue;
443
- if (!plugin.manifest.routes)
444
- continue;
496
+ if (plugin.isLocal) continue;
497
+ if (!plugin.manifest.routes) continue;
445
498
  for (const route of plugin.manifest.routes) {
446
499
  if (projectPaths.has(route.path)) {
447
500
  logger.info(
@@ -484,8 +537,7 @@ function resolvePluginExport(pluginPath, exportSubpath) {
484
537
  const exportValue = packageJson.exports[exportKey];
485
538
  if (exportValue) {
486
539
  const resolved = typeof exportValue === "string" ? exportValue : exportValue.default || exportValue.import || exportValue.require;
487
- if (resolved)
488
- return path.join(pluginPath, resolved);
540
+ if (resolved) return path.join(pluginPath, resolved);
489
541
  }
490
542
  }
491
543
  } catch {
@@ -508,8 +560,7 @@ function resolvePluginModule(pluginPath) {
508
560
  const mainPath = typeof mainExport === "string" ? mainExport : mainExport?.default || mainExport?.import || pkg.main;
509
561
  if (mainPath) {
510
562
  const resolved = path.join(pluginPath, mainPath);
511
- if (fs$1.existsSync(resolved))
512
- return resolved;
563
+ if (fs$1.existsSync(resolved)) return resolved;
513
564
  }
514
565
  } catch {
515
566
  }
@@ -633,8 +684,7 @@ async function compileRouteHydrateScript(jayHtmlPath, outputDir, projectRoot, ts
633
684
  const manifest = JSON.parse(await fs.readFile(manifestPath, "utf-8"));
634
685
  await fs.rm(manifestPath, { force: true });
635
686
  const entryKey = Object.keys(manifest).find((k) => manifest[k].isEntry);
636
- if (!entryKey)
637
- throw new Error("No entry in route hydrate manifest");
687
+ if (!entryKey) throw new Error("No entry in route hydrate manifest");
638
688
  const jsFile = manifest[entryKey].file;
639
689
  getLogger().info(`[Build] Compiled route hydrate script: ${jsFile}`);
640
690
  return { jsFile };
@@ -649,8 +699,7 @@ function resolveJayHtmlPaths(html, sourceDir, targetDir) {
649
699
  if (val && (val.startsWith("./") || val.startsWith("../"))) {
650
700
  const abs = path.resolve(sourceDir, val);
651
701
  let rel = path.relative(targetDir, abs);
652
- if (!rel.startsWith("."))
653
- rel = "./" + rel;
702
+ if (!rel.startsWith(".")) rel = "./" + rel;
654
703
  el.setAttribute(attr, rel);
655
704
  }
656
705
  };
@@ -781,10 +830,8 @@ async function buildInstanceClient(hydrateEntryPath, instanceId, outputDir, proj
781
830
  return result;
782
831
  }
783
832
  function crossProductParams(parts) {
784
- if (parts.length === 0)
785
- return [];
786
- if (parts.length === 1)
787
- return parts[0].values;
833
+ if (parts.length === 0) return [];
834
+ if (parts.length === 1) return parts[0].values;
788
835
  const logger = getLogger();
789
836
  for (let i = 0; i < parts.length; i++) {
790
837
  for (let j = i + 1; j < parts.length; j++) {
@@ -802,8 +849,8 @@ function crossProductParams(parts) {
802
849
  const next = parts[i].values;
803
850
  const combined = [];
804
851
  for (const a of result) {
805
- for (const b2 of next) {
806
- combined.push({ ...a, ...b2 });
852
+ for (const b of next) {
853
+ combined.push({ ...a, ...b });
807
854
  }
808
855
  }
809
856
  result = combined;
@@ -812,8 +859,7 @@ function crossProductParams(parts) {
812
859
  }
813
860
  function paramsMatchInferred(params, inferredParams, optionalSegments) {
814
861
  return Object.entries(inferredParams).every(([k, v]) => {
815
- if (optionalSegments?.has(k))
816
- return true;
862
+ if (optionalSegments?.has(k)) return true;
817
863
  return params[k] === v;
818
864
  });
819
865
  }
@@ -826,10 +872,8 @@ function computeSpecificity(route) {
826
872
  function buildUrl(route, params) {
827
873
  return route.rawRoute.replace(/\[\[(\w+)\]\]/g, (_, name) => {
828
874
  const value = params[name];
829
- if (!value)
830
- return "";
831
- if (route.inferredParams?.[name] === value)
832
- return "";
875
+ if (!value) return "";
876
+ if (route.inferredParams?.[name] === value) return "";
833
877
  return value;
834
878
  }).replace(/\[(\w+)\]/g, (_, name) => params[name] || "").replace(/\/\/+/g, "/").replace(/\/$/, "") || "/";
835
879
  }
@@ -886,8 +930,7 @@ async function discoverPluginClientPackages(projectRoot) {
886
930
  const seen = /* @__PURE__ */ new Set();
887
931
  const result = [];
888
932
  async function walk(pkgName) {
889
- if (seen.has(pkgName))
890
- return;
933
+ if (seen.has(pkgName)) return;
891
934
  seen.add(pkgName);
892
935
  try {
893
936
  const mainPath = projectRequire.resolve(pkgName);
@@ -991,7 +1034,19 @@ async function buildVersion(options) {
991
1034
  );
992
1035
  for (const pluginInit of pluginsWithInit) {
993
1036
  try {
994
- const pluginModule = await import(pluginInit.packageName);
1037
+ let modulePath;
1038
+ if (pluginInit.isLocal) {
1039
+ const pluginDirName = path.basename(pluginInit.pluginPath);
1040
+ modulePath = path.join(
1041
+ serverOutputDir,
1042
+ "plugins",
1043
+ pluginDirName,
1044
+ `${pluginInit.initModule}.js`
1045
+ );
1046
+ } else {
1047
+ modulePath = pluginInit.packageName;
1048
+ }
1049
+ const pluginModule = await import(modulePath);
995
1050
  const init = pluginModule.init || pluginModule[pluginInit.initExport || "init"];
996
1051
  if (init?._serverInit) {
997
1052
  logger.info(`[Build] Running plugin init: ${pluginInit.name}`);
@@ -1023,8 +1078,7 @@ async function buildVersion(options) {
1023
1078
  await discoverPluginsWithInit({ projectRoot: options.projectRoot })
1024
1079
  );
1025
1080
  for (const pluginInit of allPluginsWithInit) {
1026
- if (pluginInit.isLocal)
1027
- continue;
1081
+ if (pluginInit.isLocal) continue;
1028
1082
  const clientImportPath = `${pluginInit.packageName}/client`;
1029
1083
  try {
1030
1084
  const clientModule = await import(clientImportPath);
@@ -1089,10 +1143,8 @@ async function buildVersion(options) {
1089
1143
  logger.important(`[Build] ${instanceCount}/${totalExpected} ${routeName}${paramStr}`);
1090
1144
  }
1091
1145
  async function loadPageModule(entry) {
1092
- if (!entry.serverModule)
1093
- return {};
1094
- if (entry.isPlugin)
1095
- return import(entry.serverModule);
1146
+ if (!entry.serverModule) return {};
1147
+ if (entry.isPlugin) return import(entry.serverModule);
1096
1148
  return import(path.join(backendDir, entry.serverModule));
1097
1149
  }
1098
1150
  const routeInfos = routeEntries.map((re) => {
@@ -1108,8 +1160,7 @@ async function buildVersion(options) {
1108
1160
  const loadParamsCache = /* @__PURE__ */ new Map();
1109
1161
  const loadParamsResults = /* @__PURE__ */ new Map();
1110
1162
  for (const info of routeInfos) {
1111
- if (!info.hasDynamicParams)
1112
- continue;
1163
+ if (!info.hasDynamicParams) continue;
1113
1164
  const { route, entry } = info.routeEntry;
1114
1165
  let pageModule;
1115
1166
  try {
@@ -1127,8 +1178,7 @@ async function buildVersion(options) {
1127
1178
  serverOutputDir
1128
1179
  );
1129
1180
  const partsWithLoadParams = pageParts.parts.filter((p) => p.compDefinition?.loadParams);
1130
- if (partsWithLoadParams.length === 0)
1131
- continue;
1181
+ if (partsWithLoadParams.length === 0) continue;
1132
1182
  const paramParts = [];
1133
1183
  for (const part of partsWithLoadParams) {
1134
1184
  const propsKey = JSON.stringify(part.headlessProps ?? {});
@@ -1158,14 +1208,12 @@ async function buildVersion(options) {
1158
1208
  const byRoute = /* @__PURE__ */ new Map();
1159
1209
  for (const materialized2 of deduped) {
1160
1210
  const info = materialized2.route;
1161
- if (!byRoute.has(info))
1162
- byRoute.set(info, []);
1211
+ if (!byRoute.has(info)) byRoute.set(info, []);
1163
1212
  byRoute.get(info).push(materialized2.params);
1164
1213
  }
1165
1214
  for (const [info] of byRoute) {
1166
1215
  const { route, entry } = info.routeEntry;
1167
- if (!route.jayHtmlPath)
1168
- continue;
1216
+ if (!route.jayHtmlPath) continue;
1169
1217
  const routeDir = route.rawRoute.replace(/^\//, "") || "index";
1170
1218
  const frontendSafeRouteDir = routeDir.replace(/\[/g, "%5B").replace(/\]/g, "%5D");
1171
1219
  const backendRouteDir = path.join(backendDir, "pre-rendered", routeDir);
@@ -1198,6 +1246,12 @@ async function buildVersion(options) {
1198
1246
  }
1199
1247
  if (seResult.headMeta) {
1200
1248
  entry.headMeta = seResult.headMeta;
1249
+ const robotsMeta = seResult.headMeta.meta?.find(
1250
+ (m) => m.name === "robots" && m.content?.some((p) => p.kind === "static" && p.value.includes("noindex"))
1251
+ );
1252
+ if (robotsMeta) {
1253
+ entry.noIndex = true;
1254
+ }
1201
1255
  }
1202
1256
  logger.important(`[Build] Route server element: ${routeDir}`);
1203
1257
  } catch (err) {
@@ -1333,6 +1387,11 @@ async function buildVersion(options) {
1333
1387
  logger.info("[Build] Copied public/ contents to frontend/");
1334
1388
  } catch {
1335
1389
  }
1390
+ if (options.siteBaseUrl) {
1391
+ const sitemapPath = path.join(frontendDir, "sitemap.xml");
1392
+ const urlCount = await generateSitemap(manifest, options.siteBaseUrl, sitemapPath);
1393
+ logger.important(`[Build] Sitemap generated: ${urlCount} URLs`);
1394
+ }
1336
1395
  const sourceHash = await computeBuildHash(buildDir);
1337
1396
  const metadata = {
1338
1397
  version: options.version,
@@ -1354,8 +1413,7 @@ function toFetchRequest(req) {
1354
1413
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
1355
1414
  const headers = new Headers();
1356
1415
  for (const [key, value] of Object.entries(req.headers)) {
1357
- if (value)
1358
- headers.set(key, Array.isArray(value) ? value.join(", ") : value);
1416
+ if (value) headers.set(key, Array.isArray(value) ? value.join(", ") : value);
1359
1417
  }
1360
1418
  const init = { method: req.method, headers };
1361
1419
  if (req.method !== "GET" && req.method !== "HEAD") {
@@ -1375,8 +1433,7 @@ async function pipeFetchResponse(response, res) {
1375
1433
  try {
1376
1434
  while (true) {
1377
1435
  const { done, value } = await reader.read();
1378
- if (done)
1379
- break;
1436
+ if (done) break;
1380
1437
  res.write(value);
1381
1438
  }
1382
1439
  } finally {
@@ -1456,8 +1513,7 @@ async function startMainServer(options) {
1456
1513
  await pipeFetchResponse(response, res);
1457
1514
  } catch (err) {
1458
1515
  logger.error(`[Server] Error handling ${url.pathname}: ${err.message}`);
1459
- if (err.stack)
1460
- logger.error(err.stack);
1516
+ if (err.stack) logger.error(err.stack);
1461
1517
  if (!res.headersSent) {
1462
1518
  res.writeHead(500);
1463
1519
  res.end("Internal Server Error");
@@ -1483,11 +1539,9 @@ async function discoverWebhooks(projectRoot, serverBuildDir) {
1483
1539
  try {
1484
1540
  const plugins = await scanPlugins({ projectRoot });
1485
1541
  for (const [packageName, plugin] of plugins) {
1486
- if (plugin.isLocal)
1487
- continue;
1542
+ if (plugin.isLocal) continue;
1488
1543
  const declaredWebhooks = plugin.manifest.webhooks;
1489
- if (!declaredWebhooks || declaredWebhooks.length === 0)
1490
- continue;
1544
+ if (!declaredWebhooks || declaredWebhooks.length === 0) continue;
1491
1545
  try {
1492
1546
  const pluginModule = await import(packageName);
1493
1547
  for (const entry of declaredWebhooks) {
@@ -1519,11 +1573,9 @@ async function discoverWebhooks(projectRoot, serverBuildDir) {
1519
1573
  try {
1520
1574
  const plugins = await scanPlugins({ projectRoot });
1521
1575
  for (const [, plugin] of plugins) {
1522
- if (!plugin.isLocal)
1523
- continue;
1576
+ if (!plugin.isLocal) continue;
1524
1577
  const declaredWebhooks = plugin.manifest.webhooks;
1525
- if (!declaredWebhooks || declaredWebhooks.length === 0)
1526
- continue;
1578
+ if (!declaredWebhooks || declaredWebhooks.length === 0) continue;
1527
1579
  const pluginDirName = path.basename(plugin.pluginPath);
1528
1580
  for (const entry of declaredWebhooks) {
1529
1581
  const exportName = typeof entry === "string" ? entry : entry.name;
@@ -1554,8 +1606,7 @@ async function discoverWebhooks(projectRoot, serverBuildDir) {
1554
1606
  try {
1555
1607
  const files = await fs.readdir(webhooksDir);
1556
1608
  for (const file of files) {
1557
- if (!file.endsWith(".js"))
1558
- continue;
1609
+ if (!file.endsWith(".js")) continue;
1559
1610
  try {
1560
1611
  const mod = await import(path.join(webhooksDir, file));
1561
1612
  for (const [, value] of Object.entries(mod)) {
@@ -1690,6 +1741,11 @@ async function rebuild(options) {
1690
1741
  );
1691
1742
  }
1692
1743
  logger.important(`[Rebuild] Manifest and metadata updated`);
1744
+ if (options.siteBaseUrl) {
1745
+ const sitemapPath = path.join(frontendDir, "sitemap.xml");
1746
+ const urlCount = await generateSitemap(manifest, options.siteBaseUrl, sitemapPath);
1747
+ logger.info(`[Rebuild] Sitemap regenerated: ${urlCount} URLs`);
1748
+ }
1693
1749
  if (orphanedFiles.length > 0) {
1694
1750
  await appendCleanupManifest(buildDir, orphanedFiles);
1695
1751
  logger.info(`[Rebuild] ${orphanedFiles.length} orphaned file(s) queued for cleanup`);
@@ -1738,10 +1794,8 @@ async function rebuildContract(options) {
1738
1794
  });
1739
1795
  }
1740
1796
  async function loadRouteModule(route, buildDir) {
1741
- if (!route.serverModule)
1742
- return {};
1743
- if (route.isPlugin)
1744
- return import(route.serverModule);
1797
+ if (!route.serverModule) return {};
1798
+ if (route.isPlugin) return import(route.serverModule);
1745
1799
  return import(path.join(buildDir, route.serverModule));
1746
1800
  }
1747
1801
  async function resolveJayRouteFromManifest(route, options) {
@@ -1761,8 +1815,7 @@ async function resolveJayRouteFromManifest(route, options) {
1761
1815
  return {
1762
1816
  rawRoute: route.pattern,
1763
1817
  segments: route.segments.map((s) => {
1764
- if (s.type === "static")
1765
- return s.value;
1818
+ if (s.type === "static") return s.value;
1766
1819
  return { name: s.value, type: segmentTypeMap[s.type] };
1767
1820
  }),
1768
1821
  jayHtmlPath: resolvedJayHtmlPath,
@@ -1779,11 +1832,9 @@ function paramsMatch(instanceParams, targetParams) {
1779
1832
  return Object.entries(targetParams).every(([key, value]) => instanceParams[key] === value);
1780
1833
  }
1781
1834
  function collectInstanceFiles(instance) {
1782
- if (!instance.cachePath)
1783
- return [];
1835
+ if (!instance.cachePath) return [];
1784
1836
  const files = [instance.cachePath, instance.serverElementPath, instance.clientBundlePath];
1785
- if (instance.clientCssPath)
1786
- files.push(instance.clientCssPath);
1837
+ if (instance.clientCssPath) files.push(instance.clientCssPath);
1787
1838
  return files.filter(Boolean);
1788
1839
  }
1789
1840
  async function appendCleanupManifest(buildDir, files) {
@@ -1843,7 +1894,8 @@ async function startRendererServer(options) {
1843
1894
  contractName,
1844
1895
  params,
1845
1896
  tsConfigFilePath: options.tsConfigFilePath,
1846
- minify: options.minify
1897
+ minify: options.minify,
1898
+ siteBaseUrl: options.siteBaseUrl
1847
1899
  });
1848
1900
  };
1849
1901
  };
@@ -1902,7 +1954,8 @@ async function startRendererServer(options) {
1902
1954
  version: options.version,
1903
1955
  target,
1904
1956
  tsConfigFilePath: options.tsConfigFilePath,
1905
- minify: options.minify
1957
+ minify: options.minify,
1958
+ siteBaseUrl: options.siteBaseUrl
1906
1959
  });
1907
1960
  res.writeHead(200, { "Content-Type": "application/json" });
1908
1961
  res.end(JSON.stringify(result));
@@ -1958,14 +2011,15 @@ export {
1958
2011
  fetchActionRequest,
1959
2012
  fetchPageRequest,
1960
2013
  fetchStaticFile,
2014
+ generateSitemap,
1961
2015
  initializeServices,
1962
- e as initializeServicesFromModules,
2016
+ c as initializeServicesFromModules,
1963
2017
  isActionRequest,
1964
2018
  matchRequest,
1965
2019
  rebuild,
1966
2020
  rebuildContract,
1967
2021
  registerActionsFromManifest,
1968
- b as registerActionsFromModules,
2022
+ e as registerActionsFromModules,
1969
2023
  resolveContractToRoutes,
1970
2024
  startMainServer,
1971
2025
  startRendererServer
@@ -1,9 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
4
  import fs from "node:fs/promises";
8
5
  import path from "node:path";
9
6
  import { renderFastChangingData, headMetaToHeadTags, mergeHeadTags, serializeHeadTags, getClientInitData, actionRegistry, setClientInitData } from "@jay-framework/stack-server-runtime";
@@ -14,7 +11,7 @@ import { getLogger } from "@jay-framework/logger";
14
11
  import { parseJayFile, JAY_IMPORT_RESOLVER, injectHeadfullFSTemplates, assignCoordinatesToJayHtml, discoverHeadlessInstances } from "@jay-framework/compiler-jay-html";
15
12
  import { checkValidationErrors } from "@jay-framework/compiler-shared";
16
13
  import { isJayAction, isJayStreamAction } from "@jay-framework/fullstack-component";
17
- const require2 = createRequire(import.meta.url);
14
+ const require$1 = createRequire(import.meta.url);
18
15
  async function loadProductionPageParts(route, pageModule, jayHtmlContent, projectRoot, tsConfigFilePath, serverBuildDir) {
19
16
  const exportName = route.componentExport || "page";
20
17
  const compDefinition = pageModule[exportName] ?? pageModule.default;
@@ -68,7 +65,7 @@ async function loadProductionPageParts(route, pageModule, jayHtmlContent, projec
68
65
  if (headlessImport.structural) {
69
66
  continue;
70
67
  } else {
71
- const resolvedModulePath = isLocalModule ? modulePath : require2.resolve(module, { paths: [dirName] });
68
+ const resolvedModulePath = isLocalModule ? modulePath : require$1.resolve(module, { paths: [dirName] });
72
69
  const headlessModule = await import(resolvedModulePath);
73
70
  headlessCompDef = headlessModule[name];
74
71
  }
@@ -221,8 +218,7 @@ async function loadPagePartsFromConfig(configPath, artifacts) {
221
218
  const serveTimeContract = {
222
219
  props: entry.propNames.map((name) => ({ name }))
223
220
  };
224
- if (entry.structural)
225
- continue;
221
+ if (entry.structural) continue;
226
222
  const mod = await importModule(entry);
227
223
  headlessInstanceComponents.push({
228
224
  contractName: entry.contractName,
@@ -296,8 +292,7 @@ class FilesystemArtifactStore {
296
292
  this.moduleCache.set(modulePath, { module: mod, mtime: stat.mtimeMs });
297
293
  return mod;
298
294
  } catch {
299
- if (local)
300
- throw new Error(`Local module not found: ${fullPath}`);
295
+ if (local) throw new Error(`Local module not found: ${fullPath}`);
301
296
  }
302
297
  }
303
298
  return import(modulePath);
@@ -327,8 +322,7 @@ function matchSegments(routeSegments, urlSegments) {
327
322
  }
328
323
  urlIdx++;
329
324
  } else if (seg.type === "param") {
330
- if (urlIdx >= urlSegments.length)
331
- return void 0;
325
+ if (urlIdx >= urlSegments.length) return void 0;
332
326
  params[seg.value] = urlSegments[urlIdx];
333
327
  urlIdx++;
334
328
  } else if (seg.type === "optional") {
@@ -337,8 +331,7 @@ function matchSegments(routeSegments, urlSegments) {
337
331
  urlIdx++;
338
332
  }
339
333
  } else if (seg.type === "catchAll") {
340
- if (urlIdx >= urlSegments.length)
341
- return void 0;
334
+ if (urlIdx >= urlSegments.length) return void 0;
342
335
  params[seg.value] = urlSegments.slice(urlIdx).join("/");
343
336
  urlIdx = urlSegments.length;
344
337
  } else if (seg.type === "optionalCatchAll") {
@@ -348,8 +341,7 @@ function matchSegments(routeSegments, urlSegments) {
348
341
  }
349
342
  }
350
343
  }
351
- if (urlIdx !== urlSegments.length)
352
- return void 0;
344
+ if (urlIdx !== urlSegments.length) return void 0;
353
345
  return params;
354
346
  }
355
347
  function findInstance(route, params) {
@@ -360,10 +352,8 @@ function findInstance(route, params) {
360
352
  for (const name of paramNames) {
361
353
  const urlVal = params[name];
362
354
  const instVal = instance.params[name];
363
- if (urlVal === void 0 && instVal === void 0)
364
- continue;
365
- if (urlVal !== instVal)
366
- return false;
355
+ if (urlVal === void 0 && instVal === void 0) continue;
356
+ if (urlVal !== instVal) return false;
367
357
  }
368
358
  return true;
369
359
  });
@@ -379,8 +369,7 @@ const pagePartsCache = /* @__PURE__ */ new Map();
379
369
  async function getPageParts(route, artifacts, cachePath) {
380
370
  const cacheKey = route.pattern;
381
371
  const cached = pagePartsCache.get(cacheKey);
382
- if (cached)
383
- return cached;
372
+ if (cached) return cached;
384
373
  const routeDir = path.dirname(cachePath);
385
374
  const configRelPath = path.join(routeDir, "page-parts.json");
386
375
  const parts = await loadPagePartsFromConfig(configRelPath, artifacts);
@@ -443,13 +432,10 @@ async function fetchPageRequest(match, manifest, requestUrl, artifacts, staticBa
443
432
  };
444
433
  const headTagSources = [];
445
434
  const slowHeadTags = cf.__slowHeadTags;
446
- if (slowHeadTags)
447
- headTagSources.push(...slowHeadTags);
448
- if (fastResult.headTags)
449
- headTagSources.push(fastResult.headTags);
435
+ if (slowHeadTags) headTagSources.push(...slowHeadTags);
436
+ if (fastResult.headTags) headTagSources.push(fastResult.headTags);
450
437
  const templateHeadTags = headMetaToHeadTags(route.headMeta, fullViewState);
451
- if (templateHeadTags.length > 0)
452
- headTagSources.push(templateHeadTags);
438
+ if (templateHeadTags.length > 0) headTagSources.push(templateHeadTags);
453
439
  const headTags = headTagSources.length > 0 ? mergeHeadTags(headTagSources) : [];
454
440
  const hasCustomTitle = headTags.some((t) => t.tag?.toLowerCase() === "title");
455
441
  const titleTag = hasCustomTitle ? "" : " <title>Vite + TS</title>\n";
@@ -509,8 +495,7 @@ ${headParts}
509
495
  const tSsr = Date.now();
510
496
  write("</div>");
511
497
  const asyncScripts = (await Promise.all(asyncPromises)).filter((s) => s).join("");
512
- if (asyncScripts)
513
- write(asyncScripts);
498
+ if (asyncScripts) write(asyncScripts);
514
499
  const clientInitData = getClientInitData();
515
500
  const initArgs = route.routeClientBundlePath ? `${JSON.stringify(fullSlowViewState)}, ${JSON.stringify(fastViewState)}, ${JSON.stringify(fastCarryForward)}, ${JSON.stringify(clientInitData)}` : `${JSON.stringify(fastViewState)}, ${JSON.stringify(fastCarryForward)}, ${JSON.stringify(clientInitData)}`;
516
501
  const tTotal = Date.now() - t0;
@@ -518,7 +503,6 @@ ${headParts}
518
503
  const serverTiming = {
519
504
  cache: tCache,
520
505
  parts: tParts,
521
- data: tData - t0,
522
506
  fast: tFast - tData,
523
507
  load: tLoadMs,
524
508
  ssr: tSsr - tSsrStart,
@@ -697,8 +681,7 @@ async function registerActionsFromModules(modules, registry = actionRegistry) {
697
681
  logger.info(`[Server] Registered ${count} actions from pre-imported modules`);
698
682
  }
699
683
  function getStatusCode(code, isActionError) {
700
- if (isActionError)
701
- return 422;
684
+ if (isActionError) return 422;
702
685
  switch (code) {
703
686
  case "ACTION_NOT_FOUND":
704
687
  return 404;
@@ -727,21 +710,22 @@ const MIME_TYPES = {
727
710
  ".woff2": "font/woff2",
728
711
  ".woff": "font/woff",
729
712
  ".ttf": "font/ttf",
730
- ".webp": "image/webp"
713
+ ".webp": "image/webp",
714
+ ".xml": "application/xml",
715
+ ".txt": "text/plain"
731
716
  };
732
717
  async function fetchStaticFile(pathname, frontendDir) {
733
718
  const normalizedBase = path.resolve(frontendDir);
734
719
  for (const candidate of [path.join(frontendDir, pathname)]) {
735
720
  const normalizedFile = path.resolve(candidate);
736
- if (!normalizedFile.startsWith(normalizedBase))
737
- continue;
721
+ if (!normalizedFile.startsWith(normalizedBase)) continue;
738
722
  try {
739
723
  const content = await fs.readFile(candidate);
740
724
  const ext = path.extname(candidate);
741
725
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
742
726
  const isHashed = /[-][a-zA-Z0-9_-]{6,}\./.test(path.basename(candidate));
743
727
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
744
- return new Response(content, {
728
+ return new Response(new Uint8Array(content), {
745
729
  headers: {
746
730
  "Content-Type": contentType,
747
731
  "Content-Length": String(content.length),
@@ -760,8 +744,7 @@ async function initializeServicesFromModules(plugins, label) {
760
744
  if (plugin.init?._serverInit) {
761
745
  logger.info(`[${label}] Running plugin init: ${plugin.name}`);
762
746
  const data = await plugin.init._serverInit();
763
- if (data)
764
- setClientInitData(plugin.name, data);
747
+ if (data) setClientInitData(plugin.name, data);
765
748
  }
766
749
  } catch (err) {
767
750
  logger.warn(`[${label}] Plugin init failed: ${plugin.name}: ${err.message}`);
@@ -796,8 +779,7 @@ async function initializeServices(buildDir, projectRoot, label) {
796
779
  if (init?._serverInit) {
797
780
  logger.info(`[${label}] Running plugin init: ${pluginInit.name}`);
798
781
  const data = await init._serverInit();
799
- if (data)
800
- setClientInitData(pluginInit.name, data);
782
+ if (data) setClientInitData(pluginInit.name, data);
801
783
  }
802
784
  } catch (err) {
803
785
  logger.warn(`[${label}] Plugin init failed: ${pluginInit.name}: ${err.message}`);
@@ -812,22 +794,21 @@ async function initializeServices(buildDir, projectRoot, label) {
812
794
  if (init?._serverInit) {
813
795
  logger.info(`[${label}] Running server init...`);
814
796
  const data = await init._serverInit();
815
- if (data)
816
- setClientInitData("project", data);
797
+ if (data) setClientInitData("project", data);
817
798
  }
818
799
  } catch {
819
800
  }
820
801
  }
821
802
  export {
822
803
  FilesystemArtifactStore as F,
823
- fetchActionRequest as a,
824
- registerActionsFromModules as b,
825
- fetchStaticFile as c,
826
- initializeServices as d,
827
- initializeServicesFromModules as e,
828
- fetchPageRequest as f,
804
+ fetchPageRequest as a,
805
+ fetchStaticFile as b,
806
+ initializeServicesFromModules as c,
807
+ isActionRequest as d,
808
+ registerActionsFromModules as e,
809
+ fetchActionRequest as f,
829
810
  buildPagePartsConfig as g,
830
- isActionRequest as i,
811
+ initializeServices as i,
831
812
  loadProductionPageParts as l,
832
813
  matchRequest as m,
833
814
  registerActionsFromManifest as r
@@ -33,6 +33,8 @@ interface RouteEntry {
33
33
  cssImports?: string[];
34
34
  /** Head metadata from jay-html <head> (title, meta tags). */
35
35
  headMeta?: JayHtmlHeadMeta;
36
+ /** True when page has static <meta name="robots" content="noindex"> */
37
+ noIndex?: boolean;
36
38
  instances: InstanceEntry[];
37
39
  isPlugin?: boolean;
38
40
  pluginName?: string;
@@ -75,6 +77,8 @@ interface BuildOptions {
75
77
  concurrency: number;
76
78
  tsConfigFilePath: string;
77
79
  minify?: boolean;
80
+ /** Site base URL for sitemap generation (e.g. "https://example.com"). */
81
+ siteBaseUrl?: string;
78
82
  }
79
83
  interface ServerElementModule {
80
84
  renderToStream: (vs: object, ctx: _jay_framework_ssr_runtime.ServerRenderContext) => void;
@@ -183,4 +187,4 @@ interface PreImportedPlugin {
183
187
  declare function initializeServicesFromModules(plugins: PreImportedPlugin[], label: string): Promise<void>;
184
188
  declare function initializeServices(buildDir: string, projectRoot: string, label: string): Promise<void>;
185
189
 
186
- export { type ActionEntry as A, type BuildOptions as B, type CacheEntry as C, FilesystemArtifactStore as F, type InstanceEntry as I, type MatchResult as M, type PluginEntry as P, type RouteManifest as R, type ServerElementModule as S, type RouteEntry as a, type RouteSegment as b, type BuildMetadata as c, type PageModule as d, type ArtifactStore as e, fetchPageRequest as f, fetchActionRequest as g, registerActionsFromModules as h, isActionRequest as i, fetchStaticFile as j, initializeServices as k, initializeServicesFromModules as l, matchRequest as m, type PreImportedPlugin as n, registerActionsFromManifest as r };
190
+ export { type ActionEntry as A, type BuildOptions as B, type CacheEntry as C, FilesystemArtifactStore as F, type InstanceEntry as I, type MatchResult as M, type PageModule as P, type RouteManifest as R, type ServerElementModule as S, type RouteEntry as a, type ArtifactStore as b, type BuildMetadata as c, type PluginEntry as d, type PreImportedPlugin as e, type RouteSegment as f, fetchActionRequest as g, fetchPageRequest as h, fetchStaticFile as i, initializeServices as j, initializeServicesFromModules as k, isActionRequest as l, matchRequest as m, registerActionsFromModules as n, registerActionsFromManifest as r };
@@ -1,4 +1,4 @@
1
- export { e as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, n as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, f as fetchPageRequest, j as fetchStaticFile, k as initializeServices, l as initializeServicesFromModules, i as isActionRequest, m as matchRequest, r as registerActionsFromManifest, h as registerActionsFromModules } from './serve-index-XSavezh8.js';
1
+ export { b as ArtifactStore, C as CacheEntry, F as FilesystemArtifactStore, I as InstanceEntry, M as MatchResult, e as PreImportedPlugin, a as RouteEntry, R as RouteManifest, S as ServerElementModule, g as fetchActionRequest, h as fetchPageRequest, i as fetchStaticFile, j as initializeServices, k as initializeServicesFromModules, l as isActionRequest, m as matchRequest, r as registerActionsFromManifest, n as registerActionsFromModules } from './serve-index-cRXZm8vQ.js';
2
2
  import '@jay-framework/ssr-runtime';
3
3
  import '@jay-framework/compiler-shared';
4
4
  import '@jay-framework/stack-server-runtime';
@@ -1,23 +1,13 @@
1
- import { F, a, f, c, d, e, i, m, r, b } from "./init-services-AtDV4X1i.js";
2
- import "node:fs/promises";
3
- import "node:path";
4
- import "@jay-framework/stack-server-runtime";
5
- import "@jay-framework/view-state-merge";
6
- import "@jay-framework/ssr-runtime";
7
- import "node:module";
8
- import "@jay-framework/logger";
9
- import "@jay-framework/compiler-jay-html";
10
- import "@jay-framework/compiler-shared";
11
- import "@jay-framework/fullstack-component";
1
+ import { F, f, a, b, i, c, d, m, r, e } from "./init-services-Dy2SiHzw.js";
12
2
  export {
13
3
  F as FilesystemArtifactStore,
14
- a as fetchActionRequest,
15
- f as fetchPageRequest,
16
- c as fetchStaticFile,
17
- d as initializeServices,
18
- e as initializeServicesFromModules,
19
- i as isActionRequest,
4
+ f as fetchActionRequest,
5
+ a as fetchPageRequest,
6
+ b as fetchStaticFile,
7
+ i as initializeServices,
8
+ c as initializeServicesFromModules,
9
+ d as isActionRequest,
20
10
  m as matchRequest,
21
11
  r as registerActionsFromManifest,
22
- b as registerActionsFromModules
12
+ e as registerActionsFromModules
23
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/production-server",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,20 +30,20 @@
30
30
  "test:watch": "vitest"
31
31
  },
32
32
  "dependencies": {
33
- "@jay-framework/compiler-jay-html": "^0.23.0",
34
- "@jay-framework/compiler-jay-stack": "^0.23.0",
35
- "@jay-framework/compiler-shared": "^0.23.0",
36
- "@jay-framework/fullstack-component": "^0.23.0",
37
- "@jay-framework/logger": "^0.23.0",
38
- "@jay-framework/ssr-runtime": "^0.23.0",
39
- "@jay-framework/stack-route-scanner": "^0.23.0",
40
- "@jay-framework/stack-server-runtime": "^0.23.0",
41
- "@jay-framework/view-state-merge": "^0.23.0",
42
- "@jay-framework/vite-plugin": "^0.23.0",
33
+ "@jay-framework/compiler-jay-html": "^0.24.0",
34
+ "@jay-framework/compiler-jay-stack": "^0.24.0",
35
+ "@jay-framework/compiler-shared": "^0.24.0",
36
+ "@jay-framework/fullstack-component": "^0.24.0",
37
+ "@jay-framework/logger": "^0.24.0",
38
+ "@jay-framework/ssr-runtime": "^0.24.0",
39
+ "@jay-framework/stack-route-scanner": "^0.24.0",
40
+ "@jay-framework/stack-server-runtime": "^0.24.0",
41
+ "@jay-framework/view-state-merge": "^0.24.0",
42
+ "@jay-framework/vite-plugin": "^0.24.0",
43
43
  "vite": "^5.0.11"
44
44
  },
45
45
  "devDependencies": {
46
- "@jay-framework/dev-environment": "^0.23.0",
46
+ "@jay-framework/dev-environment": "^0.24.0",
47
47
  "@types/node": "^22.15.21",
48
48
  "rimraf": "^5.0.5",
49
49
  "tsup": "^8.0.1",