streetui 1.9.0 → 2.1.0

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.
@@ -7,7 +7,7 @@
7
7
  * (`streetui --version`) — the consolidated test-suite pins all three to the
8
8
  * same coordinated release so they can never silently drift apart.
9
9
  */
10
- declare const VERSION = "1.9.0";
10
+ declare const VERSION = "2.1.0";
11
11
 
12
12
  /**
13
13
  * StreetUI reactive signals — framework-owned reactivity, no external libraries.
@@ -128,6 +128,86 @@ declare function signalKind(source: ReadonlySignal<unknown>): SignalKind;
128
128
  */
129
129
  declare function observerCount(source: ReadonlySignal<unknown>): number | undefined;
130
130
 
131
+ /**
132
+ * StreetUI async resources — framework-native asynchronous data.
133
+ *
134
+ * A `resource` wraps a Promise-returning loader and exposes its lifecycle as
135
+ * ordinary StreetUI signals (status / data / error), so it composes with
136
+ * `derived`, `effect`, `when()`, `listOf` and the renderer with no second
137
+ * reactive system.
138
+ *
139
+ * State machine:
140
+ *
141
+ * idle ──(load)──▶ loading ──(resolve)──▶ success
142
+ * │
143
+ * └────(reject)──────▶ error
144
+ *
145
+ * Refetch keeps the previously-loaded `data` visible while `status` is
146
+ * `'loading'` again (see `isRefetching`) — there is no separate `'refetching'`
147
+ * status; it is expressed through `status === 'loading'` with `data` still set.
148
+ *
149
+ * The resource is transport-agnostic: the loader is any function returning a
150
+ * value or a Promise. When it accepts the provided `AbortSignal`, in-flight
151
+ * work is cancelled on `dispose()` or when a newer request supersedes it.
152
+ */
153
+
154
+ type ResourceStatus = 'idle' | 'loading' | 'success' | 'error';
155
+ /** Context handed to the loader; carries an AbortSignal for cancellation. */
156
+ interface ResourceLoaderContext {
157
+ readonly signal: AbortSignal;
158
+ }
159
+ /** Any value-or-Promise producing function. Receives an abort-aware context. */
160
+ type ResourceLoader<T> = (ctx: ResourceLoaderContext) => Promise<T> | T;
161
+ interface ResourceOptions<T = unknown> {
162
+ /** Load immediately on creation. Defaults to `true`. When `false`, stays `idle` until `refetch()`. */
163
+ readonly immediate?: boolean;
164
+ /**
165
+ * Explicit reactive dependencies. When any listed signal changes, the
166
+ * resource refetches. Dependencies are explicit (not auto-tracked from the
167
+ * loader body) so there is no risk of an accidental infinite refetch loop.
168
+ */
169
+ readonly watch?: ReadonlyArray<ReadonlySignal<unknown>>;
170
+ /**
171
+ * Optional teardown registrar (e.g. a route's `ctx.onCleanup`). When given,
172
+ * the resource registers its own `dispose` so it is cleaned up automatically
173
+ * when its owner is removed.
174
+ */
175
+ readonly onCleanup?: (fn: () => void) => void;
176
+ /**
177
+ * Server-provided initial value for hydration. When present the resource
178
+ * starts in `'success'` with this data already visible, and the initial
179
+ * auto-load is skipped (so the client does not refetch data the server
180
+ * already resolved). This is the client half of SSR resource transfer; the
181
+ * server side awaits `refetch()` before serializing. Set `immediate: true`
182
+ * explicitly to force a client refetch anyway.
183
+ */
184
+ readonly initialData?: T;
185
+ /** Server-provided initial error for hydration (mirrors `initialData`). */
186
+ readonly initialError?: unknown;
187
+ /**
188
+ * Explicit initial status override. Rarely needed — inferred as `'success'`
189
+ * from `initialData` or `'error'` from `initialError`.
190
+ */
191
+ readonly initialStatus?: ResourceStatus;
192
+ }
193
+ interface Resource<T> {
194
+ /** Reactive lifecycle status. */
195
+ readonly status: ReadonlySignal<ResourceStatus>;
196
+ /** The last successfully-loaded value, or `undefined` before first success. */
197
+ readonly data: ReadonlySignal<T | undefined>;
198
+ /** The most recent error, or `undefined` when there is none. Typed `unknown` — never `any`. */
199
+ readonly error: ReadonlySignal<unknown>;
200
+ /** Convenience: `status === 'loading'`. */
201
+ readonly loading: ReadonlySignal<boolean>;
202
+ /** Convenience: loading while previously-loaded data is still present (a refetch). */
203
+ readonly isRefetching: ReadonlySignal<boolean>;
204
+ /** Trigger a new request. Resolves when the request settles (or is superseded). */
205
+ refetch(): Promise<void>;
206
+ /** Cancel in-flight work, drop watchers, and ignore any late results. Idempotent. */
207
+ dispose(): void;
208
+ }
209
+ declare function resource<T>(loader: ResourceLoader<T>, options?: ResourceOptions<T>): Resource<T>;
210
+
131
211
  /**
132
212
  * Node and application identity utilities.
133
213
  * Every node in the semantic graph has a stable, unique identity.
@@ -195,7 +275,7 @@ declare function formatDiagnostic(d: Diagnostic): string;
195
275
  * in the Semantic Application Graph.
196
276
  */
