@vertz/ui-server 0.2.29 → 0.2.31

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
@@ -1,25 +1,36 @@
1
+ import {
2
+ createSSRHandler
3
+ } from "./shared/chunk-wb5fv233.js";
4
+ import {
5
+ createNodeHandler
6
+ } from "./shared/chunk-es0406qq.js";
1
7
  import {
2
8
  collectStreamChunks,
9
+ compileThemeCached,
3
10
  createAccessSetScript,
4
11
  createRequestContext,
5
12
  createSSRDataChunk,
6
- createSSRHandler,
7
13
  createSessionScript,
8
14
  createSlotPlaceholder,
9
15
  createTemplateChunk,
10
16
  encodeChunk,
11
17
  escapeAttr,
12
18
  escapeHtml,
19
+ evaluateAccessRule,
13
20
  getAccessSetForSSR,
14
21
  getStreamingRuntimeScript,
22
+ matchUrlToPatterns,
23
+ reconstructDescriptors,
15
24
  renderToStream,
16
25
  resetSlotCounter,
17
26
  safeSerialize,
18
27
  serializeToHtml,
19
28
  ssrDiscoverQueries,
29
+ ssrRenderSinglePass,
20
30
  ssrRenderToString,
21
- streamToString
22
- } from "./shared/chunk-yr65qdge.js";
31
+ streamToString,
32
+ toPrefetchSession
33
+ } from "./shared/chunk-34fexgex.js";
23
34
  import {
24
35
  clearGlobalSSRTimeout,
25
36
  createSSRAdapter,
@@ -33,7 +44,7 @@ import {
33
44
  setGlobalSSRTimeout,
34
45
  ssrStorage,
35
46
  toVNode
36
- } from "./shared/chunk-gcwqkynf.js";
47
+ } from "./shared/chunk-ybftdw1r.js";
37
48
 
38
49
  // src/aot-manifest-build.ts
39
50
  import { readdirSync, readFileSync } from "node:fs";
