@vertz/ui 0.2.15 → 0.2.17

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.
Files changed (33) hide show
  1. package/README.md +49 -0
  2. package/dist/shared/{chunk-dksg08fq.js → chunk-07bh4m1e.js} +1 -1
  3. package/dist/shared/chunk-14eqne2a.js +10 -0
  4. package/dist/shared/{chunk-nn9v1zmk.js → chunk-2wtb9x81.js} +83 -20
  5. package/dist/shared/{chunk-8hsz5y4a.js → chunk-4fwcwxn6.js} +14 -4
  6. package/dist/shared/{chunk-4txc67nd.js → chunk-6jyt4ycw.js} +67 -2
  7. package/dist/shared/{chunk-83g4h38e.js → chunk-6wd36w21.js} +1 -0
  8. package/dist/shared/{chunk-h89w580h.js → chunk-afawz764.js} +1 -1
  9. package/dist/shared/{chunk-1wby7nex.js → chunk-dhehvmj0.js} +161 -9
  10. package/dist/shared/{chunk-wymw818z.js → chunk-fkbgbf3n.js} +48 -9
  11. package/dist/shared/{chunk-hw67ckr3.js → chunk-fs3eec4b.js} +230 -19
  12. package/dist/shared/{chunk-5dbq8jp9.js → chunk-j09yyh34.js} +72 -6
  13. package/dist/shared/chunk-mtsvrj9e.js +23 -0
  14. package/dist/shared/{chunk-j6qyxfdc.js → chunk-vndfjfdy.js} +3 -3
  15. package/dist/src/auth/public.d.ts +40 -24
  16. package/dist/src/auth/public.js +110 -52
  17. package/dist/src/css/public.d.ts +110 -2
  18. package/dist/src/css/public.js +8 -4
  19. package/dist/src/form/public.d.ts +29 -6
  20. package/dist/src/form/public.js +2 -2
  21. package/dist/src/index.d.ts +284 -13
  22. package/dist/src/index.js +160 -14
  23. package/dist/src/internals.d.ts +168 -5
  24. package/dist/src/internals.js +14 -8
  25. package/dist/src/jsx-runtime/index.d.ts +5 -0
  26. package/dist/src/jsx-runtime/index.js +8 -1
  27. package/dist/src/query/public.js +4 -3
  28. package/dist/src/router/public.d.ts +17 -4
  29. package/dist/src/router/public.js +16 -11
  30. package/dist/src/test/index.d.ts +5 -0
  31. package/dist/src/test/index.js +4 -3
  32. package/package.json +3 -3
  33. package/reactivity.json +1 -11
package/dist/src/index.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  fadeIn,
7
7
  fadeOut,
8
8
  hydrate,
9
+ hydrateIslands,
9
10
  isQueryDescriptor,
10
11
  keyframes,
11
12
  onAnimationsComplete,
@@ -20,33 +21,32 @@ import {
20
21
  slideOutToTop,
21
22
  zoomIn,
22
23
  zoomOut
23
- } from "../shared/chunk-4txc67nd.js";
24
+ } from "../shared/chunk-6jyt4ycw.js";
24
25
  import {
26
+ Link,
25
27
  Outlet,
26
28
  OutletContext,
27
- RouterContext,
28
29
  RouterView,
29
30
  createLink,
30
31
  parseSearchParams,
31
- useParams,
32
- useRouter,
33
32
  useSearchParams
34
- } from "../shared/chunk-nn9v1zmk.js";
35
- import"../shared/chunk-dksg08fq.js";
33
+ } from "../shared/chunk-2wtb9x81.js";
34
+ import"../shared/chunk-07bh4m1e.js";
36
35
  import {
37
36
  createRouter
38
- } from "../shared/chunk-wymw818z.js";
37
+ } from "../shared/chunk-fkbgbf3n.js";
39
38
  import {
40
39
  defineRoutes
41
- } from "../shared/chunk-83g4h38e.js";
40
+ } from "../shared/chunk-6wd36w21.js";
42
41
  import {
43
42
  createFieldState,
44
43
  form,
45
44
  formDataToObject,
46
45
  validate
47
- } from "../shared/chunk-5dbq8jp9.js";
46
+ } from "../shared/chunk-j09yyh34.js";
48
47
  import {
49
48
  EntityStore,
49
+ FieldSelectionTracker,
50
50
  QueryEnvelopeStore,
51
51
  getEntityStore,
52
52
  getMutationEventBus,
@@ -57,14 +57,16 @@ import {
57
57
  queryMatch,
58
58
  registerRelationSchema,
59
59
  resetRelationSchemas_TEST_ONLY
60
- } from "../shared/chunk-hw67ckr3.js";
60
+ } from "../shared/chunk-fs3eec4b.js";
61
61
  import"../shared/chunk-jrtrk5z4.js";
