@streetui/core 1.0.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.
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Deterministic accessibility id helpers.
3
+ *
4
+ * Accessible markup often needs stable id relationships — a `<label for>` (or
5
+ * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a
6
+ * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids
7
+ * must be IDENTICAL on the server and the client, otherwise a hydrated subtree
8
+ * that re-renders (e.g. a toggled `when()` branch) would compute a different id
9
+ * than the server emitted and break the association.
10
+ *
11
+ * These helpers derive ids purely from a caller-supplied stable base string
12
+ * (typically a form field name or a dialog name). They use NO incrementing
13
+ * counter and NO randomness, so `a11yIds('email')` yields the same ids in every
14
+ * environment and on every call — which is exactly what SSR + hydration needs.
15
+ */
16
+ /** Normalise an arbitrary base into a token safe for use in an id/selector. */
17
+ declare function toIdToken(base: string): string;
18
+ interface A11yIds {
19
+ /** The normalised base token. */
20
+ readonly base: string;
21
+ /** Id for the primary interactive element (e.g. the input). */
22
+ readonly input: string;
23
+ /** Id for a label element / labelling text. */
24
+ readonly label: string;
25
+ /** Id for descriptive/help text. */
26
+ readonly description: string;
27
+ /** Id for an error message element. */
28
+ readonly error: string;
29
+ /** Id for a title element (e.g. a dialog title). */
30
+ readonly title: string;
31
+ /** Derive an arbitrary suffixed id from the same base. */
32
+ id(suffix: string): string;
33
+ }
34
+ /**
35
+ * Build a set of deterministic, SSR-stable ids from a base string.
36
+ *
37
+ * @example
38
+ * const ids = a11yIds('email');
39
+ * // ids.input === 'email-input', ids.label === 'email-label', ...
40
+ * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });
41
+ * text('Email', { id: ids.label });
42
+ */
43
+ declare function a11yIds(base: string): A11yIds;
44
+
45
+ /**
46
+ * Node and application identity utilities.
47
+ * Every node in the semantic graph has a stable, unique identity.
48
+ */
49
+ /** Generate a framework-internal monotonic integer ID. */
50
+ declare function nextId(): number;
51
+ /** Reset the counter (test use only). */
52
+ declare function resetIdCounter(): void;
53
+ /** Opaque branded type for node IDs. */
54
+ type NodeId = string & {
55
+ readonly __brand: 'NodeId';
56
+ };
57
+ /** Create a NodeId from a string (must be unique at call site). */
58
+ declare function createNodeId(value: string): NodeId;
59
+ /** Generate a fresh, unique NodeId. */
60
+ declare function generateNodeId(prefix?: string): NodeId;
61
+ /** Parse the prefix from a NodeId. */
62
+ declare function nodeIdPrefix(id: NodeId): string;
63
+ /** Branded type for application IDs. */
64
+ type ApplicationId = string & {
65
+ readonly __brand: 'ApplicationId';
66
+ };
67
+ /** Generate a fresh application ID. */
68
+ declare function generateApplicationId(name: string): ApplicationId;
69
+
70
+ /**
71
+ * Application and component lifecycle primitives.
72
+ *
73
+ * Lifecycle phases:
74
+ * created → mounted → active ⇄ updating → unmounting → destroyed
75
+ */
76
+ type LifecyclePhase = 'created' | 'mounted' | 'active' | 'updating' | 'unmounting' | 'destroyed';
77
+ type LifecycleHook = () => void | Promise<void>;
78
+ declare class Lifecycle {
79
+ private _phase;
80
+ private readonly _hooks;
81
+ get phase(): LifecyclePhase;
82
+ get isMounted(): boolean;
83
+ get isDestroyed(): boolean;
84
+ on(phase: LifecyclePhase, hook: LifecycleHook): () => void;
85
+ transition(to: LifecyclePhase): Promise<void>;
86
+ onMount(hook: LifecycleHook): () => void;
87
+ onUnmount(hook: LifecycleHook): () => void;
88
+ onDestroy(hook: LifecycleHook): () => void;
89
+ }
90
+ /** A simple cleanup registry — collect teardown functions and run them all at once. */
91
+ declare class CleanupRegistry {
92
+ private readonly _fns;
93
+ add(fn: () => void): void;
94
+ run(): void;
95
+ }
96
+
97
+ /**
98
+ * Environment detection and capability flags.
99
+ * The framework behaves slightly differently in browser vs. server vs. test.
100
+ *
101
+ * We use `typeof` checks throughout to remain safe across environments
102
+ * without depending on @types/node.
103
+ */
104
+ type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';
105
+ interface EnvironmentCapabilities {
106
+ readonly hasDom: boolean;
107
+ readonly hasWindow: boolean;
108
+ readonly hasDocument: boolean;
109
+ readonly isSecureContext: boolean;
110
+ }
111
+ declare class Environment {
112
+ readonly kind: EnvironmentKind;
113
+ readonly capabilities: EnvironmentCapabilities;
114
+ constructor(kind?: EnvironmentKind);
115
+ get isBrowser(): boolean;
116
+ get isServer(): boolean;
117
+ get isTest(): boolean;
118
+ get isWorker(): boolean;
119
+ }
120
+ /** The singleton environment for this execution context. */
121
+ declare const environment: Environment;
122
+
123
+ /**
124
+ * Framework diagnostics — structured errors, warnings, and hints
125
+ * that flow through the compiler, validator, and runtime.
126
+ */
127
+ type DiagnosticSeverity = 'error' | 'warning' | 'info';
128
+ interface DiagnosticLocation {
129
+ readonly file?: string;
130
+ readonly line?: number;
131
+ readonly column?: number;
132
+ readonly nodeId?: string;
133
+ }
134
+ interface Diagnostic {
135
+ readonly severity: DiagnosticSeverity;
136
+ readonly code: string;
137
+ readonly message: string;
138
+ readonly location: DiagnosticLocation | undefined;
139
+ readonly cause: unknown;
140
+ }
141
+ declare class DiagnosticError extends Error {
142
+ readonly diagnostics: readonly Diagnostic[];
143
+ constructor(diagnostics: readonly Diagnostic[]);
144
+ }
145
+ declare class DiagnosticCollector {
146
+ private readonly _diagnostics;
147
+ get diagnostics(): readonly Diagnostic[];
148
+ get hasErrors(): boolean;
149
+ get hasWarnings(): boolean;
150
+ error(code: string, message: string, location?: DiagnosticLocation, cause?: unknown): void;
151
+ warn(code: string, message: string, location?: DiagnosticLocation): void;
152
+ info(code: string, message: string, location?: DiagnosticLocation): void;
153
+ merge(other: DiagnosticCollector): void;
154
+ throwIfErrors(): void;
155
+ clear(): void;
156
+ }
157
+ /** Format a single diagnostic as a human-readable string. */
158
+ declare function formatDiagnostic(d: Diagnostic): string;
159
+
160
+ /**
161
+ * Top-level Application primitive.
162
+ * Owns lifecycle, identity, and the root of the application graph.
163
+ */
164
+
165
+ interface ApplicationOptions {
166
+ readonly name: string;
167
+ readonly version?: string;
168
+ readonly environment?: Environment;
169
+ }
170
+ declare class Application {
171
+ readonly id: ApplicationId;
172
+ readonly name: string;
173
+ readonly version: string;
174
+ readonly lifecycle: Lifecycle;
175
+ readonly cleanup: CleanupRegistry;
176
+ readonly diagnostics: DiagnosticCollector;
177
+ readonly environment: Environment;
178
+ constructor(options: ApplicationOptions);
179
+ mount(): Promise<void>;
180
+ unmount(): Promise<void>;
181
+ onMount(fn: () => void | Promise<void>): void;
182
+ onUnmount(fn: () => void | Promise<void>): void;
183
+ }
184
+ /** Factory convenience wrapper. */
185
+ declare function createApplication(options: ApplicationOptions): Application;
186
+
187
+ /**
188
+ * Framework node primitives — the base abstraction for every node
189
+ * in the Semantic Application Graph.
190
+ */
191
+
192
+ type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional';
193
+ interface NodeMetadata {
194
+ readonly createdAt: number;
195
+ readonly [key: string]: unknown;
196
+ }
197
+ declare abstract class BaseNode {
198
+ readonly id: NodeId;
199
+ readonly type: SemanticNodeType;
200
+ readonly metadata: NodeMetadata;
201
+ constructor(type: SemanticNodeType, id?: NodeId);
202
+ abstract clone(): BaseNode;
203
+ }
204
+
205
+ /**
206
+ * Observability boundary — a tiny, optional logging seam plus contextual
207
+ * framework errors.
208
+ *
209
+ * StreetUI never ships a telemetry service, never sends anything over the
210
+ * network, and never logs on its own by default. Instead an application MAY
211
+ * hand the framework a `DiagnosticSink` — any object with the log methods it
212
+ * cares about — and the framework will route the diagnostics it already
213
+ * produces (runtime errors, resource failures, hydration mismatches, router
214
+ * transitions) to it. With no sink attached there is no logging and no cost.
215
+ *
216
+ * This is deliberately smaller than a logging library: it duplicates neither
217
+ * `console` nor any structured-diagnostic type. It is a boundary, not a logger.
218
+ */
219
+ /**
220
+ * Where a framework diagnostic originated. Every field is optional so a caller
221
+ * supplies only what is meaningful for the situation. Values are intended to be
222
+ * non-sensitive identifiers — never tokens, secrets, cookies, or form values.
223
+ */
224
+ interface DiagnosticContext {
225
+ /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */
226
+ readonly package?: string;
227
+ /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */
228
+ readonly operation?: string;
229
+ /** The graph node id involved, when applicable. */
230
+ readonly nodeId?: string;
231
+ /** The route path involved, when applicable. */
232
+ readonly route?: string;
233
+ /** A resource identifier involved, when applicable. */
234
+ readonly resource?: string;
235
+ }
236
+ /**
237
+ * The application-provided logging seam. Every method is optional; the
238
+ * framework calls only the ones present. Implementations must not throw.
239
+ */
240
+ interface DiagnosticSink {
241
+ debug?(message: string, context?: DiagnosticContext): void;
242
+ info?(message: string, context?: DiagnosticContext): void;
243
+ warn?(message: string, context?: DiagnosticContext): void;
244
+ error?(message: string, context?: DiagnosticContext): void;
245
+ }
246
+ /** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */
247
+ declare function formatDiagnosticContext(context?: DiagnosticContext): string;
248
+ /**
249
+ * A framework error whose message carries structured, non-sensitive context so
250
+ * a developer immediately sees which package/operation/node was involved. The
251
+ * message never embeds a stack or environment values; production stack
252
+ * disclosure decisions stay with the server layer.
253
+ */
254
+ declare class StreetFrameworkError extends Error {
255
+ readonly context: DiagnosticContext | undefined;
256
+ constructor(message: string, context?: DiagnosticContext);
257
+ }
258
+ /** Build a `StreetFrameworkError` with the given context. */
259
+ declare function frameworkError(message: string, context?: DiagnosticContext): StreetFrameworkError;
260
+ /**
261
+ * Route a diagnostic to a sink if it implements the matching level. Safe to
262
+ * call with `undefined` — it simply does nothing, which is the default (no
263
+ * logging) posture. Never throws even if the sink method does.
264
+ */
265
+ declare function reportDiagnostic(sink: DiagnosticSink | undefined, level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: DiagnosticContext): void;
266
+ /** A sink that forwards to a `console`-like object, one call per level. */
267
+ declare function consoleDiagnosticSink(logger?: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>>): DiagnosticSink;
268
+
269
+ export { type A11yIds, Application, type ApplicationId, type ApplicationOptions, BaseNode, CleanupRegistry, type Diagnostic, DiagnosticCollector, type DiagnosticContext, DiagnosticError, type DiagnosticLocation, type DiagnosticSeverity, type DiagnosticSink, Environment, type EnvironmentCapabilities, type EnvironmentKind, Lifecycle, type LifecycleHook, type LifecyclePhase, type NodeId, type NodeMetadata, type SemanticNodeType, StreetFrameworkError, a11yIds, consoleDiagnosticSink, createApplication, createNodeId, environment, formatDiagnostic, formatDiagnosticContext, frameworkError, generateApplicationId, generateNodeId, nextId, nodeIdPrefix, reportDiagnostic, resetIdCounter, toIdToken };
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Deterministic accessibility id helpers.
3
+ *
4
+ * Accessible markup often needs stable id relationships — a `<label for>` (or
5
+ * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a
6
+ * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids
7
+ * must be IDENTICAL on the server and the client, otherwise a hydrated subtree
8
+ * that re-renders (e.g. a toggled `when()` branch) would compute a different id
9
+ * than the server emitted and break the association.
10
+ *
11
+ * These helpers derive ids purely from a caller-supplied stable base string
12
+ * (typically a form field name or a dialog name). They use NO incrementing
13
+ * counter and NO randomness, so `a11yIds('email')` yields the same ids in every
14
+ * environment and on every call — which is exactly what SSR + hydration needs.
15
+ */
16
+ /** Normalise an arbitrary base into a token safe for use in an id/selector. */
17
+ declare function toIdToken(base: string): string;
18
+ interface A11yIds {
19
+ /** The normalised base token. */
20
+ readonly base: string;
21
+ /** Id for the primary interactive element (e.g. the input). */
22
+ readonly input: string;
23
+ /** Id for a label element / labelling text. */
24
+ readonly label: string;
25
+ /** Id for descriptive/help text. */
26
+ readonly description: string;
27
+ /** Id for an error message element. */
28
+ readonly error: string;
29
+ /** Id for a title element (e.g. a dialog title). */
30
+ readonly title: string;
31
+ /** Derive an arbitrary suffixed id from the same base. */
32
+ id(suffix: string): string;
33
+ }
34
+ /**
35
+ * Build a set of deterministic, SSR-stable ids from a base string.
36
+ *
37
+ * @example
38
+ * const ids = a11yIds('email');
39
+ * // ids.input === 'email-input', ids.label === 'email-label', ...
40
+ * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });
41
+ * text('Email', { id: ids.label });
42
+ */
43
+ declare function a11yIds(base: string): A11yIds;
44
+
45
+ /**
46
+ * Node and application identity utilities.
47
+ * Every node in the semantic graph has a stable, unique identity.
48
+ */
49
+ /** Generate a framework-internal monotonic integer ID. */
50
+ declare function nextId(): number;
51
+ /** Reset the counter (test use only). */
52
+ declare function resetIdCounter(): void;
53
+ /** Opaque branded type for node IDs. */
54
+ type NodeId = string & {
55
+ readonly __brand: 'NodeId';
56
+ };
57
+ /** Create a NodeId from a string (must be unique at call site). */
58
+ declare function createNodeId(value: string): NodeId;
59
+ /** Generate a fresh, unique NodeId. */
60
+ declare function generateNodeId(prefix?: string): NodeId;
61
+ /** Parse the prefix from a NodeId. */
62
+ declare function nodeIdPrefix(id: NodeId): string;
63
+ /** Branded type for application IDs. */
64
+ type ApplicationId = string & {
65
+ readonly __brand: 'ApplicationId';
66
+ };
67
+ /** Generate a fresh application ID. */
68
+ declare function generateApplicationId(name: string): ApplicationId;
69
+
70
+ /**
71
+ * Application and component lifecycle primitives.
72
+ *
73
+ * Lifecycle phases:
74
+ * created → mounted → active ⇄ updating → unmounting → destroyed
75
+ */
76
+ type LifecyclePhase = 'created' | 'mounted' | 'active' | 'updating' | 'unmounting' | 'destroyed';
77
+ type LifecycleHook = () => void | Promise<void>;
78
+ declare class Lifecycle {
79
+ private _phase;
80
+ private readonly _hooks;
81
+ get phase(): LifecyclePhase;
82
+ get isMounted(): boolean;
83
+ get isDestroyed(): boolean;
84
+ on(phase: LifecyclePhase, hook: LifecycleHook): () => void;
85
+ transition(to: LifecyclePhase): Promise<void>;
86
+ onMount(hook: LifecycleHook): () => void;
87
+ onUnmount(hook: LifecycleHook): () => void;
88
+ onDestroy(hook: LifecycleHook): () => void;
89
+ }
90
+ /** A simple cleanup registry — collect teardown functions and run them all at once. */
91
+ declare class CleanupRegistry {
92
+ private readonly _fns;
93
+ add(fn: () => void): void;
94
+ run(): void;
95
+ }
96
+
97
+ /**
98
+ * Environment detection and capability flags.
99
+ * The framework behaves slightly differently in browser vs. server vs. test.
100
+ *
101
+ * We use `typeof` checks throughout to remain safe across environments
102
+ * without depending on @types/node.
103
+ */
104
+ type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';
105
+ interface EnvironmentCapabilities {
106
+ readonly hasDom: boolean;
107
+ readonly hasWindow: boolean;
108
+ readonly hasDocument: boolean;
109
+ readonly isSecureContext: boolean;
110
+ }
111
+ declare class Environment {
112
+ readonly kind: EnvironmentKind;
113
+ readonly capabilities: EnvironmentCapabilities;
114
+ constructor(kind?: EnvironmentKind);
115
+ get isBrowser(): boolean;
116
+ get isServer(): boolean;
117
+ get isTest(): boolean;
118
+ get isWorker(): boolean;
119
+ }
120
+ /** The singleton environment for this execution context. */
121
+ declare const environment: Environment;
122
+
123
+ /**
124
+ * Framework diagnostics — structured errors, warnings, and hints
125
+ * that flow through the compiler, validator, and runtime.
126
+ */
127
+ type DiagnosticSeverity = 'error' | 'warning' | 'info';
128
+ interface DiagnosticLocation {
129
+ readonly file?: string;
130
+ readonly line?: number;
131
+ readonly column?: number;
132
+ readonly nodeId?: string;
133
+ }
134
+ interface Diagnostic {
135
+ readonly severity: DiagnosticSeverity;
136
+ readonly code: string;
137
+ readonly message: string;
138
+ readonly location: DiagnosticLocation | undefined;
139
+ readonly cause: unknown;
140
+ }
141
+ declare class DiagnosticError extends Error {
142
+ readonly diagnostics: readonly Diagnostic[];
143
+ constructor(diagnostics: readonly Diagnostic[]);
144
+ }
145
+ declare class DiagnosticCollector {
146
+ private readonly _diagnostics;
147
+ get diagnostics(): readonly Diagnostic[];
148
+ get hasErrors(): boolean;
149
+ get hasWarnings(): boolean;
150
+ error(code: string, message: string, location?: DiagnosticLocation, cause?: unknown): void;
151
+ warn(code: string, message: string, location?: DiagnosticLocation): void;
152
+ info(code: string, message: string, location?: DiagnosticLocation): void;
153
+ merge(other: DiagnosticCollector): void;
154
+ throwIfErrors(): void;
155
+ clear(): void;
156
+ }
157
+ /** Format a single diagnostic as a human-readable string. */
158
+ declare function formatDiagnostic(d: Diagnostic): string;
159
+
160
+ /**
161
+ * Top-level Application primitive.
162
+ * Owns lifecycle, identity, and the root of the application graph.
163
+ */
164
+
165
+ interface ApplicationOptions {
166
+ readonly name: string;
167
+ readonly version?: string;
168
+ readonly environment?: Environment;
169
+ }
170
+ declare class Application {
171
+ readonly id: ApplicationId;
172
+ readonly name: string;
173
+ readonly version: string;
174
+ readonly lifecycle: Lifecycle;
175
+ readonly cleanup: CleanupRegistry;
176
+ readonly diagnostics: DiagnosticCollector;
177
+ readonly environment: Environment;
178
+ constructor(options: ApplicationOptions);
179
+ mount(): Promise<void>;
180
+ unmount(): Promise<void>;
181
+ onMount(fn: () => void | Promise<void>): void;
182
+ onUnmount(fn: () => void | Promise<void>): void;
183
+ }
184
+ /** Factory convenience wrapper. */
185
+ declare function createApplication(options: ApplicationOptions): Application;
186
+
187
+ /**
188
+ * Framework node primitives — the base abstraction for every node
189
+ * in the Semantic Application Graph.
190
+ */
191
+
192
+ type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional';
193
+ interface NodeMetadata {
194
+ readonly createdAt: number;
195
+ readonly [key: string]: unknown;
196
+ }
197
+ declare abstract class BaseNode {
198
+ readonly id: NodeId;
199
+ readonly type: SemanticNodeType;
200
+ readonly metadata: NodeMetadata;
201
+ constructor(type: SemanticNodeType, id?: NodeId);
202
+ abstract clone(): BaseNode;
203
+ }
204
+
205
+ /**
206
+ * Observability boundary — a tiny, optional logging seam plus contextual
207
+ * framework errors.
208
+ *
209
+ * StreetUI never ships a telemetry service, never sends anything over the
210
+ * network, and never logs on its own by default. Instead an application MAY
211
+ * hand the framework a `DiagnosticSink` — any object with the log methods it
212
+ * cares about — and the framework will route the diagnostics it already
213
+ * produces (runtime errors, resource failures, hydration mismatches, router
214
+ * transitions) to it. With no sink attached there is no logging and no cost.
215
+ *
216
+ * This is deliberately smaller than a logging library: it duplicates neither
217
+ * `console` nor any structured-diagnostic type. It is a boundary, not a logger.
218
+ */
219
+ /**
220
+ * Where a framework diagnostic originated. Every field is optional so a caller
221
+ * supplies only what is meaningful for the situation. Values are intended to be
222
+ * non-sensitive identifiers — never tokens, secrets, cookies, or form values.
223
+ */
224
+ interface DiagnosticContext {
225
+ /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */
226
+ readonly package?: string;
227
+ /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */
228
+ readonly operation?: string;
229
+ /** The graph node id involved, when applicable. */
230
+ readonly nodeId?: string;
231
+ /** The route path involved, when applicable. */
232
+ readonly route?: string;
233
+ /** A resource identifier involved, when applicable. */
234
+ readonly resource?: string;
235
+ }
236
+ /**
237
+ * The application-provided logging seam. Every method is optional; the
238
+ * framework calls only the ones present. Implementations must not throw.
239
+ */
240
+ interface DiagnosticSink {
241
+ debug?(message: string, context?: DiagnosticContext): void;
242
+ info?(message: string, context?: DiagnosticContext): void;
243
+ warn?(message: string, context?: DiagnosticContext): void;
244
+ error?(message: string, context?: DiagnosticContext): void;
245
+ }
246
+ /** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */
247
+ declare function formatDiagnosticContext(context?: DiagnosticContext): string;
248
+ /**
249
+ * A framework error whose message carries structured, non-sensitive context so
250
+ * a developer immediately sees which package/operation/node was involved. The
251
+ * message never embeds a stack or environment values; production stack
252
+ * disclosure decisions stay with the server layer.
253
+ */
254
+ declare class StreetFrameworkError extends Error {
255
+ readonly context: DiagnosticContext | undefined;
256
+ constructor(message: string, context?: DiagnosticContext);
257
+ }
258
+ /** Build a `StreetFrameworkError` with the given context. */
259
+ declare function frameworkError(message: string, context?: DiagnosticContext): StreetFrameworkError;
260
+ /**
261
+ * Route a diagnostic to a sink if it implements the matching level. Safe to
262
+ * call with `undefined` — it simply does nothing, which is the default (no
263
+ * logging) posture. Never throws even if the sink method does.
264
+ */
265
+ declare function reportDiagnostic(sink: DiagnosticSink | undefined, level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: DiagnosticContext): void;
266
+ /** A sink that forwards to a `console`-like object, one call per level. */
267
+ declare function consoleDiagnosticSink(logger?: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>>): DiagnosticSink;
268
+
269
+ export { type A11yIds, Application, type ApplicationId, type ApplicationOptions, BaseNode, CleanupRegistry, type Diagnostic, DiagnosticCollector, type DiagnosticContext, DiagnosticError, type DiagnosticLocation, type DiagnosticSeverity, type DiagnosticSink, Environment, type EnvironmentCapabilities, type EnvironmentKind, Lifecycle, type LifecycleHook, type LifecyclePhase, type NodeId, type NodeMetadata, type SemanticNodeType, StreetFrameworkError, a11yIds, consoleDiagnosticSink, createApplication, createNodeId, environment, formatDiagnostic, formatDiagnosticContext, frameworkError, generateApplicationId, generateNodeId, nextId, nodeIdPrefix, reportDiagnostic, resetIdCounter, toIdToken };