197
277
 
198
- type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal';
278
+ type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal' | 'head';
199
279
  interface NodeMetadata {
200
280
  readonly createdAt: number;
201
281
  readonly [key: string]: unknown;
@@ -530,6 +610,134 @@ declare function resolveTransition(config: TransitionConfig): ResolvedTransition
530
610
  /** Runtime brand check for a transition descriptor value. */
531
611
  declare function isTransitionConfig(value: unknown): value is TransitionConfig;
532
612
 
613
+ /**
614
+ * Document head / metadata model (2.0 §1–§3).
615
+ *
616
+ * `head({...})` is a first-class StreetUI primitive for declaring document
617
+ * metadata — title, meta, link, canonical, Open Graph, Twitter/X, robots,
618
+ * theme-color and favicon. It is NOT a copy of another framework's API: it is
619
+ * expressed on StreetUI's own component/graph model. A `head()` call creates a
620
+ * `'head'` graph node (rendered as a neutral inline anchor, like a portal) and
621
+ * registers a `__head__<nodeId>` descriptor — exactly the handler-registry
622
+ * convention used by `__overlay__`/`__transition__`/`__component__`. The
623
+ * renderer reads that descriptor to:
624
+ *
625
+ * • apply the contribution to `document.head` on the browser
626
+ * (`wireHeadBehavior`), adopting server-emitted tags on hydration so there
627
+ * are no duplicates, and cleaning up its own tags on unmount / route change;
628
+ * • emit only the active graph's merged metadata as an HTML string on the
629
+ * server (`renderHead`).
630
+ *
631
+ * This module is pure and DOM-free (like `transition.ts`): it defines the config
632
+ * shape and normalises it into an ordered list of {@link HeadEntry} with stable
633
+ * *dedup keys*. All merge/precedence/DOM work happens in the renderer, keyed by
634
+ * these entries.
635
+ *
636
+ * ── Deduplication & precedence (§3) ──────────────────────────────────────────
637
+ * Every entry carries a `dedupKey`. When several `head()` nodes are live at once
638
+ * (e.g. an app-level default, a route-level `head()`, and a component-level
639
+ * `head()`), the renderer merges all of their entries and, for each `dedupKey`,
640
+ * the LAST contribution in document order wins. Document order is pre-order DFS
641
+ * = mount order, so a `head()` declared deeper/later (a route or a component
642
+ * nested inside the app shell) deterministically overrides an app-level default
643
+ * for the same key. Removing that node (navigating away, unmounting the
644
+ * component) re-exposes the previously-shadowed default. `<title>` and each
645
+ * single-instance meta/link (description, robots, theme-color, viewport,
646
+ * charset, canonical, favicon, and each og: or twitter: property) collapse to one
647
+ * effective tag; generic `meta[]`/`link[]` array entries are keyed by their
648
+ * identifying attributes so independent tags coexist.
649
+ */
650
+
651
+ /** A head value that may be a literal string or a reactive signal of a string. */
652
+ type BindableString = string | ReadonlySignal<string> | Signal<string>;
653
+ /** A single `<meta>` descriptor. Provide exactly one identifying key. */
654
+ interface MetaDescriptor {
655
+ /** `name="…"` (e.g. "description", "robots", "theme-color", "twitter:card"). */
656
+ readonly name?: string;
657
+ /** `property="…"` (e.g. "og:title", "og:image") — the Open Graph convention. */
658
+ readonly property?: string;
659
+ /** `http-equiv="…"` (e.g. "content-security-policy"). */
660
+ readonly httpEquiv?: string;
661
+ /** `charset="…"` (e.g. "utf-8"). Standalone; no `content`. */
662
+ readonly charset?: string;
663
+ /** The tag's `content`. May be reactive. */
664
+ readonly content?: BindableString;
665
+ }
666
+ /** A single `<link>` descriptor. `rel`+`href` identify it. */
667
+ interface LinkDescriptor {
668
+ readonly rel: string;
669
+ readonly href: string;
670
+ readonly sizes?: string;
671
+ readonly type?: string;
672
+ readonly media?: string;
673
+ readonly as?: string;
674
+ readonly crossorigin?: string;
675
+ readonly hreflang?: string;
676
+ }
677
+ /**
678
+ * Declarative document metadata. Every field is optional; convenience fields
679
+ * (title/description/canonical/robots/themeColor/viewport/charset/favicon/
680
+ * openGraph/twitter) expand into the same normalized entries as the raw
681
+ * `meta`/`link` arrays, with single-instance dedup keys so a later `head()`
682
+ * cleanly overrides an earlier one.
683
+ */
684
+ interface HeadMetadata {
685
+ /** `<title>` text. May be reactive. Single-instance (dedup key `title`). */
686
+ readonly title?: BindableString;
687
+ /** `<meta name="description">`. May be reactive. */
688
+ readonly description?: BindableString;
689
+ /** `<link rel="canonical">` href. */
690
+ readonly canonical?: string;
691
+ /** `<meta name="robots">` (e.g. "index,follow" / "noindex"). */
692
+ readonly robots?: string;
693
+ /** `<meta name="theme-color">`. */
694
+ readonly themeColor?: string;
695
+ /** `<meta name="viewport">`. */
696
+ readonly viewport?: string;
697
+ /** `<meta charset>`. */
698
+ readonly charset?: string;
699
+ /** Favicon: a shorthand for `<link rel="icon">`. String = href, or a full descriptor. */
700
+ readonly favicon?: string | LinkDescriptor;
701
+ /** Open Graph properties — each key `k` becomes `<meta property="og:k">`. Values may be reactive. */
702
+ readonly openGraph?: Readonly<Record<string, BindableString>>;
703
+ /** Twitter/X card properties — each key `k` becomes `<meta name="twitter:k">`. Values may be reactive. */
704
+ readonly twitter?: Readonly<Record<string, BindableString>>;
705
+ /** Raw `<meta>` tags (for anything the convenience fields don't cover). */
706
+ readonly meta?: readonly MetaDescriptor[];
707
+ /** Raw `<link>` tags (stylesheets, preload, alternate, etc.). */
708
+ readonly link?: readonly LinkDescriptor[];
709
+ /** `<base href>` — single-instance. */
710
+ readonly base?: string;
711
+ }
712
+ /**
713
+ * A normalized head tag: one `<title>`, `<meta>`, `<link>` or `<base>`. Attr
714
+ * values and the title's text may still be reactive (`BindableString`); the
715
+ * renderer peeks them for SSR and subscribes to them on the browser. `dedupKey`
716
+ * is what the merge collapses on.
717
+ */
718
+ interface HeadEntry {
719
+ readonly tag: 'title' | 'meta' | 'link' | 'base';
720
+ readonly dedupKey: string;
721
+ /** Static + reactive attributes (no `undefined` values). */
722
+ readonly attrs: Readonly<Record<string, BindableString>>;
723
+ /** Text content — only meaningful for `tag === 'title'`. */
724
+ readonly text?: BindableString;
725
+ }
726
+ /** The value a `__head__<id>` handler returns: this node's ordered contribution. */
727
+ interface HeadContribution {
728
+ readonly entries: readonly HeadEntry[];
729
+ }
730
+ /**
731
+ * Normalise a {@link HeadMetadata} into an ordered list of {@link HeadEntry}.
732
+ * Emission order within one `head()` is: charset → base → title → description →
733
+ * canonical → robots → theme-color → viewport → favicon → openGraph → twitter →
734
+ * explicit meta[] → explicit link[]. (Merge across nodes is document order; this
735
+ * per-node order only affects the sequence of same-priority tags.)
736
+ */
737
+ declare function resolveHead(config: HeadMetadata): HeadContribution;
738
+ /** Runtime brand check for a head-contribution descriptor value. */
739
+ declare function isHeadContribution(value: unknown): value is HeadContribution;
740
+
533
741
  /**
534
742
  * StreetUI DSL type system.
535
743
  * All builder callbacks and option shapes live here.
@@ -722,6 +930,40 @@ interface ErrorBoundaryOptions {
722
930
  readonly source?: ErrorSource | ReadonlyArray<ErrorSource>;
723
931
  /** Invoked by the fallback's `retry()`, before the body is re-attempted (e.g. `resource.refetch`). */
724
932
  readonly onRetry?: () => void;
933
+ /**
934
+ * Error-reporting hook (§6/§7). Called with the current error each time the
935
+ * boundary ENTERS its error state (i.e. when the fallback mounts), including
936
+ * on a re-entry after a failed retry. Use it to forward the error to a
937
+ * production diagnostics sink. It observes only — it never changes the
938
+ * boundary's behavior, and receives the same `unknown` error the fallback
939
+ * sees (no sensitive framework internals are injected).
940
+ */
941
+ readonly onError?: (error: unknown) => void;
942
+ }
943
+ /**
944
+ * Branch builders for {@link ContainerDSL.asyncBoundary} — the loading / error /
945
+ * success states of a {@link Resource}. This is deliberately NOT a new async
946
+ * system: it is thin sugar over the existing `resource` state machine and
947
+ * `when()`. Exactly one branch is live at a time, chosen by the resource's
948
+ * reactive `status`/`data` (error takes precedence, then resolved data, then
949
+ * loading), so mounting/unmounting and cleanup all reuse the conditional
950
+ * machinery. Branch signature mirrors `errorBoundary`'s fallback: the content
951
+ * scope comes first.
952
+ */
953
+ interface AsyncBoundaryBranches<T> {
954
+ /** Shown while the resource is idle or performing its first load (no data yet). */
955
+ readonly loading?: (content: ContainerDSL) => void;
956
+ /**
957
+ * Shown while the resource is in its error state. Receives the current error
958
+ * and a `retry()` that re-runs the loader (a thin wrapper over `refetch`).
959
+ */
960
+ readonly error?: (content: ContainerDSL, error: unknown, retry: () => void) => void;
961
+ /**
962
+ * Shown once the resource has data (including while a refetch keeps the old
963
+ * value visible). Receives the data as a `ReadonlySignal<T>` so the branch can
964
+ * bind it reactively and update in place without remounting.
965
+ */
966
+ readonly success: (content: ContainerDSL, data: ReadonlySignal<T>) => void;
725
967
  }
