@vertz/ui-server 0.2.25 → 0.2.28

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.
@@ -9,7 +9,7 @@ import {
9
9
 
10
10
  // src/bun-dev-server.ts
11
11
  import { execSync } from "child_process";
12
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, watch as watch2, writeFileSync as writeFileSync2 } from "fs";
12
+ import { existsSync as existsSync2, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync2, watch as watch2, writeFileSync as writeFileSync2 } from "fs";
13
13
  import { dirname, normalize, resolve } from "path";
14
14
 
15
15
  // src/debug-logger.ts
@@ -593,14 +593,16 @@ function createSourceMapResolver(projectRoot) {
593
593
  }
594
594
 
595
595
  // src/ssr-access-evaluator.ts
596
- function toPrefetchSession(ssrAuth) {
596
+ function toPrefetchSession(ssrAuth, accessSet) {
597
597
  if (!ssrAuth || ssrAuth.status !== "authenticated" || !ssrAuth.user) {
598
598
  return { status: "unauthenticated" };
599
599
  }
600
600
  const roles = ssrAuth.user.role ? [ssrAuth.user.role] : undefined;
601
+ const entitlements = accessSet != null ? Object.fromEntries(Object.entries(accessSet.entitlements).map(([name, check]) => [name, check.allowed])) : undefined;
601
602
  return {
602
603
  status: "authenticated",
603
604
  roles,
605
+ entitlements,
604
606
  tenantId: ssrAuth.user.tenantId
605
607
  };
606
608
  }
@@ -644,6 +646,186 @@ function escapeAttr(s) {
644
646
  return s.replace(/[&"'<>]/g, (c) => `&#${c.charCodeAt(0)};`);
645
647
  }
646
648
 
649
+ // src/ssr-aot-manifest-dev.ts
650
+ import { compileForSSRAot } from "@vertz/ui-compiler";
651
+
652
+ // src/ssr-aot-diagnostics.ts
653
+ var MAX_DIVERGENCES = 20;
654
+
655
+ class AotDiagnostics {
656
+ _components = new Map;
657
+ _divergences = [];
658
+ recordCompilation(components) {
659
+ for (const comp of components) {
660
+ this._components.set(comp.name, {
661
+ tier: comp.tier,
662
+ holes: comp.holes
663
+ });
664
+ }
665
+ }
666
+ recordDivergence(component, aotHtml, domHtml) {
667
+ this._divergences.push({
668
+ component,
669
+ aotHtml,
670
+ domHtml,
671
+ timestamp: new Date().toISOString()
672
+ });
673
+ if (this._divergences.length > MAX_DIVERGENCES) {
674
+ this._divergences = this._divergences.slice(this._divergences.length - MAX_DIVERGENCES);
675
+ }
676
+ }
677
+ clear() {
678
+ this._components.clear();
679
+ this._divergences = [];
680
+ }
681
+ clearComponents() {
682
+ this._components.clear();
683
+ }
684
+ getClassificationLog() {
685
+ const lines = [];
686
+ for (const [name, comp] of this._components) {
687
+ let line = `${name}: ${comp.tier}`;
688
+ if (comp.holes.length > 0) {
689
+ line += `, ${comp.holes.length} hole${comp.holes.length > 1 ? "s" : ""} (${comp.holes.join(", ")})`;
690
+ }
691
+ lines.push(line);
692
+ }
693
+ const snapshot = this.getSnapshot();
694
+ const { total, aot, percentage } = snapshot.coverage;
695
+ if (total > 0) {
696
+ lines.push(`Coverage: ${aot}/${total} components (${percentage}%)`);
697
+ }
698
+ return lines;
699
+ }
700
+ getSnapshot() {
701
+ let aot = 0;
702
+ let runtime = 0;
703
+ for (const comp of this._components.values()) {
704
+ if (comp.tier === "runtime-fallback") {
705
+ runtime++;
706
+ } else {
707
+ aot++;
708
+ }
709
+ }
710
+ const total = aot + runtime;
711
+ return {
712
+ components: Object.fromEntries(this._components),
713
+ coverage: {
714
+ total,
715
+ aot,
716
+ runtime,
717
+ percentage: total === 0 ? 0 : Math.round(aot / total * 100)
718
+ },
719
+ divergences: [...this._divergences]
720
+ };
721
+ }
722
+ }
723
+
724
+ // src/ssr-aot-manifest-dev.ts
725
+ function createAotManifestManager(options) {
726
+ const { readFile: readFile2, listFiles } = options;
727
+ let currentManifest = null;
728
+ const diagnostics = new AotDiagnostics;
729
+ let rebuildCount = 0;
730
+ let lastRebuildMs = null;
731
+ let lastRebuildAt = null;
732
+ function compileFile(filePath, source) {
733
+ try {
734
+ const result = compileForSSRAot(source, { filename: filePath });
735
+ return result.components.map((comp) => ({
736
+ name: comp.name,
737
+ entry: {
738
+ tier: comp.tier,
739
+ holes: comp.holes,
740
+ file: filePath
741
+ }
742
+ }));
743
+ } catch {
744
+ return [];
745
+ }
746
+ }
747
+ function updateDiagnostics(manifest, isFullBuild) {
748
+ if (isFullBuild) {
749
+ diagnostics.clear();
750
+ } else {
751
+ diagnostics.clearComponents();
752
+ }
753
+ const entries = Object.entries(manifest.components).map(([name, entry]) => ({
754
+ name,
755
+ tier: entry.tier,
756
+ holes: entry.holes
757
+ }));
758
+ diagnostics.recordCompilation(entries);
759
+ }
760
+ function fullBuild() {
761
+ const start = performance.now();
762
+ const files = listFiles();
763
+ const components = {};
764
+ for (const filePath of files) {
765
+ if (!filePath.endsWith(".tsx"))
766
+ continue;
767
+ const source = readFile2(filePath);
768
+ if (!source)
769
+ continue;
770
+ const entries = compileFile(filePath, source);
771
+ for (const { name, entry } of entries) {
772
+ components[name] = entry;
773
+ }
774
+ }
775
+ currentManifest = { components };
776
+ updateDiagnostics(currentManifest, true);
777
+ rebuildCount++;
778
+ lastRebuildMs = Math.round(performance.now() - start);
779
+ lastRebuildAt = new Date().toISOString();
780
+ }
781
+ function incrementalUpdate(filePath, sourceText) {
782
+ if (!currentManifest)
783
+ return;
784
+ const start = performance.now();
785
+ const newComponents = { ...currentManifest.components };
786
+ for (const [name, entry] of Object.entries(newComponents)) {
787
+ if (entry.file === filePath) {
788
+ delete newComponents[name];
789
+ }
790
+ }
791
+ if (sourceText.trim()) {
792
+ const entries = compileFile(filePath, sourceText);
793
+ for (const { name, entry } of entries) {
794
+ newComponents[name] = entry;
795
+ }
796
+ }
797
+ currentManifest = { components: newComponents };
798
+ updateDiagnostics(currentManifest, false);
799
+ rebuildCount++;
800
+ lastRebuildMs = Math.round(performance.now() - start);
801
+ lastRebuildAt = new Date().toISOString();
802
+ }
803
+ return {
804
+ build() {
805
+ fullBuild();
806
+ },
807
+ onFileChange(filePath, sourceText) {
808
+ if (!filePath.endsWith(".tsx"))
809
+ return;
810
+ incrementalUpdate(filePath, sourceText);
811
+ },
812
+ getManifest() {
813
+ return currentManifest;
814
+ },
815
+ getSnapshot() {
816
+ return {
817
+ manifest: currentManifest,
818
+ rebuildCount,
819
+ lastRebuildMs,
820
+ lastRebuildAt
821
+ };
822
+ },
823
+ getDiagnostics() {
824
+ return diagnostics;
825
+ }
826
+ };
827
+ }
828
+
647
829
  // src/ssr-prefetch-dev.ts
648
830
  import {
649
831
  analyzeComponentQueries,
@@ -2726,6 +2908,18 @@ function clearSSRRequireCache() {
2726
2908
  }
2727
2909
  return keys.length;
2728
2910
  }
2911
+ function collectFiles(dir) {
2912
+ const files = [];
2913
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
2914
+ const fullPath = resolve(dir, entry.name);
2915
+ if (entry.isDirectory()) {
2916
+ files.push(...collectFiles(fullPath));
2917
+ } else {
2918
+ files.push(fullPath);
2919
+ }
2920
+ }
2921
+ return files;
2922
+ }
2729
2923
  function createBunDevServer(options) {
2730
2924
  const {
2731
2925
  entry,
@@ -2756,6 +2950,7 @@ function createBunDevServer(options) {
2756
2950
  mkdirSync(devDir, { recursive: true });
2757
2951
  const logger = createDebugLogger(devDir);
2758
2952
  const diagnostics = new DiagnosticsCollector;
2953
+ let aotManifestManager = null;
2759
2954
  let server = null;
2760
2955
  let srcWatcherRef = null;
2761
2956
  let refreshTimeout = null;
@@ -3170,6 +3365,36 @@ function createBunDevServer(options) {
3170
3365
  prefetchManager = null;
3171
3366
  }
3172
3367
  }
3368
+ aotManifestManager = createAotManifestManager({
3369
+ readFile: (path) => {
3370
+ try {
3371
+ return readFileSync2(path, "utf-8");
3372
+ } catch {
3373
+ return;
3374
+ }
3375
+ },
3376
+ listFiles: () => {
3377
+ try {
3378
+ return collectFiles(srcDir);
3379
+ } catch {
3380
+ return [];
3381
+ }
3382
+ }
3383
+ });
3384
+ try {
3385
+ const aotStart = performance.now();
3386
+ aotManifestManager.build();
3387
+ const aotMs = Math.round(performance.now() - aotStart);
3388
+ logger.log("aot", "initial-build", { durationMs: aotMs });
3389
+ if (logRequests) {
3390
+ const manifest = aotManifestManager.getManifest();
3391
+ const count = manifest ? Object.keys(manifest.components).length : 0;
3392
+ console.log(`[Server] AOT manifest built (${count} components, ${aotMs}ms)`);
3393
+ }
3394
+ } catch (e) {
3395
+ console.warn("[Server] Failed to build AOT manifest:", e instanceof Error ? e.message : e);
3396
+ aotManifestManager = null;
3397
+ }
3173
3398
  mkdirSync(devDir, { recursive: true });
3174
3399
  const frInitPath = resolve(devDir, "fast-refresh-init.ts");
3175
3400
  writeFileSync2(frInitPath, `import '@vertz/ui-server/fast-refresh-runtime';
@@ -3260,6 +3485,12 @@ if (import.meta.hot) import.meta.hot.accept();
3260
3485
  if (pathname === "/__vertz_diagnostics") {
3261
3486
  return Response.json(diagnostics.getSnapshot());
3262
3487
  }
3488
+ if (pathname === "/__vertz_ssr_aot") {
3489
+ if (!aotManifestManager) {
3490
+ return Response.json({ error: "AOT manifest manager not available" }, { status: 404 });
3491
+ }
3492
+ return Response.json(aotManifestManager.getDiagnostics().getSnapshot());
3493
+ }
3263
3494
  if (pathname === "/__vertz_prefetch_manifest") {
3264
3495
  if (!prefetchManager) {
3265
3496
  return Response.json({ error: "No prefetch manifest available (router file not found)" }, { status: 404 });
@@ -3354,6 +3585,7 @@ data: {}
3354
3585
  }) : null;
3355
3586
  let sessionScript = "";
3356
3587
  let ssrAuth;
3588
+ let ssrAccessSet;
3357
3589
  if (sessionResolver) {
3358
3590
  try {
3359
3591
  const sessionResult = await sessionResolver(request);
@@ -3363,6 +3595,7 @@ data: {}
3363
3595
  user: sessionResult.session.user,
3364
3596
  expiresAt: sessionResult.session.expiresAt
3365
3597
  };
3598
+ ssrAccessSet = sessionResult.accessSet;
3366
3599
  const scripts = [];
3367
3600
  scripts.push(createSessionScript(sessionResult.session));
3368
3601
  if (sessionResult.accessSet != null) {
@@ -3397,7 +3630,7 @@ data: {}
3397
3630
  fallbackMetrics: fontFallbackMetrics,
3398
3631
  ssrAuth,
3399
3632
  manifest: prefetchManager?.getSSRManifest(),
3400
- prefetchSession: toPrefetchSession(ssrAuth)
3633
+ prefetchSession: toPrefetchSession(ssrAuth, ssrAccessSet)
3401
3634
  });
3402
3635
  logger.log("ssr", "render-done", {
3403
3636
  url: pathname,
@@ -3687,7 +3920,20 @@ data: {}
3687
3920
  isRouter: changedFilePath === routerPath
3688
3921
  });
3689
3922
  }
3690
- } catch {}
3923
+ if (aotManifestManager) {
3924
+ const aotStart = performance.now();
3925
+ aotManifestManager.onFileChange(changedFilePath, source);
3926
+ const aotMs = Math.round(performance.now() - aotStart);
3927
+ logger.log("aot", "rebuild", {
3928
+ file: lastChangedFile,
3929
+ durationMs: aotMs
3930
+ });
3931
+ }
3932
+ } catch {
3933
+ if (aotManifestManager) {
3934
+ aotManifestManager.onFileChange(changedFilePath, "");
3935
+ }
3936
+ }
3691
3937
  }
3692
3938
  if (stopped)
3693
3939
  return;
@@ -1,6 +1,6 @@
1
1
  type ErrorCategory = "build" | "resolve" | "runtime" | "ssr";
2
2
  import { CSSExtractionResult } from "@vertz/ui-compiler";
3
- type DebugCategory = "fields" | "manifest" | "plugin" | "prefetch" | "ssr" | "watcher" | "ws";
3
+ type DebugCategory = "aot" | "fields" | "manifest" | "plugin" | "prefetch" | "ssr" | "watcher" | "ws";
4
4
  interface DebugLogger {
5
5
  log(category: DebugCategory, message: string, data?: Record<string, unknown>): void;
6
6
  isEnabled(category: DebugCategory): boolean;