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.
- package/dist/bin.cjs +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/create-bin.cjs +1 -1
- package/dist/create-bin.cjs.map +1 -1
- package/dist/create-bin.js +1 -1
- package/dist/create-bin.js.map +1 -1
- package/dist/{compile-DqsMQVJk.d.cts → hydration-diagnostics-Jm3qUydo.d.cts} +353 -3
- package/dist/{compile-DqsMQVJk.d.ts → hydration-diagnostics-Jm3qUydo.d.ts} +353 -3
- package/dist/index.cjs +873 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +389 -147
- package/dist/index.d.ts +389 -147
- package/dist/index.js +858 -8
- package/dist/index.js.map +1 -1
- package/dist/renderer-interface-CPrfslvr.d.ts +26 -0
- package/dist/renderer-interface-moxwy5PA.d.cts +26 -0
- package/dist/{server-BYnmb_hR.d.ts → server-DG0tvuRt.d.ts} +181 -2
- package/dist/{server-DnwqBTfE.d.cts → server-_kf9p9SV.d.cts} +181 -2
- package/dist/server.cjs +217 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +216 -3
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +368 -6
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +368 -6
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/hydration-diagnostics-4pwt6v7b.d.cts +0 -89
- package/dist/hydration-diagnostics-B2FmY05M.d.ts +0 -89
|
@@ -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.
|
|
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
|
-
|
|
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 };
|