62
62
  import {
63
63
  ThemeProvider,
64
64
  children,
65
+ compileFonts,
65
66
  compileTheme,
66
67
  css,
67
68
  defineTheme,
69
+ font,
68
70
  getInjectedCSS,
69
71
  globalCss,
70
72
  injectCSS,
@@ -72,16 +74,20 @@ import {
72
74
  resolveChildren,
73
75
  s,
74
76
  variants
75
- } from "../shared/chunk-1wby7nex.js";
77
+ } from "../shared/chunk-dhehvmj0.js";
76
78
  import {
77
79
  __append,
78
80
  __element,
79
81
  __enterChildren,
80
82
  __exitChildren,
81
83
  __staticText,
84
+ claimElement,
82
85
  endHydration,
86
+ enterChildren,
87
+ exitChildren,
88
+ getIsHydrating,
83
89
  startHydration
84
- } from "../shared/chunk-j6qyxfdc.js";
90
+ } from "../shared/chunk-vndfjfdy.js";
85
91
  import"../shared/chunk-prj7nm08.js";
86
92
  import {
87
93
  RENDER_NODE_BRAND,
@@ -89,7 +95,15 @@ import {
89
95
  getAdapter,
90
96
  isRenderNode,
91
97
  setAdapter
92
- } from "../shared/chunk-h89w580h.js";
98
+ } from "../shared/chunk-afawz764.js";
99
+ import {
100
+ RouterContext,
101
+ useParams,
102
+ useRouter
103
+ } from "../shared/chunk-mtsvrj9e.js";
104
+ import {
105
+ isBrowser
106
+ } from "../shared/chunk-14eqne2a.js";
93
107
  import {
94
108
  DisposalScopeError,
95
109
  _tryOnCleanup,
@@ -106,7 +120,7 @@ import {
106
120
  signal,
107
121
  untrack,
108
122
  useContext
109
- } from "../shared/chunk-8hsz5y4a.js";
123
+ } from "../shared/chunk-4fwcwxn6.js";
110
124
  // src/component/error-boundary-context.ts
111
125
  var handlerStack = [];
112
126
  function pushErrorHandler(handler) {
@@ -620,6 +634,128 @@ function createDialogStack(container) {
620
634
  });
621
635
  }
622
636
  }
