@vertz/ui-server 0.2.25 → 0.2.26

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.js CHANGED
@@ -35,6 +35,62 @@ import {
35
35
  toVNode
36
36
  } from "./shared/chunk-gcwqkynf.js";
37
37
 
38
+ // src/aot-manifest-build.ts
39
+ import { readdirSync, readFileSync } from "node:fs";
40
+ import { join } from "node:path";
41
+ import { compileForSSRAot } from "@vertz/ui-compiler";
42
+ function generateAotBuildManifest(srcDir) {
43
+ const components = {};
44
+ const classificationLog = [];
45
+ const tsxFiles = collectTsxFiles(srcDir);
46
+ for (const filePath of tsxFiles) {
47
+ try {
48
+ const source = readFileSync(filePath, "utf-8");
49
+ const result = compileForSSRAot(source, { filename: filePath });
50
+ for (const comp of result.components) {
51
+ components[comp.name] = {
52
+ tier: comp.tier,
53
+ holes: comp.holes
54
+ };
55
+ }
56
+ } catch (e) {
57
+ classificationLog.push(`⚠ ${filePath}: ${e instanceof Error ? e.message : "compilation failed"}`);
58
+ }
59
+ }
60
+ let aotCount = 0;
61
+ let runtimeCount = 0;
62
+ for (const [name, entry] of Object.entries(components)) {
63
+ let line = `${name}: ${entry.tier}`;
64
+ if (entry.holes.length > 0) {
65
+ const holeLabel = entry.holes.length === 1 ? "hole" : "holes";
66
+ line += `, ${entry.holes.length} ${holeLabel} (${entry.holes.join(", ")})`;
67
+ }
68
+ classificationLog.push(line);
69
+ if (entry.tier === "runtime-fallback") {
70
+ runtimeCount++;
71
+ } else {
72
+ aotCount++;
73
+ }
74
+ }
75
+ const total = aotCount + runtimeCount;
76
+ if (total > 0) {
77
+ const pct = Math.round(aotCount / total * 100);
78
+ classificationLog.push(`Coverage: ${aotCount}/${total} components (${pct}%)`);
79
+ }
80
+ return { components, classificationLog };
81
+ }
82
+ function collectTsxFiles(dir) {
83
+ const files = [];
84
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
85
+ const fullPath = join(dir, entry.name);
86
+ if (entry.isDirectory()) {
87
+ files.push(...collectTsxFiles(fullPath));
88
+ } else if (entry.name.endsWith(".tsx")) {
89
+ files.push(fullPath);
90
+ }
91
+ }
92
+ return files;
93
+ }
38
94
  // src/asset-pipeline.ts