726
968
  interface ContentDSL {
727
969
  heading(text: BindableText, options?: HeadingOptions): void;
@@ -762,6 +1004,23 @@ interface ContainerDSL extends ContentDSL {
762
1004
  * removal. It does NOT trap arbitrary global errors; errors remain observable.
763
1005
  */
764
1006
  errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
1007
+ /**
1008
+ * Render the loading / error / success states of an async {@link Resource}
1009
+ * (§4). This is sugar over the existing `resource` state machine and `when()`
1010
+ * — NOT a second async system and NOT a literal port of React Suspense. It
1011
+ * renders exactly one branch at a time based on the resource's reactive state:
1012
+ * the `error` branch while `status === 'error'` (with a `retry()` that calls
1013
+ * `refetch`), otherwise the `success` branch once data is present (data passed
1014
+ * as a `ReadonlySignal<T>` so it updates in place, and stays visible while a
1015
+ * refetch is in flight), otherwise the `loading` branch. Because it is built
1016
+ * from `when()`, SSR renders whichever branch matches the resource's current
1017
+ * (peeked) state — so a server that awaits the resource before serializing
1018
+ * emits the resolved `success` branch, and hydration (seeded via the
1019
+ * resource's `initialData`) reuses it with no duplicate work. Resource
1020
+ * cleanup/cancellation is the resource's own concern (pass its `dispose` to
1021
+ * the owning scope's `onCleanup`, e.g. a component's `ctx.onCleanup`).
1022
+ */
1023
+ asyncBoundary<T>(key: string, resource: Resource<T>, branches: AsyncBoundaryBranches<T>): void;
765
1024
  /**
766
1025
  * Render `builder`'s subtree into `document.body` instead of inline at this
767
1026
  * position (a neutral inline anchor is left behind). On the server there is no
@@ -810,6 +1069,18 @@ interface ContainerDSL extends ContentDSL {
810
1069
  * `ctx.renderChildren` (§6 native child composition).
811
1070
  */
812
1071
  component<P>(key: string, def: ComponentDefinition<P>, props: P, children?: ContainerBuilder): void;
1072
+ /**
1073
+ * Declare document metadata (§1–§3): title, meta, link, canonical, Open Graph,
1074
+ * Twitter/X, robots, theme-color, favicon. Renders nothing visible at this
1075
+ * position (a neutral empty anchor); the framework applies the metadata to
1076
+ * `document.head` on the browser and emits it via `renderHead()` on the
1077
+ * server. Several `head()` calls compose — an app-level default, a route-level
1078
+ * `head()`, and a component-level `head()` are merged and, per metadata key,
1079
+ * the last declared (deepest/latest in document order) wins. Removing a
1080
+ * `head()` node (route change / component unmount) re-exposes the previously
1081
+ * shadowed value, and server tags are adopted on hydration without duplication.
1082
+ */
1083
+ head(metadata: HeadMetadata): void;
813
1084
  }
814
1085
  interface SectionDSL extends ContainerDSL {
815
1086
  }
@@ -871,7 +1142,23 @@ declare class ContainerBuilderBase extends ContentBuilderBase implements Contain
871
1142
  form(key: string, builder: FormBuilder, options?: FormOptions): void;
872
1143
  when(condition: Bindable<boolean>, builder: ContainerBuilder, elseBuilder?: ContainerBuilder, options?: WhenOptions): void;
873
1144
  errorBoundary(id: string, builder: ContainerBuilder, options: ErrorBoundaryOptions): void;
1145
+ asyncBoundary<T>(key: string, res: Resource<T>, branches: AsyncBoundaryBranches<T>): void;
874
1146
  portal(key: string, builder: ContainerBuilder, options?: PortalOptions): void;
1147
+ /**
1148
+ * Declare document metadata (2.0 §1–§3). Creates a `'head'` node — a neutral,
1149
+ * empty inline anchor at this position (one node / one element, so positional
1150
+ * hydration is preserved) — and registers a `__head__<id>` descriptor holding
1151
+ * this call's normalized, dedup-keyed {@link resolveHead} contribution. The
1152
+ * renderer applies it to `document.head` on the browser (adopting server tags
1153
+ * on hydration, cleaning up on unmount / route change) and emits the active
1154
+ * graph's merged metadata as a string on the server (`renderHead`).
1155
+ *
1156
+ * Multiple `head()` nodes may be live at once (app default + route + component)
1157
+ * — the renderer merges them and, per dedup key, the last in document order
1158
+ * wins (see head.ts). No new render path: this reuses the same graph-node +
1159
+ * handler-registry convention as overlays/transitions/components.
1160
+ */
1161
+ head(metadata: HeadMetadata): void;
875
1162
  /**
876
1163
  * Shared assembly for every overlay kind: a `portal` node whose single child
877
1164
  * is a `when(open, panel)` conditional. The panel container carries the
@@ -996,4 +1283,67 @@ declare function compile(app: StreetApp, options?: CompileOptions): CompiledAppl
996
1283
  */
997
1284
  declare function compileGraph(graph: ApplicationGraph, options?: CompileOptions): CompiledApplication;
998
1285
 
999
- export { type InputOptions as $, type ApplicationId as A, BaseNode as B, type CompiledApplication as C, DiagnosticCollector as D, type Diagnostic as E, DiagnosticError as F, GraphNode as G, type DiagnosticLocation as H, type DiagnosticSeverity as I, type ErrorBoundaryOptions as J, type ErrorFallbackBuilder as K, type ErrorSource as L, type EventDescriptor as M, type FormBuilder as N, FormBuilderImpl as O, type PageDSL as P, type FormDSL as Q, type ReadonlySignal as R, StreetApp as S, type TransitionConfig as T, type Unsubscribe as U, VERSION as V, type FormOptions as W, type GraphNodeData as X, type HandlerFn as Y, type HeadingOptions as Z, type ImageOptions as _, type ComponentDefinition as a, type InputOptionsBase as a0, type LinkOptions as a1, type ListBuilder as a2, ListBuilderImpl as a3, type ListDSL as a4, type ListOptions as a5, type ListPlanEntry as a6, type NodeId as a7, type NodeMetadata as a8, type OverlayOptions as a9, formatDiagnostic as aA, generateApplicationId as aB, generateNodeId as aC, isBatching as aD, isComponentDefinition as aE, isTransitionConfig as aF, nextId as aG, nodeIdPrefix as aH, observerCount as aI, reactiveListItemKey as aJ, reactiveListItemSignature as aK, resetIdCounter as aL, resolveTransition as aM, signal as aN, signalKind as aO, streetui as aP, type PageBuilder as aa, PageBuilderImpl as ab, type PortalOptions as ac, type PropValue as ad, type Props as ae, type ReactiveConsumer as af, type ReactiveSource as ag, type ResolvedTransition as ah, type SectionBuilder as ai, SectionBuilderImpl as aj, type SectionDSL as ak, type SectionOptions as al, type SerializedGraph as am, type SerializedNode as an, type StateRef as ao, type StreetUI as ap, type TextOptions as aq, type TextValue as ar, type WhenOptions as as, batch as at, compile as au, compileGraph as av, component as aw, createNodeId as ax, derived as ay, effect as az, type ContainerBuilder as b, Signal as c, type Subscriber as d, ApplicationGraph as e, type SemanticNodeType as f, type ContainerDSL as g, type SignalKind as h, type A11yOptions as i, AppBuilder as j, type AppDSL as k, type AppOptions as l, type ApplicationGraphOptions as m, type Bindable as n, type BindableText as o, type BoundInputOptions as p, type ButtonOptions as q, type CompileOptions as r, type ComponentContext as s, type ComponentRender as t, type ComponentSetup as u, ContainerBuilderImpl as v, type ContainerOptions as w, type ContentDSL as x, type ControlledInputOptions as y, DerivedSignal as z };
1286
+ /**
1287
+ * Hydration diagnostics — dev-only, opt-in explanations of hydration mismatches.
1288
+ *
1289
+ * Hydration is self-repairing: when the server-rendered DOM does not match the
1290
+ * graph at a position, the renderer mounts a fresh subtree in place and drops
1291
+ * the offending element (see `hydrateChildren` in `hydrate.ts`). That recovery
1292
+ * is silent by design — a local mismatch must never tear down the whole app.
1293
+ *
1294
+ * During development, though, a silent repair hides a real problem (usually a
1295
+ * server/client divergence). A `HydrationDiagnosticSink` can be attached to the
1296
+ * renderer to *observe* those repairs without changing them: for every mismatch
1297
+ * the renderer reports what it expected, what it found, where, and what it did
1298
+ * to recover. Nothing is thrown, nothing is mutated differently, and when no
1299
+ * sink is attached there is zero additional work on the hydration path.
1300
+ */
1301
+ /** What kind of divergence the hydrator encountered at a position. */
1302
+ type HydrationMismatchType = 'tag-mismatch' | 'missing-element' | 'surplus-element';
1303
+ /** A single, fully-described hydration divergence and the repair taken. */
1304
+ interface HydrationDiagnostic {
1305
+ /** The category of mismatch. */
1306
+ readonly type: HydrationMismatchType;
1307
+ /** The tag the graph expected at this position (null for a surplus element). */
1308
+ readonly expected: string | null;
1309
+ /** The tag actually found in the server DOM (null for a missing element). */
1310
+ readonly found: string | null;
1311
+ /** A human-readable path to the position, e.g. `app / page[0] / section[1]`. */
1312
+ readonly path: string;
1313
+ /** The graph node id involved, when one exists (null for surplus DOM). */
1314
+ readonly nodeId: string | null;
1315
+ /** The semantic node type involved, when one exists (null for surplus DOM). */
1316
+ readonly nodeType: string | null;
1317
+ /** The recovery action the renderer performed. */
1318
+ readonly action: string;
1319
+ /** A single-line, developer-facing summary of the whole diagnostic. */
1320
+ readonly message: string;
1321
+ }
1322
+ /**
1323
+ * Receives hydration diagnostics as they are discovered. Kept intentionally
1324
+ * tiny so any logger — `console`, a test collector, a `DiagnosticSink` — can
1325
+ * satisfy it. Implementations must not throw.
1326
+ */
1327
+ interface HydrationDiagnosticSink {
1328
+ report(diagnostic: HydrationDiagnostic): void;
1329
+ }
1330
+ /** Build the canonical one-line message for a diagnostic. */
1331
+ declare function formatHydrationDiagnostic(d: Omit<HydrationDiagnostic, 'message'>): string;
1332
+ /**
1333
+ * A ready-made sink that accumulates diagnostics into an array — the shape most
1334
+ * useful for tests and for a DevTools panel. The returned `diagnostics` array is
1335
+ * appended to in-place as repairs happen.
1336
+ */
1337
+ declare function createHydrationDiagnosticCollector(): {
1338
+ readonly sink: HydrationDiagnosticSink;
1339
+ readonly diagnostics: HydrationDiagnostic[];
1340
+ };
1341
+ /**
1342
+ * A sink that forwards each diagnostic to a `console`-like logger as a single
1343
+ * warning line. Handy default when you just want the messages surfaced in dev.
1344
+ */
1345
+ declare function consoleHydrationDiagnosticSink(logger?: {
1346
+ warn(message: string): void;
1347
+ }): HydrationDiagnosticSink;
1348
+
1349
+ export { type FormBuilder as $, type ApplicationId as A, BaseNode as B, type CompiledApplication as C, DiagnosticCollector as D, type ComponentRender as E, type ComponentSetup as F, GraphNode as G, type HydrationDiagnostic as H, ContainerBuilderImpl as I, type ContainerOptions as J, type ContentDSL as K, type ControlledInputOptions as L, DerivedSignal as M, type Diagnostic as N, DiagnosticError as O, type PageDSL as P, type DiagnosticLocation as Q, type ReadonlySignal as R, StreetApp as S, type TransitionConfig as T, type Unsubscribe as U, VERSION as V, type DiagnosticSeverity as W, type ErrorBoundaryOptions as X, type ErrorFallbackBuilder as Y, type ErrorSource as Z, type EventDescriptor as _, type ComponentDefinition as a, observerCount as a$, FormBuilderImpl as a0, type FormDSL as a1, type FormOptions as a2, type GraphNodeData as a3, type HandlerFn as a4, type HeadContribution as a5, type HeadEntry as a6, type HeadMetadata as a7, type HeadingOptions as a8, type HydrationMismatchType as a9, type SectionOptions as aA, type SerializedGraph as aB, type SerializedNode as aC, type StateRef as aD, type StreetUI as aE, type TextOptions as aF, type TextValue as aG, type WhenOptions as aH, batch as aI, compile as aJ, compileGraph as aK, component as aL, consoleHydrationDiagnosticSink as aM, createHydrationDiagnosticCollector as aN, createNodeId as aO, derived as aP, effect as aQ, formatDiagnostic as aR, formatHydrationDiagnostic as aS, generateApplicationId as aT, generateNodeId as aU, isBatching as aV, isComponentDefinition as aW, isHeadContribution as aX, isTransitionConfig as aY, nextId as aZ, nodeIdPrefix as a_, type ImageOptions as aa, type InputOptions as ab, type InputOptionsBase as ac, type LinkDescriptor as ad, type LinkOptions as ae, type ListBuilder as af, ListBuilderImpl as ag, type ListDSL as ah, type ListOptions as ai, type ListPlanEntry as aj, type MetaDescriptor as ak, type NodeId as al, type NodeMetadata as am, type OverlayOptions as an, type PageBuilder as ao, PageBuilderImpl as ap, type PortalOptions as aq, type PropValue as ar, type Props as as, type ReactiveConsumer as at, type ReactiveSource as au, type ResolvedTransition as av, type ResourceLoader as aw, type SectionBuilder as ax, SectionBuilderImpl as ay, type SectionDSL as az, type ContainerBuilder as b, reactiveListItemKey as b0, reactiveListItemSignature as b1, resetIdCounter as b2, resolveHead as b3, resolveTransition as b4, resource as b5, signal as b6, signalKind as b7, streetui as b8, Signal as c, type Subscriber as d, type ResourceStatus as e, type ResourceOptions as f, type Resource as g, type ResourceLoaderContext as h, ApplicationGraph as i, type HydrationDiagnosticSink as j, type SemanticNodeType as k, type ContainerDSL as l, type SignalKind as m, type A11yOptions as n, AppBuilder as o, type AppDSL as p, type AppOptions as q, type ApplicationGraphOptions as r, type AsyncBoundaryBranches as s, type Bindable as t, type BindableString as u, type BindableText as v, type BoundInputOptions as w, type ButtonOptions as x, type CompileOptions as y, type ComponentContext as z };