@@ -384,7 +395,7 @@ ${options.head}` : headHtml;
384
395
  });
385
396
  }
386
397
  // src/render-to-html.ts
387
- import { compileTheme, getInjectedCSS } from "@vertz/ui";
398
+ import { getInjectedCSS } from "@vertz/ui";
388
399
  async function twoPassRender(options) {
389
400
  options.app();
390
401
  const queries = getSSRQueries();
@@ -403,7 +414,7 @@ async function twoPassRender(options) {
403
414
  const pendingQueries = queries.filter((q) => !q.resolved);
404
415
  const vnode = options.app();
405
416
  const collectedCSS = getInjectedCSS();
406
- const themeCss = options.theme ? compileTheme(options.theme, { fallbackMetrics: options.fallbackMetrics }).css : "";
417
+ const themeCss = options.theme ? compileThemeCached(options.theme, options.fallbackMetrics).css : "";
407
418
  const allStyles = [themeCss, ...options.styles ?? [], ...collectedCSS].filter(Boolean);
408
419
  const styleTags = allStyles.length > 0 ? `<style>${allStyles.join(`
409
420
  `)}</style>` : "";
@@ -483,48 +494,6 @@ async function renderToHTML(appOrOptions, maybeOptions) {
483
494
  }
484
495
  });
485
496
  }
486
- // src/ssr-access-evaluator.ts
487
- function toPrefetchSession(ssrAuth, accessSet) {
488
- if (!ssrAuth || ssrAuth.status !== "authenticated" || !ssrAuth.user) {
489
- return { status: "unauthenticated" };
490
- }
491
- const roles = ssrAuth.user.role ? [ssrAuth.user.role] : undefined;
492
- const entitlements = accessSet != null ? Object.fromEntries(Object.entries(accessSet.entitlements).map(([name, check]) => [name, check.allowed])) : undefined;
493
- return {
494
- status: "authenticated",
495
- roles,
496
- entitlements,
497
- tenantId: ssrAuth.user.tenantId
498
- };
499
- }
500
- function evaluateAccessRule(rule, session) {
501
- switch (rule.type) {
502
- case "public":
503
- return true;
504
- case "authenticated":
505
- return session.status === "authenticated";
506
- case "role":
507
- if (session.status !== "authenticated")
508
- return false;
509
- return session.roles?.some((r) => rule.roles.includes(r)) === true;
510
- case "entitlement":
511
- if (session.status !== "authenticated")
512
- return false;
513
- return session.entitlements?.[rule.value] === true;
514
- case "where":
515
- return true;
516
- case "fva":
517
- return session.status === "authenticated";
518
- case "deny":
519
- return false;
520
- case "all":
521
- return rule.rules.every((r) => evaluateAccessRule(r, session));
522
- case "any":
523
- return rule.rules.some((r) => evaluateAccessRule(r, session));
524
- default:
525
- return false;
526
- }
527
- }
528
497
  // src/ssr-aot-diagnostics.ts
529
498
  var MAX_DIVERGENCES = 20;
530
499
 
@@ -701,429 +670,6 @@ function createAotManifestManager(options) {
701
670
  }
702
671
  };
703
672
  }
704
- // src/ssr-aot-pipeline.ts
705
- import { compileTheme as compileTheme3 } from "@vertz/ui";
706
-
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
- }
741
-
742
- // src/ssr-single-pass.ts
743
- import { compileTheme as compileTheme2 } from "@vertz/ui";
744
-
745
- // src/ssr-manifest-prefetch.ts
746
- function reconstructDescriptors(queries, routeParams, apiClient) {
747
- if (!apiClient)
748
- return [];
749
- const result = [];
750
- for (const query of queries) {
751
- const descriptor = reconstructSingle(query, routeParams, apiClient);
752
- if (descriptor) {
753
- result.push(descriptor);
754
- }
755
- }
756
- return result;
757
- }
758
- function reconstructSingle(query, routeParams, apiClient) {
759
- const { entity, operation } = query;
760
- if (!entity || !operation)
761
- return;
762
- const entitySdk = apiClient[entity];
763
- if (!entitySdk)
764
- return;
765
- const method = entitySdk[operation];
766
- if (typeof method !== "function")
767
- return;
768
- const args = buildFactoryArgs(query, routeParams);
769
- if (args === undefined)
770
- return;
771
- try {
772
- const descriptor = method(...args);
773
- if (!descriptor || typeof descriptor._key !== "string" || typeof descriptor._fetch !== "function") {
774
- return;
775
- }
776
- return { key: descriptor._key, fetch: descriptor._fetch };
777
- } catch {
778
- return;
779
- }
780
- }
781
- function buildFactoryArgs(query, routeParams) {
782
- const { operation, idParam, queryBindings } = query;
783
- if (operation === "get") {
784
- if (idParam) {
785
- const id = routeParams[idParam];
786
- if (!id)
787
- return;
788
- const options = resolveQueryBindings(queryBindings, routeParams);
789
- if (options === undefined && queryBindings)
790
- return;
791
- return options ? [id, options] : [id];
792
- }
793
- return;
794
- }
795
- if (!queryBindings)
796
- return [];
797
- const resolved = resolveQueryBindings(queryBindings, routeParams);
798
- if (resolved === undefined)
799
- return;
800
- return [resolved];
801
- }
802
- function resolveQueryBindings(bindings, routeParams) {
803
- if (!bindings)
804
- return;
805
- const resolved = {};
806
- if (bindings.where) {
807
- const where = {};
808
- for (const [key, value] of Object.entries(bindings.where)) {
809
- if (value === null)
810
- return;
811
- if (typeof value === "string" && value.startsWith("$")) {
812
- const paramName = value.slice(1);
813
- const paramValue = routeParams[paramName];
814
- if (!paramValue)
815
- return;
816
- where[key] = paramValue;
817
- } else {
818
- where[key] = value;
819
- }
820
- }
821
- resolved.where = where;
822
- }
823
- if (bindings.select)
824
- resolved.select = bindings.select;
825
- if (bindings.include)
826
- resolved.include = bindings.include;
827
- if (bindings.orderBy)
828
- resolved.orderBy = bindings.orderBy;
829
- if (bindings.limit !== undefined)
830
- resolved.limit = bindings.limit;
831
- return resolved;
832
- }
833
-
834
- // src/ssr-single-pass.ts
835
- async function ssrRenderSinglePass(module, url, options) {
836
- if (options?.prefetch === false) {
837
- return ssrRenderToString(module, url, options);
838
- }
839
- const normalizedUrl = url.endsWith("/index.html") ? url.slice(0, -"/index.html".length) || "/" : url;
840
- const ssrTimeout = options?.ssrTimeout ?? 300;
841
- ensureDomShim();
842
- const zeroDiscoveryData = attemptZeroDiscovery(normalizedUrl, module, options, ssrTimeout);
843
- if (zeroDiscoveryData) {
844
- return renderWithPrefetchedData(module, normalizedUrl, zeroDiscoveryData, options);
845
- }
846
- const discoveryCtx = createRequestContext(normalizedUrl);
847
- if (options?.ssrAuth) {
848
- discoveryCtx.ssrAuth = options.ssrAuth;
849
- }
850
- const discoveredData = await ssrStorage.run(discoveryCtx, async () => {
851
- try {
852
- setGlobalSSRTimeout(ssrTimeout);
853
- const createApp = resolveAppFactory(module);
854
- createApp();
855
- if (discoveryCtx.ssrRedirect) {
856
- return { redirect: discoveryCtx.ssrRedirect };
857
- }
858
- if (discoveryCtx.pendingRouteComponents?.size) {
859
- const entries = Array.from(discoveryCtx.pendingRouteComponents.entries());
860
- const results = await Promise.allSettled(entries.map(([route, promise]) => Promise.race([
861
- promise.then((mod) => ({ route, factory: mod.default })),
862
- new Promise((_, reject) => setTimeout(() => reject(new Error("lazy route timeout")), ssrTimeout))
863
- ])));
864
- discoveryCtx.resolvedComponents = new Map;
865
- for (const result of results) {
866
- if (result.status === "fulfilled") {
867
- const { route, factory } = result.value;
868
- discoveryCtx.resolvedComponents.set(route, factory);
869
- }
870
- }
871
- discoveryCtx.pendingRouteComponents = undefined;
872
- }
873
- const queries = getSSRQueries();
874
- const eligibleQueries = filterByEntityAccess(queries, options?.manifest?.entityAccess, options?.prefetchSession);
875
- const resolvedQueries = [];
876
- if (eligibleQueries.length > 0) {
877
- await Promise.allSettled(eligibleQueries.map(({ promise, timeout, resolve, key }) => Promise.race([
878
- promise.then((data) => {
879
- resolve(data);
880
- resolvedQueries.push({ key, data });
881
- return "resolved";
882
- }),
883
- new Promise((r) => setTimeout(r, timeout || ssrTimeout)).then(() => "timeout")
884
- ])));
885
- }
886
- return {
887
- resolvedQueries,
888
- resolvedComponents: discoveryCtx.resolvedComponents
889
- };
890
- } finally {
891
- clearGlobalSSRTimeout();
892
- }
893
- });
894
- if ("redirect" in discoveredData) {
895
- return {
896
- html: "",
897
- css: "",
898
- ssrData: [],
899
- headTags: "",
900
- redirect: discoveredData.redirect
901
- };
902
- }
903
- const renderCtx = createRequestContext(normalizedUrl);
904
- if (options?.ssrAuth) {
905
- renderCtx.ssrAuth = options.ssrAuth;
906
- }
907
- for (const { key, data } of discoveredData.resolvedQueries) {
908
- renderCtx.queryCache.set(key, data);
909
- }
910
- renderCtx.resolvedComponents = discoveredData.resolvedComponents ?? new Map;
911
- return ssrStorage.run(renderCtx, async () => {
912
- try {
913
- setGlobalSSRTimeout(ssrTimeout);
914
- const createApp = resolveAppFactory(module);
915
- let themeCss = "";
916
- let themePreloadTags = "";
917
- if (module.theme) {
918
- try {
919
- const compiled = compileTheme2(module.theme, {
920
- fallbackMetrics: options?.fallbackMetrics
921
- });
922
- themeCss = compiled.css;
923
- themePreloadTags = compiled.preloadTags;
924
- } catch (e) {
925
- console.error("[vertz] Failed to compile theme export. Ensure your theme is created with defineTheme().", e);
926
- }
927
- }
928
- const app = createApp();
929
- const vnode = toVNode(app);
930
- const stream = renderToStream(vnode);
931
- const html = await streamToString(stream);
932
- const css = collectCSS(themeCss, module);
933
- const ssrData = discoveredData.resolvedQueries.map(({ key, data }) => ({
934
- key,
935
- data: JSON.parse(JSON.stringify(data))
936
- }));
937
- return {
938
- html,
939
- css,
940
- ssrData,
941
- headTags: themePreloadTags,
942
- discoveredRoutes: renderCtx.discoveredRoutes,
943
- matchedRoutePatterns: renderCtx.matchedRoutePatterns
944
- };
945
- } finally {
946
- clearGlobalSSRTimeout();
947
- }
948
- });
949
- }
950
- function attemptZeroDiscovery(url, module, options, ssrTimeout) {
951
- const manifest = options?.manifest;
952
- if (!manifest?.routeEntries || !module.api)
953
- return null;
954
- const matches = matchUrlToPatterns(url, manifest.routePatterns);
955
- if (matches.length === 0)
956
- return null;
957
- const allQueries = [];
958
- let mergedParams = {};
959
- for (const match of matches) {
960
- const entry = manifest.routeEntries[match.pattern];
961
- if (entry) {
962
- allQueries.push(...entry.queries);
963
- }
964
- mergedParams = { ...mergedParams, ...match.params };
965
- }
966
- if (allQueries.length === 0)
967
- return null;
968
- const descriptors = reconstructDescriptors(allQueries, mergedParams, module.api);
969
- if (descriptors.length === 0)
970
- return null;
971
- return prefetchFromDescriptors(descriptors, ssrTimeout);
972
- }
973
- async function prefetchFromDescriptors(descriptors, ssrTimeout) {
974
- const resolvedQueries = [];
975
- await Promise.allSettled(descriptors.map(({ key, fetch: fetchFn }) => Promise.race([
976
- fetchFn().then((result) => {
977
- const data = unwrapResult(result);
978
- resolvedQueries.push({ key, data });
979
- return "resolved";
980
- }),
981
- new Promise((r) => setTimeout(r, ssrTimeout)).then(() => "timeout")
982
- ])));
983
- return { resolvedQueries };
984
- }
985
- function unwrapResult(result) {
986
- if (result && typeof result === "object" && "ok" in result && "data" in result) {
987
- const r = result;
988
- if (r.ok)
989
- return r.data;
990
- }
991
- return result;
992
- }
993
- async function renderWithPrefetchedData(module, normalizedUrl, prefetchedData, options) {
994
- const data = await prefetchedData;
995
- const ssrTimeout = options?.ssrTimeout ?? 300;
996
- const renderCtx = createRequestContext(normalizedUrl);
997
- if (options?.ssrAuth) {
998
- renderCtx.ssrAuth = options.ssrAuth;
999
- }
1000
- for (const { key, data: queryData } of data.resolvedQueries) {
1001
- renderCtx.queryCache.set(key, queryData);
1002
- }
1003
- renderCtx.resolvedComponents = new Map;
1004
- return ssrStorage.run(renderCtx, async () => {
1005
- try {
1006
- setGlobalSSRTimeout(ssrTimeout);
1007
- const createApp = resolveAppFactory(module);
1008
- let themeCss = "";
1009
- let themePreloadTags = "";
1010
- if (module.theme) {
1011
- try {
1012
- const compiled = compileTheme2(module.theme, {
1013
- fallbackMetrics: options?.fallbackMetrics
1014
- });
1015
- themeCss = compiled.css;
1016
- themePreloadTags = compiled.preloadTags;
1017
- } catch (e) {
1018
- console.error("[vertz] Failed to compile theme export. Ensure your theme is created with defineTheme().", e);
1019
- }
1020
- }
1021
- const app = createApp();
1022
- const vnode = toVNode(app);
1023
- const stream = renderToStream(vnode);
1024
- const html = await streamToString(stream);
1025
- if (renderCtx.ssrRedirect) {
1026
- return {
1027
- html: "",
1028
- css: "",
1029
- ssrData: [],
1030
- headTags: "",
1031
- redirect: renderCtx.ssrRedirect,
1032
- discoveredRoutes: renderCtx.discoveredRoutes,
1033
- matchedRoutePatterns: renderCtx.matchedRoutePatterns
1034
- };
1035
- }
1036
- const css = collectCSS(themeCss, module);
1037
- const ssrData = data.resolvedQueries.map(({ key, data: d }) => ({
1038
- key,
1039
- data: JSON.parse(JSON.stringify(d))
1040
- }));
1041
- return {
1042
- html,
1043
- css,
1044
- ssrData,
1045
- headTags: themePreloadTags,
1046
- discoveredRoutes: renderCtx.discoveredRoutes,
1047
- matchedRoutePatterns: renderCtx.matchedRoutePatterns
1048
- };
1049
- } finally {
1050
- clearGlobalSSRTimeout();
1051
- }
1052
- });
1053
- }
1054
- var domShimInstalled = false;
1055
- function ensureDomShim() {
1056
- if (domShimInstalled && typeof document !== "undefined")
1057
- return;
1058
- domShimInstalled = true;
1059
- installDomShim();
1060
- }
1061
- function resolveAppFactory(module) {
1062
- const createApp = module.default || module.App;
1063
- if (typeof createApp !== "function") {
1064
- throw new Error("App entry must export a default function or named App function");
1065
- }
1066
- return createApp;
1067
- }
1068
- function filterByEntityAccess(queries, entityAccess, session) {
1069
- if (!entityAccess || !session)
1070
- return queries;
1071
- return queries.filter(({ key }) => {
1072
- const entity = extractEntityFromKey(key);
1073
- const method = extractMethodFromKey(key);
1074
- if (!entity)
1075
- return true;
1076
- const entityRules = entityAccess[entity];
1077
- if (!entityRules)
1078
- return true;
1079
- const rule = entityRules[method];
1080
- if (!rule)
1081
- return true;
1082
- return evaluateAccessRule(rule, session);
1083
- });
1084
- }
1085
- function extractEntityFromKey(key) {
1086
- const pathStart = key.indexOf(":/");
1087
- if (pathStart === -1)
1088
- return;
1089
- const path = key.slice(pathStart + 2);
1090
- const firstSlash = path.indexOf("/");
1091
- const questionMark = path.indexOf("?");
1092
- if (firstSlash === -1 && questionMark === -1)
1093
- return path;
1094
- if (firstSlash === -1)
1095
- return path.slice(0, questionMark);
1096
- if (questionMark === -1)
1097
- return path.slice(0, firstSlash);
1098
- return path.slice(0, Math.min(firstSlash, questionMark));
1099
- }
1100
- function extractMethodFromKey(key) {
1101
- const pathStart = key.indexOf(":/");
1102
- if (pathStart === -1)
1103
- return "list";
1104
- const path = key.slice(pathStart + 2);
1105
- const cleanPath = path.split("?")[0] ?? "";
1106
- const segments = cleanPath.split("/").filter(Boolean);
1107
- return segments.length > 1 ? "get" : "list";
1108
- }
1109
- function collectCSS(themeCss, module) {
1110
- const alreadyIncluded = new Set;
1111
- if (themeCss)
1112
- alreadyIncluded.add(themeCss);
1113
- if (module.styles) {
1114
- for (const s of module.styles)
1115
- alreadyIncluded.add(s);
1116
- }
1117
- const componentCss = module.getInjectedCSS ? module.getInjectedCSS().filter((s) => !alreadyIncluded.has(s)) : [];
1118
- const themeTag = themeCss ? `<style data-vertz-css>${themeCss}</style>` : "";
1119
- const globalTag = module.styles && module.styles.length > 0 ? `<style data-vertz-css>${module.styles.join(`
1120
- `)}</style>` : "";
1121
- const componentTag = componentCss.length > 0 ? `<style data-vertz-css>${componentCss.join(`
1122
- `)}</style>` : "";
1123
- return [themeTag, globalTag, componentTag].filter(Boolean).join(`
1124
- `);
1125
- }
1126
-
1127
673
  // src/ssr-aot-pipeline.ts
1128
674
  function createHoles(holeNames, module, url, queryCache, ssrAuth) {
1129
675
  if (holeNames.length === 0)
@@ -1140,7 +686,7 @@ function createHoles(holeNames, module, url, queryCache, ssrAuth) {
1140
686
  }
1141
687
  holeCtx.resolvedComponents = new Map;
1142
688
  return ssrStorage.run(holeCtx, () => {
1143
- ensureDomShim2();
689
+ ensureDomShim();
1144
690
  const factory = resolveHoleComponent(module, name);
1145
691
  if (!factory) {
1146
692
  return `<!-- AOT hole: ${name} not found -->`;
@@ -1211,7 +757,7 @@ async function ssrRenderAot(module, url, options) {
1211
757
  const css = collectCSSFromModule(module, options.fallbackMetrics);
1212
758
  const ssrData = [];
1213
759
  for (const [key, data2] of queryCache) {
1214
- ssrData.push({ key, data: JSON.parse(JSON.stringify(data2)) });
760
+ ssrData.push({ key, data: data2 });
1215
761
  }
1216
762
  return {
1217
763
  html,
@@ -1229,11 +775,11 @@ function isAotDebugEnabled() {
1229
775
  return false;
1230
776
  return env === "1" || env.split(",").includes("aot");
1231
777
  }
1232
- var domShimInstalled2 = false;
1233
- function ensureDomShim2() {
1234
- if (domShimInstalled2 && typeof document !== "undefined")
778
+ var domShimInstalled = false;
779
+ function ensureDomShim() {
780
+ if (domShimInstalled && typeof document !== "undefined")
1235
781
  return;
1236
- domShimInstalled2 = true;
782
+ domShimInstalled = true;
1237
783
  installDomShim();
1238
784
  }
1239
785
  function collectCSSFromModule(module, fallbackMetrics) {
@@ -1241,7 +787,7 @@ function collectCSSFromModule(module, fallbackMetrics) {
1241
787
  let preloadTags = "";
1242
788
  if (module.theme) {
1243
789
  try {
1244
- const compiled = compileTheme3(module.theme, { fallbackMetrics });
790
+ const compiled = compileThemeCached(module.theme, fallbackMetrics);
1245
791
  themeCss = compiled.css;
1246
792
  preloadTags = compiled.preloadTags;
1247
793
  } catch (e) {
@@ -1569,6 +1115,7 @@ export {
1569
1115
  createSSRDataChunk,
1570
1116
  createSSRAdapter,
1571
1117
  createPrefetchManifestManager,
1118
+ createNodeHandler,
1572
1119
  createHoles,
1573
1120
  createAotManifestManager,
1574
1121
  createAccessSetScript,