39
95
  function renderAssetTags(assets) {
40
96
  if (assets.length === 0)
@@ -63,7 +119,7 @@ function inlineCriticalCss(css) {
63
119
  // src/font-metrics.ts
64
120
  import { access as fsAccess } from "node:fs/promises";
65
121
  import { readFile } from "node:fs/promises";
66
- import { join } from "node:path";
122
+ import { join as join2 } from "node:path";
67
123
  import { fromBuffer } from "@capsizecss/unpack";
68
124
  var SYSTEM_FONT_METRICS = {
69
125
  Arial: {
@@ -132,12 +188,12 @@ function getPrimarySrcPath(descriptor) {
132
188
  }
133
189
  async function resolveFilePath(urlPath, rootDir) {
134
190
  const cleaned = urlPath.startsWith("/") ? urlPath.slice(1) : urlPath;
135
- const direct = join(rootDir, cleaned);
191
+ const direct = join2(rootDir, cleaned);
136
192
  try {
137
193
  await fsAccess(direct);
138
194
  return direct;
139
195
  } catch {
140
- return join(rootDir, "public", cleaned);
196
+ return join2(rootDir, "public", cleaned);
141
197
  }
142
198
  }
143
199
  async function extractFontMetrics(fonts, rootDir) {
@@ -467,144 +523,168 @@ function evaluateAccessRule(rule, session) {
467
523
  return false;
468
524
  }
469
525
  }
470
- // src/ssr-html.ts
471
- function generateSSRHtml(options) {
472
- const {
473
- appHtml,
474
- css,
475
- ssrData,
476
- clientEntry,
477
- title = "Vertz App",
478
- headTags: rawHeadTags = "",
479
- modulepreload
480
- } = options;
481
- const modulepreloadTags = modulepreload?.length ? modulepreload.map((p) => `<link rel="modulepreload" href="${escapeAttr(p)}">`).join(`
482
- `) : "";
483
- const headTags = [rawHeadTags, modulepreloadTags].filter(Boolean).join(`
484
- `);
485
- const ssrDataScript = ssrData.length > 0 ? `<script>window.__VERTZ_SSR_DATA__ = ${JSON.stringify(ssrData)};</script>` : "";
486
- return `<!doctype html>
487
- <html lang="en">
488
- <head>
489
- <meta charset="UTF-8" />
490
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
491
- <title>${escapeHtml(title)}</title>
492
- ${headTags}
493
- ${css}
494
- </head>
495
- <body>
496
- <div id="app">${appHtml}</div>
497
- ${ssrDataScript}
498
- <script type="module" src="${escapeAttr(clientEntry)}"></script>
499
- </body>
500
- </html>`;
501
- }
502
- // src/ssr-prefetch-dev.ts
503
- import {
504
- analyzeComponentQueries,
505
- generatePrefetchManifest
506
- } from "@vertz/ui-compiler";
507
- function createPrefetchManifestManager(options) {
508
- const { routerPath, readFile: readFile2, resolveImport } = options;
509
- let currentManifest = null;
510
- let currentSSRManifest;
511
- let rebuildCount = 0;
512
- let lastRebuildMs = null;
513
- let lastRebuildAt = null;
514
- let fileToRouteIndices = new Map;
515
- function buildFileIndex(routes) {
516
- const index = new Map;
517
- for (let i = 0;i < routes.length; i++) {
518
- const file = routes[i]?.file;
519
- if (file) {
520
- const existing = index.get(file) ?? [];
521
- existing.push(i);
522
- index.set(file, existing);
526
+ // src/ssr-aot-diagnostics.ts
527
+ var MAX_DIVERGENCES = 20;
528
+
529
+ class AotDiagnostics {
530
+ _components = new Map;
531
+ _divergences = [];
532
+ recordCompilation(components) {
533
+ for (const comp of components) {
534
+ this._components.set(comp.name, {
535
+ tier: comp.tier,
536
+ holes: comp.holes
537
+ });
538
+ }
539
+ }
540
+ recordDivergence(component, aotHtml, domHtml) {
541
+ this._divergences.push({
542
+ component,
543
+ aotHtml,
544
+ domHtml,
545
+ timestamp: new Date().toISOString()
546
+ });
547
+ if (this._divergences.length > MAX_DIVERGENCES) {
548
+ this._divergences = this._divergences.slice(this._divergences.length - MAX_DIVERGENCES);
549
+ }
550
+ }
551
+ clear() {
552
+ this._components.clear();
553
+ this._divergences = [];
554
+ }
555
+ clearComponents() {
556
+ this._components.clear();
557
+ }
558
+ getClassificationLog() {
559
+ const lines = [];
560
+ for (const [name, comp] of this._components) {
561
+ let line = `${name}: ${comp.tier}`;
562
+ if (comp.holes.length > 0) {
563
+ line += `, ${comp.holes.length} hole${comp.holes.length > 1 ? "s" : ""} (${comp.holes.join(", ")})`;
523
564
  }
565
+ lines.push(line);
524
566
  }
525
- return index;
567
+ const snapshot = this.getSnapshot();
568
+ const { total, aot, percentage } = snapshot.coverage;
569
+ if (total > 0) {
570
+ lines.push(`Coverage: ${aot}/${total} components (${percentage}%)`);
571
+ }
572
+ return lines;
526
573
  }
527
- function toSSRManifest(manifest) {
528
- const routeEntries = {};
529
- for (const route of manifest.routes) {
530
- const existing = routeEntries[route.pattern];
531
- if (existing) {
532
- existing.queries.push(...route.queries);
574
+ getSnapshot() {
575
+ let aot = 0;
576
+ let runtime = 0;
577
+ for (const comp of this._components.values()) {
578
+ if (comp.tier === "runtime-fallback") {
579
+ runtime++;
533
580
  } else {
534
- routeEntries[route.pattern] = { queries: [...route.queries] };
581
+ aot++;
535
582
  }
536
583
  }
584
+ const total = aot + runtime;
537
585
  return {
538
- routePatterns: [...new Set(manifest.routes.map((r) => r.pattern))],
539
- routeEntries
586
+ components: Object.fromEntries(this._components),
587
+ coverage: {
588
+ total,
589
+ aot,
590
+ runtime,
591
+ percentage: total === 0 ? 0 : Math.round(aot / total * 100)
592
+ },
593
+ divergences: [...this._divergences]
540
594
  };
541
595
  }
542
- function fullBuild(routerSourceOverride) {
596
+ }
597
+ // src/ssr-aot-manifest-dev.ts
598
+ import { compileForSSRAot as compileForSSRAot2 } from "@vertz/ui-compiler";
599
+ function createAotManifestManager(options) {
600
+ const { readFile: readFile2, listFiles } = options;
601
+ let currentManifest = null;
602
+ const diagnostics = new AotDiagnostics;
603
+ let rebuildCount = 0;
604
+ let lastRebuildMs = null;
605
+ let lastRebuildAt = null;
606
+ function compileFile(filePath, source) {
607
+ try {
608
+ const result = compileForSSRAot2(source, { filename: filePath });
609
+ return result.components.map((comp) => ({
610
+ name: comp.name,
611
+ entry: {
612
+ tier: comp.tier,
613
+ holes: comp.holes,
614
+ file: filePath
615
+ }
616
+ }));
617
+ } catch {
618
+ return [];
619
+ }
620
+ }
621
+ function updateDiagnostics(manifest, isFullBuild) {
622
+ if (isFullBuild) {
623
+ diagnostics.clear();
624
+ } else {
625
+ diagnostics.clearComponents();
626
+ }
627
+ const entries = Object.entries(manifest.components).map(([name, entry]) => ({
628
+ name,
629
+ tier: entry.tier,
630
+ holes: entry.holes
631
+ }));
632
+ diagnostics.recordCompilation(entries);
633
+ }
634
+ function fullBuild() {
543
635
  const start = performance.now();
544
- const routerSource = routerSourceOverride ?? readFile2(routerPath);
545
- if (!routerSource) {
546
- return;
636
+ const files = listFiles();
637
+ const components = {};
638
+ for (const filePath of files) {
639
+ if (!filePath.endsWith(".tsx"))
640
+ continue;
641
+ const source = readFile2(filePath);
642
+ if (!source)
643
+ continue;
644
+ const entries = compileFile(filePath, source);
645
+ for (const { name, entry } of entries) {
646
+ components[name] = entry;
647
+ }
547
648
  }
548
- try {
549
- const manifest = generatePrefetchManifest({
550
- routerSource,
551
- routerPath,
552
- readFile: readFile2,
553
- resolveImport
554
- });
555
- currentManifest = manifest;
556
- currentSSRManifest = toSSRManifest(manifest);
557
- fileToRouteIndices = buildFileIndex(manifest.routes);
558
- rebuildCount++;
559
- lastRebuildMs = Math.round(performance.now() - start);
560
- lastRebuildAt = new Date().toISOString();
561
- } catch {}
649
+ currentManifest = { components };
650
+ updateDiagnostics(currentManifest, true);
651
+ rebuildCount++;
652
+ lastRebuildMs = Math.round(performance.now() - start);
653
+ lastRebuildAt = new Date().toISOString();
562
654
  }
563
655
  function incrementalUpdate(filePath, sourceText) {
564
656
  if (!currentManifest)
565
657
  return;
566
- const indices = fileToRouteIndices.get(filePath);
567
- if (!indices || indices.length === 0)
568
- return;
569
658
  const start = performance.now();
570
- try {
571
- const analysis = analyzeComponentQueries(sourceText, filePath);
572
- const newRoutes = [...currentManifest.routes];
573
- for (const idx of indices) {
574
- const existing = newRoutes[idx];
575
- if (existing) {
576
- newRoutes[idx] = {
577
- ...existing,
578
- queries: analysis.queries,
579
- params: analysis.params
580
- };
581
- }
659
+ const newComponents = { ...currentManifest.components };
660
+ for (const [name, entry] of Object.entries(newComponents)) {
661
+ if (entry.file === filePath) {
662
+ delete newComponents[name];
582
663
  }
583
- const newManifest = {
584
- ...currentManifest,
585
- routes: newRoutes,
586
- generatedAt: new Date().toISOString()
587
- };
588
- currentManifest = newManifest;
589
- currentSSRManifest = toSSRManifest(newManifest);
590
- rebuildCount++;
591
- lastRebuildMs = Math.round(performance.now() - start);
592
- lastRebuildAt = new Date().toISOString();
593
- } catch {}
664
+ }
665
+ if (sourceText.trim()) {
666
+ const entries = compileFile(filePath, sourceText);
667
+ for (const { name, entry } of entries) {
668
+ newComponents[name] = entry;
669
+ }
670
+ }
671
+ currentManifest = { components: newComponents };
672
+ updateDiagnostics(currentManifest, false);
673
+ rebuildCount++;
674
+ lastRebuildMs = Math.round(performance.now() - start);
675
+ lastRebuildAt = new Date().toISOString();
594
676
  }
595
677
  return {
596
678
  build() {
597
679
  fullBuild();
598
680
  },
599
681
  onFileChange(filePath, sourceText) {
600
- if (filePath === routerPath) {
601
- fullBuild(sourceText);
602
- } else {
603
- incrementalUpdate(filePath, sourceText);
604
- }
682
+ if (!filePath.endsWith(".tsx"))
683
+ return;
684
+ incrementalUpdate(filePath, sourceText);
605
685
  },
606
- getSSRManifest() {
607
- return currentSSRManifest;
686
+ getManifest() {
687
+ return currentManifest;
608
688
  },
609
689
  getSnapshot() {
610
690
  return {
@@ -613,9 +693,53 @@ function createPrefetchManifestManager(options) {
613
693
  lastRebuildMs,
614
694
  lastRebuildAt
615
695
  };
696
+ },
697
+ getDiagnostics() {
698
+ return diagnostics;
616
699
  }
617
700
  };
618
701
  }
702
+ // src/ssr-aot-pipeline.ts
703
+ import { compileTheme as compileTheme3 } from "@vertz/ui";
704
+
705
+ // src/ssr-route-matcher.ts
706
+ function matchUrlToPatterns(url, patterns) {
707
+ const path = (url.split("?")[0] ?? "").split("#")[0] ?? "";
708
+ const matches = [];
709
+ for (const pattern of patterns) {
710
+ const result = matchPattern(path, pattern);
711
+ if (result) {
712
+ matches.push(result);
713
+ }
714
+ }
715
+ matches.sort((a, b) => {
716
+ const aSegments = a.pattern.split("/").length;
717
+ const bSegments = b.pattern.split("/").length;
718
+ return aSegments - bSegments;
719
+ });
720
+ return matches;
721
+ }
722
+ function matchPattern(path, pattern) {
723
+ const pathSegments = path.split("/").filter(Boolean);
724
+ const patternSegments = pattern.split("/").filter(Boolean);
725
+ if (patternSegments.length > pathSegments.length)
726
+ return;
727
+ const params = {};
728
+ for (let i = 0;i < patternSegments.length; i++) {
729
+ const seg = patternSegments[i];
730
+ const val = pathSegments[i];
731
+ if (seg.startsWith(":")) {
732
+ params[seg.slice(1)] = val;
733
+ } else if (seg !== val) {
734
+ return;
735
+ }
736
+ }
737
+ return { pattern, params };
738
+ }
739
+
740
+ // src/ssr-single-pass.ts
741
+ import { compileTheme as compileTheme2 } from "@vertz/ui";
742
+
619
743
  // src/ssr-manifest-prefetch.ts
620
744
  function reconstructDescriptors(queries, routeParams, apiClient) {
621
745
  if (!apiClient)
@@ -704,42 +828,8 @@ function resolveQueryBindings(bindings, routeParams) {
704
828
  resolved.limit = bindings.limit;
705
829
  return resolved;
706
830
  }
707
- // src/ssr-route-matcher.ts
708
- function matchUrlToPatterns(url, patterns) {
709
- const path = (url.split("?")[0] ?? "").split("#")[0] ?? "";
710
- const matches = [];
711
- for (const pattern of patterns) {
712
- const result = matchPattern(path, pattern);
713
- if (result) {
714
- matches.push(result);
715
- }
716
- }
717
- matches.sort((a, b) => {
718
- const aSegments = a.pattern.split("/").length;
719
- const bSegments = b.pattern.split("/").length;
720
- return aSegments - bSegments;
721
- });
722
- return matches;
723
- }
724
- function matchPattern(path, pattern) {
725
- const pathSegments = path.split("/").filter(Boolean);
726
- const patternSegments = pattern.split("/").filter(Boolean);
727
- if (patternSegments.length > pathSegments.length)
728
- return;
729
- const params = {};
730
- for (let i = 0;i < patternSegments.length; i++) {
731
- const seg = patternSegments[i];
732
- const val = pathSegments[i];
733
- if (seg.startsWith(":")) {
734
- params[seg.slice(1)] = val;
735
- } else if (seg !== val) {
736
- return;
737
- }
738
- }
739
- return { pattern, params };
740
- }
831
+
741
832
  // src/ssr-single-pass.ts
742
- import { compileTheme as compileTheme2 } from "@vertz/ui";
743
833
  async function ssrRenderSinglePass(module, url, options) {
744
834
  if (options?.prefetch === false) {
745
835
  return ssrRenderToString(module, url, options);
@@ -1031,6 +1121,408 @@ function collectCSS(themeCss, module) {
1031
1121
  return [themeTag, globalTag, componentTag].filter(Boolean).join(`
1032
1122
  `);
1033
1123
  }
1124
+
1125
+ // src/ssr-aot-pipeline.ts
1126
+ function createHoles(holeNames, module, url, queryCache, ssrAuth) {
1127
+ if (holeNames.length === 0)
1128
+ return {};
1129
+ const holes = {};
1130
+ for (const name of holeNames) {
1131
+ holes[name] = () => {
1132
+ const holeCtx = createRequestContext(url);
1133
+ for (const [key, data] of queryCache) {
1134
+ holeCtx.queryCache.set(key, data);
1135
+ }
1136
+ if (ssrAuth) {
1137
+ holeCtx.ssrAuth = ssrAuth;
1138
+ }
1139
+ holeCtx.resolvedComponents = new Map;
1140
+ return ssrStorage.run(holeCtx, () => {
1141
+ ensureDomShim2();
1142
+ const factory = resolveHoleComponent(module, name);
1143
+ if (!factory) {
1144
+ return `<!-- AOT hole: ${name} not found -->`;
1145
+ }
1146
+ const node = factory();
1147
+ const vnode = toVNode(node);
1148
+ return serializeToHtml(vnode);
1149
+ });
1150
+ };
1151
+ }
1152
+ return holes;
1153
+ }
1154
+ function resolveHoleComponent(module, name) {
1155
+ const moduleRecord = module;
1156
+ const exported = moduleRecord[name];
1157
+ if (typeof exported === "function") {
1158
+ return exported;
1159
+ }
1160
+ return;
1161
+ }
1162
+ async function ssrRenderAot(module, url, options) {
1163
+ const { aotManifest, manifest } = options;
1164
+ const ssrTimeout = options.ssrTimeout ?? 300;
1165
+ const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
1166
+ const fallbackOptions = {
1167
+ ssrTimeout,
1168
+ fallbackMetrics: options.fallbackMetrics,
1169
+ ssrAuth: options.ssrAuth,
1170
+ manifest,
1171
+ prefetchSession: options.prefetchSession
1172
+ };
1173
+ const aotPatterns = Object.keys(aotManifest.routes);
1174
+ const matches = matchUrlToPatterns(normalizedUrl, aotPatterns);
1175
+ if (matches.length === 0) {
1176
+ return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1177
+ }
1178
+ const match = matches[matches.length - 1];
1179
+ if (!match) {
1180
+ return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1181
+ }
1182
+ const aotEntry = aotManifest.routes[match.pattern];
1183
+ if (!aotEntry) {
1184
+ return ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1185
+ }
1186
+ const queryCache = new Map;
1187
+ try {
1188
+ setGlobalSSRTimeout(ssrTimeout);
1189
+ const holes = createHoles(aotEntry.holes, module, normalizedUrl, queryCache, options.ssrAuth);
1190
+ const ctx = {
1191
+ holes,
1192
+ getData: (key) => queryCache.get(key),
1193
+ session: options.prefetchSession,
1194
+ params: match.params
1195
+ };
1196
+ const data = {};
1197
+ for (const [key, value] of queryCache) {
1198
+ data[key] = value;
1199
+ }
1200
+ const html = aotEntry.render(data, ctx);
1201
+ if (options.diagnostics && isAotDebugEnabled()) {
1202
+ try {
1203
+ const domResult = await ssrRenderSinglePass(module, normalizedUrl, fallbackOptions);
1204
+ if (domResult.html !== html) {
1205
+ options.diagnostics.recordDivergence(match.pattern, html, domResult.html);
1206
+ }
1207
+ } catch {}
1208
+ }
1209
+ const css = collectCSSFromModule(module, options.fallbackMetrics);
1210
+ const ssrData = [];
1211
+ for (const [key, data2] of queryCache) {
1212
+ ssrData.push({ key, data: JSON.parse(JSON.stringify(data2)) });
1213
+ }
1214
+ return {
1215
+ html,
1216
+ css: css.cssString,
1217
+ ssrData,
1218
+ headTags: css.preloadTags
1219
+ };
1220
+ } finally {
1221
+ clearGlobalSSRTimeout();
1222
+ }
1223
+ }
1224
+ function isAotDebugEnabled() {
1225
+ const env = process.env.VERTZ_DEBUG;
1226
+ if (!env)
1227
+ return false;
1228
+ return env === "1" || env.split(",").includes("aot");
1229
+ }
1230
+ var domShimInstalled2 = false;
1231
+ function ensureDomShim2() {
1232
+ if (domShimInstalled2 && typeof document !== "undefined")
1233
+ return;
1234
+ domShimInstalled2 = true;
1235
+ installDomShim();
1236
+ }
1237
+ function collectCSSFromModule(module, fallbackMetrics) {
1238
+ let themeCss = "";
1239
+ let preloadTags = "";
1240
+ if (module.theme) {
1241
+ try {
1242
+ const compiled = compileTheme3(module.theme, { fallbackMetrics });
1243
+ themeCss = compiled.css;
1244
+ preloadTags = compiled.preloadTags;
1245
+ } catch (e) {
1246
+ console.error("[vertz] Failed to compile theme export. Ensure your theme is created with defineTheme().", e);
1247
+ }
1248
+ }
1249
+ const alreadyIncluded = new Set;
1250
+ if (themeCss)
1251
+ alreadyIncluded.add(themeCss);
1252
+ if (module.styles) {
1253
+ for (const s of module.styles)
1254
+ alreadyIncluded.add(s);
1255
+ }
1256
+ const componentCss = module.getInjectedCSS ? module.getInjectedCSS().filter((s) => !alreadyIncluded.has(s)) : [];
1257
+ const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
1258
+ const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
1259
+ `)}</style>` : "";
1260
+ const componentTag = componentCss.length > 0 ? `<style data-vertz-css>${componentCss.join(`
1261
+ `)}</style>` : "";
1262
+ const cssString = [themeTag, globalTag, componentTag].filter(Boolean).join(`
1263
+ `);
1264
+ return { cssString, preloadTags };
1265
+ }
1266
+ // src/ssr-aot-runtime.ts
1267
+ var UNITLESS_PROPERTIES = new Set([
1268
+ "animationIterationCount",
1269
+ "aspectRatio",
1270
+ "borderImageOutset",
1271
+ "borderImageSlice",
1272
+ "borderImageWidth",
1273
+ "boxFlex",
1274
+ "boxFlexGroup",
1275
+ "boxOrdinalGroup",
1276
+ "columnCount",
1277
+ "columns",
1278
+ "flex",
1279
+ "flexGrow",
1280
+ "flexPositive",
1281
+ "flexShrink",
1282
+ "flexNegative",
1283
+ "flexOrder",
1284
+ "fontWeight",
1285
+ "gridArea",
1286
+ "gridColumn",
1287
+ "gridColumnEnd",
1288
+ "gridColumnSpan",
1289
+ "gridColumnStart",
1290
+ "gridRow",
1291
+ "gridRowEnd",
1292
+ "gridRowSpan",
1293
+ "gridRowStart",
1294
+ "lineClamp",
1295
+ "lineHeight",
1296
+ "opacity",
1297
+ "order",
1298
+ "orphans",
1299
+ "scale",
1300
+ "tabSize",
1301
+ "widows",
1302
+ "zIndex",
1303
+ "zoom"
1304
+ ]);
1305
+ function __esc(value) {
1306
+ if (value == null || value === false)
1307
+ return "";
1308
+ if (value === true)
1309
+ return "true";
1310
+ if (typeof value === "number")
1311
+ return String(value);
1312
+ if (Array.isArray(value))
1313
+ return value.map(__esc).join("");
1314
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1315
+ }
1316
+ function __esc_attr(value) {
1317
+ const str = typeof value === "string" ? value : String(value);
1318
+ return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
1319
+ }
1320
+ function __ssr_spread(props) {
1321
+ const parts = [];
1322
+ for (const key in props) {
1323
+ const value = props[key];
1324
+ if (value == null || value === false)
1325
+ continue;
1326
+ const third = key.charAt(2);
1327
+ if (key.length > 2 && key.charAt(0) === "o" && key.charAt(1) === "n" && third >= "A" && third <= "Z") {
1328
+ continue;
1329
+ }
1330
+ if (typeof value === "function")
1331
+ continue;
1332
+ if (key === "key" || key === "ref" || key === "children")
1333
+ continue;
1334
+ const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1335
+ if (key === "style" && typeof value === "object") {
1336
+ const css = __ssr_style_object(value);
1337
+ if (css) {
1338
+ parts.push(` style="${__esc_attr(css)}"`);
1339
+ }
1340
+ continue;
1341
+ }
1342
+ if (value === true) {
1343
+ parts.push(` ${attrName}`);
1344
+ continue;
1345
+ }
1346
+ parts.push(` ${attrName}="${__esc_attr(value)}"`);
1347
+ }
1348
+ return parts.join("");
1349
+ }
1350
+ function camelToKebab(prop) {
1351
+ if (prop.startsWith("--"))
1352
+ return prop;
1353
+ if (prop.startsWith("ms")) {
1354
+ return `-${prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}`;
1355
+ }
1356
+ const first = prop.charAt(0);
1357
+ if (first >= "A" && first <= "Z") {
1358
+ return `-${first.toLowerCase()}${prop.slice(1).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}`;
1359
+ }
1360
+ return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
1361
+ }
1362
+ function __ssr_style_object(style) {
1363
+ const parts = [];
1364
+ for (const prop in style) {
1365
+ const value = style[prop];
1366
+ if (value == null || value === "")
1367
+ continue;
1368
+ const cssProp = camelToKebab(prop);
1369
+ if (typeof value === "number" && value !== 0 && !UNITLESS_PROPERTIES.has(prop)) {
1370
+ parts.push(`${cssProp}: ${value}px`);
1371
+ } else {
1372
+ parts.push(`${cssProp}: ${value}`);
1373
+ }
1374
+ }
1375
+ return parts.join("; ");
1376
+ }
1377
+ // src/ssr-html.ts
1378
+ function generateSSRHtml(options) {
1379
+ const {
1380
+ appHtml,
1381
+ css,
1382
+ ssrData,
1383
+ clientEntry,
1384
+ title = "Vertz App",
1385
+ headTags: rawHeadTags = "",
1386
+ modulepreload
1387
+ } = options;
1388
+ const modulepreloadTags = modulepreload?.length ? modulepreload.map((p) => `<link rel="modulepreload" href="${escapeAttr(p)}">`).join(`
1389
+ `) : "";
1390
+ const headTags = [rawHeadTags, modulepreloadTags].filter(Boolean).join(`
1391
+ `);
1392
+ const ssrDataScript = ssrData.length > 0 ? `<script>window.__VERTZ_SSR_DATA__ = ${JSON.stringify(ssrData)};</script>` : "";
1393
+ return `<!doctype html>
1394
+ <html lang="en">
1395
+ <head>
1396
+ <meta charset="UTF-8" />
1397
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
1398
+ <title>${escapeHtml(title)}</title>
1399
+ ${headTags}
1400
+ ${css}
1401
+ </head>
1402
+ <body>
1403
+ <div id="app">${appHtml}</div>
1404
+ ${ssrDataScript}
1405
+ <script type="module" src="${escapeAttr(clientEntry)}"></script>
1406
+ </body>
1407
+ </html>`;
1408
+ }
1409
+ // src/ssr-prefetch-dev.ts
1410
+ import {
1411
+ analyzeComponentQueries,
1412
+ generatePrefetchManifest
1413
+ } from "@vertz/ui-compiler";
1414
+ function createPrefetchManifestManager(options) {
1415
+ const { routerPath, readFile: readFile2, resolveImport } = options;
1416
+ let currentManifest = null;
1417
+ let currentSSRManifest;
1418
+ let rebuildCount = 0;
1419
+ let lastRebuildMs = null;
1420
+ let lastRebuildAt = null;
1421
+ let fileToRouteIndices = new Map;
1422
+ function buildFileIndex(routes) {
1423
+ const index = new Map;
1424
+ for (let i = 0;i < routes.length; i++) {
1425
+ const file = routes[i]?.file;
1426
+ if (file) {
1427
+ const existing = index.get(file) ?? [];
1428
+ existing.push(i);
1429
+ index.set(file, existing);
1430
+ }
1431
+ }
1432
+ return index;
1433
+ }
1434
+ function toSSRManifest(manifest) {
1435
+ const routeEntries = {};
1436
+ for (const route of manifest.routes) {
1437
+ const existing = routeEntries[route.pattern];
1438
+ if (existing) {
1439
+ existing.queries.push(...route.queries);
1440
+ } else {
1441
+ routeEntries[route.pattern] = { queries: [...route.queries] };
1442
+ }
1443
+ }
1444
+ return {
1445
+ routePatterns: [...new Set(manifest.routes.map((r) => r.pattern))],
1446
+ routeEntries
1447
+ };
1448
+ }
1449
+ function fullBuild(routerSourceOverride) {
1450
+ const start = performance.now();
1451
+ const routerSource = routerSourceOverride ?? readFile2(routerPath);
1452
+ if (!routerSource) {
1453
+ return;
1454
+ }
1455
+ try {
1456
+ const manifest = generatePrefetchManifest({
1457
+ routerSource,
1458
+ routerPath,
1459
+ readFile: readFile2,
1460
+ resolveImport
1461
+ });
1462
+ currentManifest = manifest;
1463
+ currentSSRManifest = toSSRManifest(manifest);
1464
+ fileToRouteIndices = buildFileIndex(manifest.routes);
1465
+ rebuildCount++;
1466
+ lastRebuildMs = Math.round(performance.now() - start);
1467
+ lastRebuildAt = new Date().toISOString();
1468
+ } catch {}
1469
+ }
1470
+ function incrementalUpdate(filePath, sourceText) {
1471
+ if (!currentManifest)
1472
+ return;
1473
+ const indices = fileToRouteIndices.get(filePath);
1474
+ if (!indices || indices.length === 0)
1475
+ return;
1476
+ const start = performance.now();
1477
+ try {
1478
+ const analysis = analyzeComponentQueries(sourceText, filePath);
1479
+ const newRoutes = [...currentManifest.routes];
1480
+ for (const idx of indices) {
1481
+ const existing = newRoutes[idx];
1482
+ if (existing) {
1483
+ newRoutes[idx] = {
1484
+ ...existing,
1485
+ queries: analysis.queries,
1486
+ params: analysis.params
1487
+ };
1488
+ }
1489
+ }
1490
+ const newManifest = {
1491
+ ...currentManifest,
1492
+ routes: newRoutes,
1493
+ generatedAt: new Date().toISOString()
1494
+ };
1495
+ currentManifest = newManifest;
1496
+ currentSSRManifest = toSSRManifest(newManifest);
1497
+ rebuildCount++;
1498
+ lastRebuildMs = Math.round(performance.now() - start);
1499
+ lastRebuildAt = new Date().toISOString();
1500
+ } catch {}
1501
+ }
1502
+ return {
1503
+ build() {
1504
+ fullBuild();
1505
+ },
1506
+ onFileChange(filePath, sourceText) {
1507
+ if (filePath === routerPath) {
1508
+ fullBuild(sourceText);
1509
+ } else {
1510
+ incrementalUpdate(filePath, sourceText);
1511
+ }
1512
+ },
1513
+ getSSRManifest() {
1514
+ return currentSSRManifest;
1515
+ },
1516
+ getSnapshot() {
1517
+ return {
1518
+ manifest: currentManifest,
1519
+ rebuildCount,
1520
+ lastRebuildMs,
1521
+ lastRebuildAt
1522
+ };
1523
+ }
1524
+ };
1525
+ }
1034
1526
  export {
1035
1527
  wrapWithHydrationMarkers,
1036
1528
  toPrefetchSession,
@@ -1038,6 +1530,7 @@ export {
1038
1530
  ssrStorage,
1039
1531
  ssrRenderToString,
1040
1532
  ssrRenderSinglePass,
1533
+ ssrRenderAot,
1041
1534
  ssrDiscoverQueries,
1042
1535
  setGlobalSSRTimeout,
1043
1536
  serializeToHtml,
@@ -1054,6 +1547,7 @@ export {
1054
1547
  rawHtml,
1055
1548
  matchUrlToPatterns,
1056
1549
  isInSSR,
1550
+ isAotDebugEnabled,
1057
1551
  inlineCriticalCss,
1058
1552
  getStreamingRuntimeScript,
1059
1553
  getSSRUrl,
@@ -1061,6 +1555,7 @@ export {
1061
1555
  getGlobalSSRTimeout,
1062
1556
  getAccessSetForSSR,
1063
1557
  generateSSRHtml,
1558
+ generateAotBuildManifest,
1064
1559
  extractFontMetrics,
1065
1560
  evaluateAccessRule,
1066
1561
  encodeChunk,
@@ -1072,8 +1567,15 @@ export {
1072
1567
  createSSRDataChunk,
1073
1568
  createSSRAdapter,
1074
1569
  createPrefetchManifestManager,
1570
+ createHoles,
1571
+ createAotManifestManager,
1075
1572
  createAccessSetScript,
1076
1573
  collectStreamChunks,
1077
1574
  clearGlobalSSRTimeout,
1078
- HeadCollector
1575
+ __ssr_style_object,
1576
+ __ssr_spread,
1577
+ __esc_attr,
1578
+ __esc,
1579
+ HeadCollector,
1580
+ AotDiagnostics
1079
1581
  };