637
+ // src/image/config.ts
638
+ var optimizerBaseUrl = null;
639
+ function configureImageOptimizer(baseUrl) {
640
+ optimizerBaseUrl = baseUrl;
641
+ }
642
+ function isOptimizerConfigured() {
643
+ return optimizerBaseUrl !== null;
644
+ }
645
+ function buildOptimizedUrl(src, width, height, quality, fit) {
646
+ if (!optimizerBaseUrl)
647
+ return null;
648
+ if (!src.startsWith("http://") && !src.startsWith("https://"))
649
+ return null;
650
+ const params = new URLSearchParams({
651
+ url: src,
652
+ w: String(width),
653
+ h: String(height),
654
+ q: String(quality),
655
+ fit
656
+ });
657
+ return `${optimizerBaseUrl}?${params}`;
658
+ }
659
+ // src/image/image.ts
660
+ var BUILD_ONLY_PROPS = new Set([
661
+ "src",
662
+ "width",
663
+ "height",
664
+ "alt",
665
+ "class",
666
+ "style",
667
+ "loading",
668
+ "decoding",
669
+ "fetchpriority",
670
+ "priority",
671
+ "quality",
672
+ "fit",
673
+ "pictureClass"
674
+ ]);
675
+ function Image({
676
+ src,
677
+ width,
678
+ height,
679
+ alt,
680
+ class: className,
681
+ style,
682
+ loading = "lazy",
683
+ decoding = "async",
684
+ fetchpriority,
685
+ priority,
686
+ quality = 80,
687
+ fit = "cover",
688
+ pictureClass: _pictureClass,
689
+ ...rest
690
+ }) {
691
+ const resolvedLoading = priority ? "eager" : loading;
692
+ const resolvedDecoding = priority ? "sync" : decoding;
693
+ const resolvedFetchpriority = priority ? "high" : fetchpriority;
694
+ const optimizedSrc = buildOptimizedUrl(src, width, height, quality, fit);
695
+ if (isOptimizerConfigured() && optimizedSrc === null) {
696
+ console.info(`[vertz] <Image src="${src}"> was not optimized — only absolute HTTP(S) URLs are rewritten. ` + "Relative paths and data URIs are served as-is.");
697
+ }
698
+ const el = document.createElement("img");
699
+ el.setAttribute("src", optimizedSrc ?? src);
700
+ el.setAttribute("width", String(width));
701
+ el.setAttribute("height", String(height));
702
+ el.setAttribute("alt", alt);
703
+ el.setAttribute("loading", resolvedLoading);
704
+ el.setAttribute("decoding", resolvedDecoding);
705
+ if (resolvedFetchpriority)
706
+ el.setAttribute("fetchpriority", resolvedFetchpriority);
707
+ if (className)
708
+ el.setAttribute("class", className);
709
+ if (style)
710
+ el.setAttribute("style", style);
711
+ for (const [key, value] of Object.entries(rest)) {
712
+ if (!BUILD_ONLY_PROPS.has(key) && value != null) {
713
+ el.setAttribute(key, String(value));
714
+ }
715
+ }
716
+ return el;
717
+ }
718
+ // src/island/island.ts
719
+ function validateSerializable(props, islandId) {
720
+ for (const [key, value] of Object.entries(props)) {
721
+ if (typeof value === "function") {
722
+ throw new Error(`[vertz] Island "${islandId}" received a function prop "${key}". ` + "Island props must be JSON-serializable. Define event handlers inside the island component instead.");
723
+ }
724
+ if (typeof value === "symbol") {
725
+ throw new Error(`[vertz] Island "${islandId}" received a Symbol prop "${key}". ` + "Island props must be JSON-serializable.");
726
+ }
727
+ }
728
+ }
729
+ function Island({ id, component: Component, props = {} }) {
730
+ const islandId = id ?? Component.name ?? "Island";
731
+ validateSerializable(props, islandId);
732
+ if (getIsHydrating()) {
733
+ const claimed = claimElement("div");
734
+ if (claimed) {
735
+ enterChildren(claimed);
736
+ claimElement("script");
737
+ Component(props);
738
+ exitChildren();
739
+ return claimed;
740
+ }
741
+ }
742
+ const wrapper = document.createElement("div");
743
+ wrapper.setAttribute("data-v-island", islandId);
744
+ const script = document.createElement("script");
745
+ script.setAttribute("data-v-island-props", "");
746
+ script.setAttribute("type", "application/json");
747
+ script.textContent = JSON.stringify(props);
748
+ wrapper.appendChild(script);
749
+ const content = Component(props);
750
+ if (content != null) {
751
+ if (content instanceof Node) {
752
+ wrapper.appendChild(content);
753
+ } else if (typeof content === "string") {
754
+ wrapper.appendChild(document.createTextNode(content));
755
+ }
756
+ }
757
+ return wrapper;
758
+ }
623
759
  // src/mount.ts
624
760
  var MOUNTED_KEY = Symbol.for("vertz:mounted-roots");
625
761
  var _global = globalThis;
