@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.
- package/dist/bun-dev-server.js +250 -4
- package/dist/bun-plugin/index.d.ts +1 -1
- package/dist/index.d.ts +346 -86
- package/dist/index.js +658 -154
- package/package.json +5 -5
package/dist/bun-dev-server.js
CHANGED
|
@@ -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
|
-
|
|
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;
|