@@ -766,8 +902,10 @@ export {
766
902
  keyframes,
767
903
  isRenderNode,
768
904
  isQueryDescriptor,
905
+ isBrowser,
769
906
  invalidate,
770
907
  injectCSS,
908
+ hydrateIslands,
771
909
  hydrate,
772
910
  globalCss,
773
911
  getRelationSchema,
@@ -777,6 +915,7 @@ export {
777
915
  getAdapter,
778
916
  formDataToObject,
779
917
  form,
918
+ font,
780
919
  fadeOut,
781
920
  fadeIn,
782
921
  defineTheme,
@@ -790,9 +929,12 @@ export {
790
929
  createDialogStack,
791
930
  createDOMAdapter,
792
931
  createContext,
932
+ configureImageOptimizer,
793
933
  computed,
794
934
  compileTheme,
935
+ compileFonts,
795
936
  children,
937
+ buildOptimizedUrl,
796
938
  batch,
797
939
  accordionUp,
798
940
  accordionDown,
@@ -811,6 +953,10 @@ export {
811
953
  OutletContext,
812
954
  Outlet,
813
955
  ListTransition,
956
+ Link,
957
+ Island,
958
+ Image,
959
+ FieldSelectionTracker,
814
960
  ErrorBoundary,
815
961
  EntityStore,
816
962
  DisposalScopeError,
@@ -80,6 +80,49 @@ declare function getContextScope(): ContextScope | null;
80
80
  * @internal
81
81
  */
82
82
  declare function setContextScope(scope: ContextScope | null): ContextScope | null;
83
+ interface FontSrc {
84
+ path: string;
85
+ weight?: string | number;
86
+ style?: "normal" | "italic";
87
+ }
88
+ type FallbackFontName = "Arial" | "Times New Roman" | "Courier New";
89
+ interface FontFallbackMetrics {
90
+ /** CSS ascent-override value, e.g., '94.52%' */
91
+ ascentOverride: string;
92
+ /** CSS descent-override value, e.g., '24.60%' */
93
+ descentOverride: string;
94
+ /** CSS line-gap-override value, e.g., '0.00%' */
95
+ lineGapOverride: string;
96
+ /** CSS size-adjust value, e.g., '104.88%' */
97
+ sizeAdjust: string;
98
+ /** System font used as fallback base. */
99
+ fallbackFont: FallbackFontName;
100
+ }
101
+ interface CompileFontsOptions {
102
+ /** Pre-computed fallback metrics per font key. Provided by @vertz/ui-server at build/SSR time. */
103
+ fallbackMetrics?: Record<string, FontFallbackMetrics>;
104
+ }
105
+ type FontStyle = "normal" | "italic";
106
+ type FontDisplay = "auto" | "block" | "swap" | "fallback" | "optional";
107
+ interface FontDescriptor {
108
+ readonly __brand: "FontDescriptor";
109
+ readonly family: string;
110
+ readonly weight: string;
111
+ readonly style: FontStyle;
112
+ readonly display: FontDisplay;
113
+ readonly src?: string | FontSrc[];
114
+ readonly fallback: string[];
115
+ readonly subsets: string[];
116
+ readonly unicodeRange?: string;
117
+ readonly adjustFontFallback: boolean | FallbackFontName;
118
+ }
119
+ /** Structured description of a resource to preload. */
120
+ interface PreloadItem {
121
+ href: string;
122
+ as: "font" | "image" | "style" | "script";
123
+ type?: string;
124
+ crossorigin?: boolean;
125
+ }
83
126
  /** Color tokens: a map of color names to their raw/contextual values. */
84
127
  type ColorTokens = Record<string, Record<string, string>>;
85
128
  /** Spacing tokens: a flat map of names to CSS values. */
@@ -90,6 +133,8 @@ interface Theme {
90
133
  colors: ColorTokens;
91
134
  /** Spacing scale tokens. */
92
135
  spacing?: SpacingTokens;
136
+ /** Font descriptors keyed by token name. */
137
+ fonts?: Record<string, FontDescriptor>;
93
138
  }
94
139
  /** Output of compileTheme(). */
95
140
  interface CompiledTheme {
@@ -97,6 +142,15 @@ interface CompiledTheme {
97
142
  css: string;
98
143
  /** Flat list of token dot-paths (e.g., 'primary.500', 'background'). */
99
144
  tokens: string[];
145
+ /** Font preload link tags for injection into <head>. */
146
+ preloadTags: string;
147
+ /** Structured preload data for generating HTTP Link headers. */
148
+ preloadItems: PreloadItem[];
149
+ }
150
+ /** Options for compileTheme(). */
151
+ interface CompileThemeOptions {
152
+ /** Pre-computed font fallback metrics for zero-CLS font loading. */
153
+ fallbackMetrics?: CompileFontsOptions["fallbackMetrics"];
100
154
  }
101
155
  /**
102
156
  * Compile a theme into CSS custom properties.
@@ -108,7 +162,7 @@ interface CompiledTheme {
108
162
  * @param theme - A theme object from defineTheme().
109
163
  * @returns Compiled CSS and token list.
110
164
  */
111
- declare function compileTheme(theme: Theme): CompiledTheme;
165
+ declare function compileTheme(theme: Theme, options?: CompileThemeOptions): CompiledTheme;
112
166
  /**
113
167
  * Shared CSS token lookup tables.
114
168
  *
@@ -383,12 +437,23 @@ declare function clearChildren(container: Node): void;
383
437
  * @returns A dispose function to stop the reactive list reconciliation
384
438
  */
385
439
  declare function __list<T>(container: HTMLElement, items: Signal<T[]> | (() => T[]), keyFn: (item: T, index: number) => string | number, renderFn: (item: T) => Node): DisposeFn;
440
+ /**
441
+ * Returns true when running in a real browser environment.
442
+ * Returns false on the server, even if `window` exists (DOM shim).
443
+ *
444
+ * Uses `hasSSRResolver()` — which returns true when an SSR resolver
445
+ * has been registered — instead of `getSSRContext()` which only returns
446
+ * a value inside `ssrStorage.run()`. This correctly identifies server
447
+ * module-scope code (e.g., HMR re-imports where `createRouter()` runs
448
+ * at import time, outside any SSR render context).
449
+ */
450
+ declare function isBrowser(): boolean;
386
451
  /** A function returning a dynamic import of a component module. */
387
452
  type ComponentLoader = () => Promise<{
388
453
  default: ComponentFunction;
389
454
  }>;
390
- /** A component function that takes props and an element to mount into. */
391
- type ComponentFunction = (props: Record<string, unknown>, el: Element) => void;
455
+ /** A component function that takes props and optionally an element to mount into. May return a Node. */
456
+ type ComponentFunction = (props: Record<string, unknown>, el?: Element) => Node | void;
392
457
  /** Maps component IDs to their dynamic import loaders. */
393
458
  type ComponentRegistry = Record<string, ComponentLoader>;
394
459
  /**
@@ -413,14 +478,27 @@ interface CacheStore<T = unknown> {
413
478
  clear?(): void;
414
479
  }
415
480
  /**
416
- * Default in-memory cache backed by a Map.
481
+ * Default in-memory cache backed by a Map with optional LRU eviction.
482
+ *
483
+ * When `maxSize` is finite, least-recently-used entries are evicted on `set()`
484
+ * when the cache exceeds the limit. `get()` promotes entries to most-recently-used.
417
485
  */
418
486
  declare class MemoryCache<T = unknown> implements CacheStore<T> {
419
487
  private _store;
488
+ private _maxSize;
489
+ private _refs;
490
+ private _orphans;
491
+ constructor(options?: {
492
+ maxSize?: number;
493
+ });
420
494
  get(key: string): T | undefined;
421
495
  set(key: string, value: T): void;
422
496
  delete(key: string): void;
423
497
  clear(): void;
498
+ /** Mark a cache key as actively used by a query instance. */
499
+ retain(key: string): void;
500
+ /** Release a cache key when a query instance disposes or changes key. */
501
+ release(key: string): void;
424
502
  }
425
503
  /**
426
504
  * Derive a cache key from a thunk function.
@@ -492,6 +570,8 @@ interface RouteConfig<
492
570
  searchParams?: SearchParamSchema<TSearch>;
493
571
  /** Nested child routes. */
494
572
  children?: RouteDefinitionMap;
573
+ /** Whether to pre-render this route at build time (default: true for static routes). */
574
+ prerender?: boolean;
495
575
  }
496
576
  /** A map of path patterns to route configs (user input format). */
497
577
  interface RouteDefinitionMap {
@@ -513,6 +593,8 @@ interface CompiledRoute {
513
593
  searchParams?: RouteConfig["searchParams"];
514
594
  /** Compiled children. */
515
595
  children?: CompiledRoute[];
596
+ /** Whether to pre-render this route at build time (default: true for static routes). */
597
+ prerender?: boolean;
516
598
  }
517
599
  /** A single matched route entry in the matched chain. */
518
600
  interface MatchedRoute {
@@ -666,11 +748,22 @@ interface SerializedStore {
666
748
  }>;
667
749
  }
668
750
  /**
751
+ * Options for mergeWithSelect — metadata about field selection.
752
+ */
753
+ interface MergeSelectOptions {
754
+ /** Fields that were part of the query's select set */
755
+ fields: string[];
756
+ /** Query source identifier for diagnostics (e.g., 'GET:/users') */
757
+ querySource: string;
758
+ }
759
+ /**
669
760
  * Options for EntityStore constructor.
670
761
  */
671
762
  interface EntityStoreOptions {
672
763
  /** Initial data to hydrate from (SSR). */
673
764
  initialData?: SerializedStore;
765
+ /** Enable dev-mode field selection tracking (zero overhead when false). */
766
+ devMode?: boolean;
674
767
  }
675
768
  /**
676
769
  * EntityStore - Normalized, signal-backed entity cache for @vertz/ui.
@@ -682,6 +775,7 @@ declare class EntityStore {
682
775
  private _entities;
683
776
  private _typeListeners;
684
777
  private _queryIndices;
778
+ private _fieldTracker;
685
779
  /** Public accessor for query indices — used by optimistic handlers and tests. */
686
780
  get queryIndices(): QueryResultIndex;
687
781
  constructor(options?: EntityStoreOptions);
@@ -705,6 +799,14 @@ declare class EntityStore {
705
799
  id: string;
706
800
  }>(type: string, data: T | T[]): void;
707
801
  /**
802
+ * Merge entities with field selection metadata.
803
+ * Registers the select set for dev-mode access warnings.
804
+ * In production (devMode: false), behaves identically to merge().
805
+ */
806
+ mergeWithSelect<T extends {
807
+ id: string;
808
+ }>(type: string, data: T | T[], selectOptions: MergeSelectOptions): void;
809
+ /**
708
810
  * Remove an entity from the store.
709
811
  * Triggers type change listeners and removes from query indices.
710
812
  */
@@ -790,8 +892,15 @@ declare class EntityStore {
790
892
  private _mergeOne;
791
893
  /**
792
894
  * Recompute the visible signal value from base + all layers.
895
+ * Uses lastPlainVisible for equality check to avoid triggering
896
+ * field selection Proxy warnings during internal store operations.
793
897
  */
794
898
  private _recomputeVisible;
899
+ /**
900
+ * Wrap entity in dev-mode Proxy for field selection warnings.
901
+ * No-op when devMode is off or no tracking exists.
902
+ */
903
+ private _wrapWithFieldProxy;
795
904
  private _getOrCreateTypeMap;
796
905
  private _getOrCreateListeners;
797
906
  private _notifyTypeChange;
@@ -843,8 +952,62 @@ interface SSRRenderContext {
843
952
  errors: unknown[];
844
953
  /** Global per-query timeout override (ms). */
845
954
  globalSSRTimeout?: number;
955
+ /**
956
+ * Lazy route component Promises registered by RouterView during Pass 1.
957
+ * Keyed by CompiledRoute object identity to avoid pattern string collisions.
958
+ */
959
+ pendingRouteComponents?: Map<object, Promise<{
960
+ default: () => Node;
961
+ }>>;
962
+ /**
963
+ * Resolved sync factories, populated between Pass 1 and Pass 2.
964
+ * Keyed by CompiledRoute object identity.
965
+ */
966
+ resolvedComponents?: Map<object, () => Node>;
967
+ /**
968
+ * Route patterns discovered by createRouter() during SSR.
969
+ * Used by the build pipeline to discover which routes to pre-render.
970
+ */
971
+ discoveredRoutes?: string[];
972
+ /**
973
+ * Auth state resolved by the server (e.g. from session cookie).
974
+ * Set by ssrRenderToString() before Pass 1 so AuthProvider can
975
+ * hydrate status/user synchronously during SSR.
976
+ */
977
+ ssrAuth?: SSRAuth;
978
+ /**
979
+ * Written by ProtectedRoute during Pass 1 when the user is not
980
+ * authenticated. Signals ssrRenderToString() to skip Pass 2 and
981
+ * return a redirect response instead.
982
+ */
983
+ ssrRedirect?: {
984
+ to: string;
985
+ };
846
986
  }
987
+ /** Auth state injected into SSRRenderContext by the server. */
988
+ type SSRAuth = {
989
+ status: "authenticated";
990
+ user: {
991
+ id: string;
992
+ email: string;
993
+ role: string;
994
+ [key: string]: unknown;
995
+ };
996
+ expiresAt: number;
997
+ } | {
998
+ status: "unauthenticated";
999
+ };
847
1000
  type SSRContextResolver = () => SSRRenderContext | undefined;
848
1001
  declare function registerSSRResolver(resolver: SSRContextResolver | null): void;
849
1002
  declare function getSSRContext(): SSRRenderContext | undefined;
850
- export { stopSignalCollection, startSignalCollection, setContextScope, setAdapter, runCleanups, resolveComponent, removeNode, registerSSRResolver, pushScope, popScope, onCleanup, onAnimationsComplete, matchRoute, matchPath, lifecycleEffect, isRenderNode, insertBefore, getSSRContext, getContextScope, getAdapter, executeLoaders, domEffect, deserializeProps, deriveKey, createDOMAdapter, compileTheme, clearChildren, _tryOnCleanup, __text, __staticText, __show, __on, __list, __insert, __exitChildren, __enterChildren, __element, __conditional, __classList, __child, __attr, __append, SSRRenderContext, SSRQueryEntry, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RenderText, RenderNode, RenderElement, RenderAdapter, RENDER_NODE_BRAND, RADIUS_SCALE, QueryEnvelopeStore, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, EntityStore, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
1003
+ /**
1004
+ * Returns true when an SSR resolver has been registered.
1005
+ *
1006
+ * This indicates we are running on the server — regardless of whether
1007
+ * an SSR render is currently active. The resolver is registered once
1008
+ * at import time by `@vertz/ui-server` and never cleared during the
1009
+ * server's lifetime. Stored on globalThis so it survives require.cache
1010
+ * clears during HMR module re-evaluation.
1011
+ */
1012
+ declare function hasSSRResolver(): boolean;
1013
+ export { stopSignalCollection, startSignalCollection, setContextScope, setAdapter, runCleanups, resolveComponent, removeNode, registerSSRResolver, pushScope, popScope, onCleanup, onAnimationsComplete, matchRoute, matchPath, lifecycleEffect, isRenderNode, isBrowser, insertBefore, hasSSRResolver, getSSRContext, getContextScope, getAdapter, executeLoaders, domEffect, deserializeProps, deriveKey, createDOMAdapter, compileTheme, clearChildren, _tryOnCleanup, __text, __staticText, __show, __on, __list, __insert, __exitChildren, __enterChildren, __element, __conditional, __classList, __child, __attr, __append, SSRRenderContext, SSRQueryEntry, SSRAuth, SPACING_SCALE, SIZE_KEYWORDS, SHADOW_SCALE, RenderText, RenderNode, RenderElement, RenderAdapter, RENDER_NODE_BRAND, RADIUS_SCALE, QueryEnvelopeStore, PropertyMapping, PSEUDO_PREFIXES, PSEUDO_MAP, PROPERTY_MAP, MemoryCache, MatchResult, LINE_HEIGHT_SCALE, KEYWORD_MAP, HEIGHT_AXIS_PROPERTIES, FONT_WEIGHT_SCALE, FONT_SIZE_SCALE, EntityStore, DISPLAY_MAP, CSS_COLOR_KEYWORDS, CSSDeclarationEntry, CONTENT_MAP, COLOR_NAMESPACES, ALIGNMENT_MAP };
@@ -2,24 +2,24 @@ import {
2
2
  deserializeProps,
3
3
  onAnimationsComplete,
4
4
  resolveComponent
5
- } from "../shared/chunk-4txc67nd.js";
5
+ } from "../shared/chunk-6jyt4ycw.js";
6
6
  import {
7
7
  __attr,
8
8
  __classList,
9
9
  __on,
10
10
  __show
11
- } from "../shared/chunk-dksg08fq.js";
11
+ } from "../shared/chunk-07bh4m1e.js";
12
12
  import {
13
13
  executeLoaders,
14
14
  matchPath,
15
15
  matchRoute
16
- } from "../shared/chunk-83g4h38e.js";
16
+ } from "../shared/chunk-6wd36w21.js";
17
17
  import {
18
18
  EntityStore,
19
19
  MemoryCache,
20
20
  QueryEnvelopeStore,
21
21
  deriveKey
22
- } from "../shared/chunk-hw67ckr3.js";
22
+ } from "../shared/chunk-fs3eec4b.js";
23
23
  import"../shared/chunk-jrtrk5z4.js";
24
24
  import {
25
25
  ALIGNMENT_MAP,
@@ -40,7 +40,7 @@ import {
40
40
  SIZE_KEYWORDS,
41
41
  SPACING_SCALE,
42
42
  compileTheme
43
- } from "../shared/chunk-1wby7nex.js";
43
+ } from "../shared/chunk-dhehvmj0.js";
44
44
  import {
45
45
  __append,
46
46
  __child,
@@ -53,7 +53,7 @@ import {
53
53
  claimComment,
54
54
  claimText,
55
55
  getIsHydrating
56
- } from "../shared/chunk-j6qyxfdc.js";
56
+ } from "../shared/chunk-vndfjfdy.js";
57
57
  import"../shared/chunk-prj7nm08.js";
58
58
  import {
59
59
  RENDER_NODE_BRAND,
@@ -61,12 +61,16 @@ import {
61
61
  getAdapter,
62
62
  isRenderNode,
63
63
  setAdapter
64
- } from "../shared/chunk-h89w580h.js";
64
+ } from "../shared/chunk-afawz764.js";
65
+ import {
66
+ isBrowser
67
+ } from "../shared/chunk-14eqne2a.js";
65
68
  import {
66
69
  _tryOnCleanup,
67
70
  domEffect,
68
71
  getContextScope,
69
72
  getSSRContext,
73
+ hasSSRResolver,
70
74
  lifecycleEffect,
71
75
  onCleanup,
72
76
  popScope,
@@ -77,7 +81,7 @@ import {
77
81
  signal,
78
82
  startSignalCollection,
79
83
  stopSignalCollection
80
- } from "../shared/chunk-8hsz5y4a.js";
84
+ } from "../shared/chunk-4fwcwxn6.js";
81
85
  // src/dom/conditional.ts
82
86
  function normalizeNode(branchResult) {
83
87
  if (branchResult == null || typeof branchResult === "boolean") {
@@ -325,7 +329,9 @@ export {
325
329
  matchPath,
326
330
  lifecycleEffect,
327
331
  isRenderNode,
332
+ isBrowser,
328
333
  insertBefore,
334
+ hasSSRResolver,
329
335
  getSSRContext,
330
336
  getContextScope,
331
337
  getAdapter,
@@ -1,3 +1,7 @@
1
+ /** A ref container for DOM element access. */
2
+ interface Ref<T> {
3
+ current: T | undefined;
4
+ }
1
5
  /**
2
6
  * JSX namespace - required for TypeScript's react-jsx mode
3
7
  * to understand intrinsic element types and component types.
@@ -11,6 +15,7 @@ declare namespace JSX {
11
15
  }
12
16
  interface IntrinsicAttributes {
13
17
  key?: string | number;
18
+ ref?: Ref<unknown> | ((el: Element) => void);
14
19
  }
15
20
  interface IntrinsicElements {
16
21
  [key: string]: HTMLAttributes | undefined;
@@ -26,7 +26,7 @@ function jsxImpl(tag, props) {
26
26
  if (typeof tag === "function") {
27
27
  return tag(props || {});
28
28
  }
29
- const { children, ...attrs } = props || {};
29
+ const { children, ref: refProp, ...attrs } = props || {};
30
30
  const svg = isSVGTag(tag);
31
31
  const element = svg ? document.createElementNS(SVG_NS, tag) : document.createElement(tag);
32
32
  for (const [key, value] of Object.entries(attrs)) {
@@ -45,6 +45,13 @@ function jsxImpl(tag, props) {
45
45
  }
46
46
  }
47
47
  applyChildren(element, children);
48
+ if (refProp != null) {
49
+ if (typeof refProp === "function") {
50
+ refProp(element);
51
+ } else if (typeof refProp === "object" && "current" in refProp) {
52
+ refProp.current = element;
53
+ }
54
+ }
48
55
  return element;
49
56
  }
50
57
  function jsx(tag, props) {
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  query,
3
3
  queryMatch
4
- } from "../../shared/chunk-hw67ckr3.js";
4
+ } from "../../shared/chunk-fs3eec4b.js";
5
5
  import"../../shared/chunk-jrtrk5z4.js";
6
- import"../../shared/chunk-h89w580h.js";
7
- import"../../shared/chunk-8hsz5y4a.js";
6
+ import"../../shared/chunk-afawz764.js";
7
+ import"../../shared/chunk-14eqne2a.js";
8
+ import"../../shared/chunk-4fwcwxn6.js";
8
9
 
9
10
  // src/query/public.ts
10
11
  import { isQueryDescriptor } from "@vertz/fetch";