@streetui/core 1.6.1 → 1.7.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/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/a11y-ids.ts","../src/identity.ts","../src/lifecycle.ts","../src/environment.ts","../src/diagnostics.ts","../src/application.ts","../src/node.ts","../src/observability.ts"],"sourcesContent":["export * from './a11y-ids.js';\nexport * from './application.js';\nexport * from './diagnostics.js';\nexport * from './environment.js';\nexport * from './identity.js';\nexport * from './lifecycle.js';\nexport * from './node.js';\nexport * from './observability.js';\n","/**\n * Deterministic accessibility id helpers.\n *\n * Accessible markup often needs stable id relationships — a `<label for>` (or\n * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a\n * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids\n * must be IDENTICAL on the server and the client, otherwise a hydrated subtree\n * that re-renders (e.g. a toggled `when()` branch) would compute a different id\n * than the server emitted and break the association.\n *\n * These helpers derive ids purely from a caller-supplied stable base string\n * (typically a form field name or a dialog name). They use NO incrementing\n * counter and NO randomness, so `a11yIds('email')` yields the same ids in every\n * environment and on every call — which is exactly what SSR + hydration needs.\n */\n\nconst UNSAFE = /[^A-Za-z0-9_-]+/g;\n\n/** Normalise an arbitrary base into a token safe for use in an id/selector. */\nexport function toIdToken(base: string): string {\n const token = base.trim().replace(UNSAFE, '-').replace(/^-+|-+$/g, '');\n return token.length > 0 ? token : 'field';\n}\n\nexport interface A11yIds {\n /** The normalised base token. */\n readonly base: string;\n /** Id for the primary interactive element (e.g. the input). */\n readonly input: string;\n /** Id for a label element / labelling text. */\n readonly label: string;\n /** Id for descriptive/help text. */\n readonly description: string;\n /** Id for an error message element. */\n readonly error: string;\n /** Id for a title element (e.g. a dialog title). */\n readonly title: string;\n /** Derive an arbitrary suffixed id from the same base. */\n id(suffix: string): string;\n}\n\n/**\n * Build a set of deterministic, SSR-stable ids from a base string.\n *\n * @example\n * const ids = a11yIds('email');\n * // ids.input === 'email-input', ids.label === 'email-label', ...\n * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });\n * text('Email', { id: ids.label });\n */\nexport function a11yIds(base: string): A11yIds {\n const token = toIdToken(base);\n return {\n base: token,\n input: `${token}-input`,\n label: `${token}-label`,\n description: `${token}-description`,\n error: `${token}-error`,\n title: `${token}-title`,\n id: (suffix: string) => `${token}-${toIdToken(suffix)}`,\n };\n}\n","/**\n * Node and application identity utilities.\n * Every node in the semantic graph has a stable, unique identity.\n */\n\nlet _counter = 0;\n\n/** Generate a framework-internal monotonic integer ID. */\nexport function nextId(): number {\n return ++_counter;\n}\n\n/** Reset the counter (test use only). */\nexport function resetIdCounter(): void {\n _counter = 0;\n}\n\n/** Opaque branded type for node IDs. */\nexport type NodeId = string & { readonly __brand: 'NodeId' };\n\n/** Create a NodeId from a string (must be unique at call site). */\nexport function createNodeId(value: string): NodeId {\n return value as NodeId;\n}\n\n/** Generate a fresh, unique NodeId. */\nexport function generateNodeId(prefix: string = 'node'): NodeId {\n return createNodeId(`${prefix}:${nextId()}`);\n}\n\n/** Parse the prefix from a NodeId. */\nexport function nodeIdPrefix(id: NodeId): string {\n const colon = id.indexOf(':');\n return colon === -1 ? id : id.slice(0, colon);\n}\n\n/** Branded type for application IDs. */\nexport type ApplicationId = string & { readonly __brand: 'ApplicationId' };\n\n/** Generate a fresh application ID. */\nexport function generateApplicationId(name: string): ApplicationId {\n return `app:${name}:${nextId()}` as ApplicationId;\n}\n","/**\n * Application and component lifecycle primitives.\n *\n * Lifecycle phases:\n * created → mounted → active ⇄ updating → unmounting → destroyed\n */\n\nexport type LifecyclePhase =\n | 'created'\n | 'mounted'\n | 'active'\n | 'updating'\n | 'unmounting'\n | 'destroyed';\n\nexport type LifecycleHook = () => void | Promise<void>;\n\nexport class Lifecycle {\n private _phase: LifecyclePhase = 'created';\n private readonly _hooks: Map<LifecyclePhase, LifecycleHook[]> = new Map();\n\n get phase(): LifecyclePhase {\n return this._phase;\n }\n\n get isMounted(): boolean {\n return this._phase === 'mounted' || this._phase === 'active' || this._phase === 'updating';\n }\n\n get isDestroyed(): boolean {\n return this._phase === 'destroyed';\n }\n\n on(phase: LifecyclePhase, hook: LifecycleHook): () => void {\n const hooks = this._hooks.get(phase) ?? [];\n hooks.push(hook);\n this._hooks.set(phase, hooks);\n return () => {\n const current = this._hooks.get(phase);\n if (current !== undefined) {\n const idx = current.indexOf(hook);\n if (idx !== -1) current.splice(idx, 1);\n }\n };\n }\n\n async transition(to: LifecyclePhase): Promise<void> {\n this._phase = to;\n const hooks = this._hooks.get(to) ?? [];\n for (const hook of hooks) {\n await hook();\n }\n }\n\n onMount(hook: LifecycleHook): () => void {\n return this.on('mounted', hook);\n }\n\n onUnmount(hook: LifecycleHook): () => void {\n return this.on('unmounting', hook);\n }\n\n onDestroy(hook: LifecycleHook): () => void {\n return this.on('destroyed', hook);\n }\n}\n\n/** A simple cleanup registry — collect teardown functions and run them all at once. */\nexport class CleanupRegistry {\n private readonly _fns: Array<() => void> = [];\n\n add(fn: () => void): void {\n this._fns.push(fn);\n }\n\n run(): void {\n for (const fn of this._fns) {\n try {\n fn();\n } catch {\n // Best-effort cleanup; don't let one failure block others\n }\n }\n this._fns.length = 0;\n }\n}\n","/**\n * Environment detection and capability flags.\n * The framework behaves slightly differently in browser vs. server vs. test.\n *\n * We use `typeof` checks throughout to remain safe across environments\n * without depending on @types/node.\n */\n\nexport type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';\n\nexport interface EnvironmentCapabilities {\n readonly hasDom: boolean;\n readonly hasWindow: boolean;\n readonly hasDocument: boolean;\n readonly isSecureContext: boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ndeclare const process: any;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction detectEnvironment(): EnvironmentKind {\n // Explicit test override via process.env\n try {\n if (\n typeof process !== 'undefined' &&\n process !== null &&\n typeof process === 'object' &&\n (process.env?.['NODE_ENV'] === 'test' || process.env?.['VITEST'] === 'true')\n ) {\n return 'test';\n }\n } catch {\n // process may not be defined in all environments\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return 'browser';\n }\n\n if (\n typeof self !== 'undefined' &&\n typeof (self as unknown as Record<string, unknown>)['importScripts'] === 'function'\n ) {\n return 'worker';\n }\n\n try {\n if (typeof process !== 'undefined' && typeof process === 'object') {\n return 'server';\n }\n } catch {\n // ignore\n }\n\n return 'unknown';\n}\n\nfunction detectCapabilities(): EnvironmentCapabilities {\n return {\n hasDom: typeof document !== 'undefined',\n hasWindow: typeof window !== 'undefined',\n hasDocument: typeof document !== 'undefined',\n isSecureContext:\n typeof window !== 'undefined'\n ? ((window as unknown as Record<string, unknown>)['isSecureContext'] === true)\n : false,\n };\n}\n\nexport class Environment {\n readonly kind: EnvironmentKind;\n readonly capabilities: EnvironmentCapabilities;\n\n constructor(kind?: EnvironmentKind) {\n this.kind = kind ?? detectEnvironment();\n this.capabilities = detectCapabilities();\n }\n\n get isBrowser(): boolean {\n return this.kind === 'browser';\n }\n\n get isServer(): boolean {\n return this.kind === 'server';\n }\n\n get isTest(): boolean {\n return this.kind === 'test';\n }\n\n get isWorker(): boolean {\n return this.kind === 'worker';\n }\n}\n\n/** The singleton environment for this execution context. */\nexport const environment = new Environment();\n","/**\n * Framework diagnostics — structured errors, warnings, and hints\n * that flow through the compiler, validator, and runtime.\n */\n\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info';\n\nexport interface DiagnosticLocation {\n readonly file?: string;\n readonly line?: number;\n readonly column?: number;\n readonly nodeId?: string;\n}\n\nexport interface Diagnostic {\n readonly severity: DiagnosticSeverity;\n readonly code: string;\n readonly message: string;\n readonly location: DiagnosticLocation | undefined;\n readonly cause: unknown;\n}\n\nexport class DiagnosticError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n const summary = diagnostics\n .filter(d => d.severity === 'error')\n .map(d => `[${d.code}] ${d.message}`)\n .join('\\n');\n super(`StreetUI diagnostics:\\n${summary}`);\n this.name = 'DiagnosticError';\n this.diagnostics = diagnostics;\n }\n}\n\nexport class DiagnosticCollector {\n private readonly _diagnostics: Diagnostic[] = [];\n\n get diagnostics(): readonly Diagnostic[] {\n return this._diagnostics;\n }\n\n get hasErrors(): boolean {\n return this._diagnostics.some(d => d.severity === 'error');\n }\n\n get hasWarnings(): boolean {\n return this._diagnostics.some(d => d.severity === 'warning');\n }\n\n error(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n cause?: unknown,\n ): void {\n this._diagnostics.push({ severity: 'error', code, message, location: location ?? undefined, cause: cause ?? undefined });\n }\n\n warn(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'warning', code, message, location: location ?? undefined, cause: undefined });\n }\n\n info(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'info', code, message, location: location ?? undefined, cause: undefined });\n }\n\n merge(other: DiagnosticCollector): void {\n for (const d of other.diagnostics) {\n this._diagnostics.push(d);\n }\n }\n\n throwIfErrors(): void {\n if (this.hasErrors) {\n throw new DiagnosticError(this._diagnostics);\n }\n }\n\n clear(): void {\n this._diagnostics.length = 0;\n }\n}\n\n/** Format a single diagnostic as a human-readable string. */\nexport function formatDiagnostic(d: Diagnostic): string {\n const loc = d.location !== undefined\n ? ` (${[d.location.file, d.location.line, d.location.column]\n .filter(Boolean)\n .join(':')})`\n : '';\n return `[${d.severity.toUpperCase()}] ${d.code}: ${d.message}${loc}`;\n}\n","/**\n * Top-level Application primitive.\n * Owns lifecycle, identity, and the root of the application graph.\n */\n\nimport { type ApplicationId, generateApplicationId } from './identity.js';\nimport { Lifecycle, CleanupRegistry } from './lifecycle.js';\nimport { Environment, environment as defaultEnvironment } from './environment.js';\nimport { DiagnosticCollector } from './diagnostics.js';\n\nexport interface ApplicationOptions {\n readonly name: string;\n readonly version?: string;\n readonly environment?: Environment;\n}\n\nexport class Application {\n readonly id: ApplicationId;\n readonly name: string;\n readonly version: string;\n readonly lifecycle: Lifecycle;\n readonly cleanup: CleanupRegistry;\n readonly diagnostics: DiagnosticCollector;\n readonly environment: Environment;\n\n constructor(options: ApplicationOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.id = generateApplicationId(options.name);\n this.lifecycle = new Lifecycle();\n this.cleanup = new CleanupRegistry();\n this.diagnostics = new DiagnosticCollector();\n this.environment = options.environment ?? defaultEnvironment;\n }\n\n async mount(): Promise<void> {\n if (this.lifecycle.phase !== 'created') {\n throw new Error(`Application \"${this.name}\" is already mounted (phase: ${this.lifecycle.phase})`);\n }\n await this.lifecycle.transition('mounted');\n await this.lifecycle.transition('active');\n }\n\n async unmount(): Promise<void> {\n if (!this.lifecycle.isMounted) {\n return;\n }\n await this.lifecycle.transition('unmounting');\n this.cleanup.run();\n await this.lifecycle.transition('destroyed');\n }\n\n onMount(fn: () => void | Promise<void>): void {\n this.lifecycle.onMount(fn);\n }\n\n onUnmount(fn: () => void | Promise<void>): void {\n this.lifecycle.onUnmount(fn);\n }\n}\n\n/** Factory convenience wrapper. */\nexport function createApplication(options: ApplicationOptions): Application {\n return new Application(options);\n}\n","/**\n * Framework node primitives — the base abstraction for every node\n * in the Semantic Application Graph.\n */\n\nimport { type NodeId, generateNodeId } from './identity.js';\n\nexport type SemanticNodeType =\n | 'application'\n | 'page'\n | 'section'\n | 'container'\n | 'heading'\n | 'text'\n | 'button'\n | 'input'\n | 'form'\n | 'list'\n | 'list-item'\n | 'image'\n | 'link'\n | 'component'\n | 'slot'\n | 'fragment'\n | 'reactive-list'\n | 'conditional';\n\nexport interface NodeMetadata {\n readonly createdAt: number;\n readonly [key: string]: unknown;\n}\n\nexport abstract class BaseNode {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly metadata: NodeMetadata;\n\n constructor(type: SemanticNodeType, id?: NodeId) {\n this.type = type;\n this.id = id ?? generateNodeId(type);\n this.metadata = { createdAt: Date.now() };\n }\n\n abstract clone(): BaseNode;\n}\n","/**\n * Observability boundary — a tiny, optional logging seam plus contextual\n * framework errors.\n *\n * StreetUI never ships a telemetry service, never sends anything over the\n * network, and never logs on its own by default. Instead an application MAY\n * hand the framework a `DiagnosticSink` — any object with the log methods it\n * cares about — and the framework will route the diagnostics it already\n * produces (runtime errors, resource failures, hydration mismatches, router\n * transitions) to it. With no sink attached there is no logging and no cost.\n *\n * This is deliberately smaller than a logging library: it duplicates neither\n * `console` nor any structured-diagnostic type. It is a boundary, not a logger.\n */\n\n/**\n * Where a framework diagnostic originated. Every field is optional so a caller\n * supplies only what is meaningful for the situation. Values are intended to be\n * non-sensitive identifiers — never tokens, secrets, cookies, or form values.\n */\nexport interface DiagnosticContext {\n /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */\n readonly package?: string;\n /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */\n readonly operation?: string;\n /** The graph node id involved, when applicable. */\n readonly nodeId?: string;\n /** The route path involved, when applicable. */\n readonly route?: string;\n /** A resource identifier involved, when applicable. */\n readonly resource?: string;\n}\n\n/**\n * The application-provided logging seam. Every method is optional; the\n * framework calls only the ones present. Implementations must not throw.\n */\nexport interface DiagnosticSink {\n debug?(message: string, context?: DiagnosticContext): void;\n info?(message: string, context?: DiagnosticContext): void;\n warn?(message: string, context?: DiagnosticContext): void;\n error?(message: string, context?: DiagnosticContext): void;\n}\n\n/** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */\nexport function formatDiagnosticContext(context?: DiagnosticContext): string {\n if (context === undefined) return '';\n const parts: string[] = [];\n if (context.package !== undefined) parts.push(`package=${context.package}`);\n if (context.operation !== undefined) parts.push(`operation=${context.operation}`);\n if (context.nodeId !== undefined) parts.push(`node=${context.nodeId}`);\n if (context.route !== undefined) parts.push(`route=${context.route}`);\n if (context.resource !== undefined) parts.push(`resource=${context.resource}`);\n return parts.length > 0 ? ` [${parts.join(', ')}]` : '';\n}\n\n/**\n * A framework error whose message carries structured, non-sensitive context so\n * a developer immediately sees which package/operation/node was involved. The\n * message never embeds a stack or environment values; production stack\n * disclosure decisions stay with the server layer.\n */\nexport class StreetFrameworkError extends Error {\n readonly context: DiagnosticContext | undefined;\n\n constructor(message: string, context?: DiagnosticContext) {\n super(`${message}${formatDiagnosticContext(context)}`);\n this.name = 'StreetFrameworkError';\n this.context = context ?? undefined;\n }\n}\n\n/** Build a `StreetFrameworkError` with the given context. */\nexport function frameworkError(\n message: string,\n context?: DiagnosticContext,\n): StreetFrameworkError {\n return new StreetFrameworkError(message, context);\n}\n\n/**\n * Route a diagnostic to a sink if it implements the matching level. Safe to\n * call with `undefined` — it simply does nothing, which is the default (no\n * logging) posture. Never throws even if the sink method does.\n */\nexport function reportDiagnostic(\n sink: DiagnosticSink | undefined,\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n context?: DiagnosticContext,\n): void {\n if (sink === undefined) return;\n const fn = sink[level];\n if (typeof fn !== 'function') return;\n try {\n fn.call(sink, message, context);\n } catch {\n // A misbehaving sink must never break the framework.\n }\n}\n\n/** A sink that forwards to a `console`-like object, one call per level. */\nexport function consoleDiagnosticSink(\n logger: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>> = console,\n): DiagnosticSink {\n return {\n debug: (m, c) => logger.debug?.(`${m}${formatDiagnosticContext(c)}`),\n info: (m, c) => logger.info?.(`${m}${formatDiagnosticContext(c)}`),\n warn: (m, c) => logger.warn?.(`${m}${formatDiagnosticContext(c)}`),\n error: (m, c) => logger.error?.(`${m}${formatDiagnosticContext(c)}`),\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/a11y-ids.ts","../src/identity.ts","../src/lifecycle.ts","../src/environment.ts","../src/diagnostics.ts","../src/application.ts","../src/node.ts","../src/observability.ts"],"sourcesContent":["export * from './a11y-ids.js';\nexport * from './application.js';\nexport * from './diagnostics.js';\nexport * from './environment.js';\nexport * from './identity.js';\nexport * from './lifecycle.js';\nexport * from './node.js';\nexport * from './observability.js';\n","/**\n * Deterministic accessibility id helpers.\n *\n * Accessible markup often needs stable id relationships — a `<label for>` (or\n * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a\n * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids\n * must be IDENTICAL on the server and the client, otherwise a hydrated subtree\n * that re-renders (e.g. a toggled `when()` branch) would compute a different id\n * than the server emitted and break the association.\n *\n * These helpers derive ids purely from a caller-supplied stable base string\n * (typically a form field name or a dialog name). They use NO incrementing\n * counter and NO randomness, so `a11yIds('email')` yields the same ids in every\n * environment and on every call — which is exactly what SSR + hydration needs.\n */\n\nconst UNSAFE = /[^A-Za-z0-9_-]+/g;\n\n/** Normalise an arbitrary base into a token safe for use in an id/selector. */\nexport function toIdToken(base: string): string {\n const token = base.trim().replace(UNSAFE, '-').replace(/^-+|-+$/g, '');\n return token.length > 0 ? token : 'field';\n}\n\nexport interface A11yIds {\n /** The normalised base token. */\n readonly base: string;\n /** Id for the primary interactive element (e.g. the input). */\n readonly input: string;\n /** Id for a label element / labelling text. */\n readonly label: string;\n /** Id for descriptive/help text. */\n readonly description: string;\n /** Id for an error message element. */\n readonly error: string;\n /** Id for a title element (e.g. a dialog title). */\n readonly title: string;\n /** Derive an arbitrary suffixed id from the same base. */\n id(suffix: string): string;\n}\n\n/**\n * Build a set of deterministic, SSR-stable ids from a base string.\n *\n * @example\n * const ids = a11yIds('email');\n * // ids.input === 'email-input', ids.label === 'email-label', ...\n * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });\n * text('Email', { id: ids.label });\n */\nexport function a11yIds(base: string): A11yIds {\n const token = toIdToken(base);\n return {\n base: token,\n input: `${token}-input`,\n label: `${token}-label`,\n description: `${token}-description`,\n error: `${token}-error`,\n title: `${token}-title`,\n id: (suffix: string) => `${token}-${toIdToken(suffix)}`,\n };\n}\n","/**\n * Node and application identity utilities.\n * Every node in the semantic graph has a stable, unique identity.\n */\n\nlet _counter = 0;\n\n/** Generate a framework-internal monotonic integer ID. */\nexport function nextId(): number {\n return ++_counter;\n}\n\n/** Reset the counter (test use only). */\nexport function resetIdCounter(): void {\n _counter = 0;\n}\n\n/** Opaque branded type for node IDs. */\nexport type NodeId = string & { readonly __brand: 'NodeId' };\n\n/** Create a NodeId from a string (must be unique at call site). */\nexport function createNodeId(value: string): NodeId {\n return value as NodeId;\n}\n\n/** Generate a fresh, unique NodeId. */\nexport function generateNodeId(prefix: string = 'node'): NodeId {\n return createNodeId(`${prefix}:${nextId()}`);\n}\n\n/** Parse the prefix from a NodeId. */\nexport function nodeIdPrefix(id: NodeId): string {\n const colon = id.indexOf(':');\n return colon === -1 ? id : id.slice(0, colon);\n}\n\n/** Branded type for application IDs. */\nexport type ApplicationId = string & { readonly __brand: 'ApplicationId' };\n\n/** Generate a fresh application ID. */\nexport function generateApplicationId(name: string): ApplicationId {\n return `app:${name}:${nextId()}` as ApplicationId;\n}\n","/**\n * Application and component lifecycle primitives.\n *\n * Lifecycle phases:\n * created → mounted → active ⇄ updating → unmounting → destroyed\n */\n\nexport type LifecyclePhase =\n | 'created'\n | 'mounted'\n | 'active'\n | 'updating'\n | 'unmounting'\n | 'destroyed';\n\nexport type LifecycleHook = () => void | Promise<void>;\n\nexport class Lifecycle {\n private _phase: LifecyclePhase = 'created';\n private readonly _hooks: Map<LifecyclePhase, LifecycleHook[]> = new Map();\n\n get phase(): LifecyclePhase {\n return this._phase;\n }\n\n get isMounted(): boolean {\n return this._phase === 'mounted' || this._phase === 'active' || this._phase === 'updating';\n }\n\n get isDestroyed(): boolean {\n return this._phase === 'destroyed';\n }\n\n on(phase: LifecyclePhase, hook: LifecycleHook): () => void {\n const hooks = this._hooks.get(phase) ?? [];\n hooks.push(hook);\n this._hooks.set(phase, hooks);\n return () => {\n const current = this._hooks.get(phase);\n if (current !== undefined) {\n const idx = current.indexOf(hook);\n if (idx !== -1) current.splice(idx, 1);\n }\n };\n }\n\n async transition(to: LifecyclePhase): Promise<void> {\n this._phase = to;\n const hooks = this._hooks.get(to) ?? [];\n for (const hook of hooks) {\n await hook();\n }\n }\n\n onMount(hook: LifecycleHook): () => void {\n return this.on('mounted', hook);\n }\n\n onUnmount(hook: LifecycleHook): () => void {\n return this.on('unmounting', hook);\n }\n\n onDestroy(hook: LifecycleHook): () => void {\n return this.on('destroyed', hook);\n }\n}\n\n/** A simple cleanup registry — collect teardown functions and run them all at once. */\nexport class CleanupRegistry {\n private readonly _fns: Array<() => void> = [];\n\n add(fn: () => void): void {\n this._fns.push(fn);\n }\n\n run(): void {\n for (const fn of this._fns) {\n try {\n fn();\n } catch {\n // Best-effort cleanup; don't let one failure block others\n }\n }\n this._fns.length = 0;\n }\n}\n","/**\n * Environment detection and capability flags.\n * The framework behaves slightly differently in browser vs. server vs. test.\n *\n * We use `typeof` checks throughout to remain safe across environments\n * without depending on @types/node.\n */\n\nexport type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';\n\nexport interface EnvironmentCapabilities {\n readonly hasDom: boolean;\n readonly hasWindow: boolean;\n readonly hasDocument: boolean;\n readonly isSecureContext: boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ndeclare const process: any;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction detectEnvironment(): EnvironmentKind {\n // Explicit test override via process.env\n try {\n if (\n typeof process !== 'undefined' &&\n process !== null &&\n typeof process === 'object' &&\n (process.env?.['NODE_ENV'] === 'test' || process.env?.['VITEST'] === 'true')\n ) {\n return 'test';\n }\n } catch {\n // process may not be defined in all environments\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return 'browser';\n }\n\n if (\n typeof self !== 'undefined' &&\n typeof (self as unknown as Record<string, unknown>)['importScripts'] === 'function'\n ) {\n return 'worker';\n }\n\n try {\n if (typeof process !== 'undefined' && typeof process === 'object') {\n return 'server';\n }\n } catch {\n // ignore\n }\n\n return 'unknown';\n}\n\nfunction detectCapabilities(): EnvironmentCapabilities {\n return {\n hasDom: typeof document !== 'undefined',\n hasWindow: typeof window !== 'undefined',\n hasDocument: typeof document !== 'undefined',\n isSecureContext:\n typeof window !== 'undefined'\n ? ((window as unknown as Record<string, unknown>)['isSecureContext'] === true)\n : false,\n };\n}\n\nexport class Environment {\n readonly kind: EnvironmentKind;\n readonly capabilities: EnvironmentCapabilities;\n\n constructor(kind?: EnvironmentKind) {\n this.kind = kind ?? detectEnvironment();\n this.capabilities = detectCapabilities();\n }\n\n get isBrowser(): boolean {\n return this.kind === 'browser';\n }\n\n get isServer(): boolean {\n return this.kind === 'server';\n }\n\n get isTest(): boolean {\n return this.kind === 'test';\n }\n\n get isWorker(): boolean {\n return this.kind === 'worker';\n }\n}\n\n/** The singleton environment for this execution context. */\nexport const environment = new Environment();\n","/**\n * Framework diagnostics — structured errors, warnings, and hints\n * that flow through the compiler, validator, and runtime.\n */\n\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info';\n\nexport interface DiagnosticLocation {\n readonly file?: string;\n readonly line?: number;\n readonly column?: number;\n readonly nodeId?: string;\n}\n\nexport interface Diagnostic {\n readonly severity: DiagnosticSeverity;\n readonly code: string;\n readonly message: string;\n readonly location: DiagnosticLocation | undefined;\n readonly cause: unknown;\n}\n\nexport class DiagnosticError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n const summary = diagnostics\n .filter(d => d.severity === 'error')\n .map(d => `[${d.code}] ${d.message}`)\n .join('\\n');\n super(`StreetUI diagnostics:\\n${summary}`);\n this.name = 'DiagnosticError';\n this.diagnostics = diagnostics;\n }\n}\n\nexport class DiagnosticCollector {\n private readonly _diagnostics: Diagnostic[] = [];\n\n get diagnostics(): readonly Diagnostic[] {\n return this._diagnostics;\n }\n\n get hasErrors(): boolean {\n return this._diagnostics.some(d => d.severity === 'error');\n }\n\n get hasWarnings(): boolean {\n return this._diagnostics.some(d => d.severity === 'warning');\n }\n\n error(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n cause?: unknown,\n ): void {\n this._diagnostics.push({ severity: 'error', code, message, location: location ?? undefined, cause: cause ?? undefined });\n }\n\n warn(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'warning', code, message, location: location ?? undefined, cause: undefined });\n }\n\n info(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'info', code, message, location: location ?? undefined, cause: undefined });\n }\n\n merge(other: DiagnosticCollector): void {\n for (const d of other.diagnostics) {\n this._diagnostics.push(d);\n }\n }\n\n throwIfErrors(): void {\n if (this.hasErrors) {\n throw new DiagnosticError(this._diagnostics);\n }\n }\n\n clear(): void {\n this._diagnostics.length = 0;\n }\n}\n\n/** Format a single diagnostic as a human-readable string. */\nexport function formatDiagnostic(d: Diagnostic): string {\n const loc = d.location !== undefined\n ? ` (${[d.location.file, d.location.line, d.location.column]\n .filter(Boolean)\n .join(':')})`\n : '';\n return `[${d.severity.toUpperCase()}] ${d.code}: ${d.message}${loc}`;\n}\n","/**\n * Top-level Application primitive.\n * Owns lifecycle, identity, and the root of the application graph.\n */\n\nimport { type ApplicationId, generateApplicationId } from './identity.js';\nimport { Lifecycle, CleanupRegistry } from './lifecycle.js';\nimport { Environment, environment as defaultEnvironment } from './environment.js';\nimport { DiagnosticCollector } from './diagnostics.js';\n\nexport interface ApplicationOptions {\n readonly name: string;\n readonly version?: string;\n readonly environment?: Environment;\n}\n\nexport class Application {\n readonly id: ApplicationId;\n readonly name: string;\n readonly version: string;\n readonly lifecycle: Lifecycle;\n readonly cleanup: CleanupRegistry;\n readonly diagnostics: DiagnosticCollector;\n readonly environment: Environment;\n\n constructor(options: ApplicationOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.id = generateApplicationId(options.name);\n this.lifecycle = new Lifecycle();\n this.cleanup = new CleanupRegistry();\n this.diagnostics = new DiagnosticCollector();\n this.environment = options.environment ?? defaultEnvironment;\n }\n\n async mount(): Promise<void> {\n if (this.lifecycle.phase !== 'created') {\n throw new Error(`Application \"${this.name}\" is already mounted (phase: ${this.lifecycle.phase})`);\n }\n await this.lifecycle.transition('mounted');\n await this.lifecycle.transition('active');\n }\n\n async unmount(): Promise<void> {\n if (!this.lifecycle.isMounted) {\n return;\n }\n await this.lifecycle.transition('unmounting');\n this.cleanup.run();\n await this.lifecycle.transition('destroyed');\n }\n\n onMount(fn: () => void | Promise<void>): void {\n this.lifecycle.onMount(fn);\n }\n\n onUnmount(fn: () => void | Promise<void>): void {\n this.lifecycle.onUnmount(fn);\n }\n}\n\n/** Factory convenience wrapper. */\nexport function createApplication(options: ApplicationOptions): Application {\n return new Application(options);\n}\n","/**\n * Framework node primitives — the base abstraction for every node\n * in the Semantic Application Graph.\n */\n\nimport { type NodeId, generateNodeId } from './identity.js';\n\nexport type SemanticNodeType =\n | 'application'\n | 'page'\n | 'section'\n | 'container'\n | 'heading'\n | 'text'\n | 'button'\n | 'input'\n | 'form'\n | 'list'\n | 'list-item'\n | 'image'\n | 'link'\n | 'component'\n | 'slot'\n | 'fragment'\n | 'reactive-list'\n | 'conditional'\n | 'portal';\n\nexport interface NodeMetadata {\n readonly createdAt: number;\n readonly [key: string]: unknown;\n}\n\nexport abstract class BaseNode {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly metadata: NodeMetadata;\n\n constructor(type: SemanticNodeType, id?: NodeId) {\n this.type = type;\n this.id = id ?? generateNodeId(type);\n this.metadata = { createdAt: Date.now() };\n }\n\n abstract clone(): BaseNode;\n}\n","/**\n * Observability boundary — a tiny, optional logging seam plus contextual\n * framework errors.\n *\n * StreetUI never ships a telemetry service, never sends anything over the\n * network, and never logs on its own by default. Instead an application MAY\n * hand the framework a `DiagnosticSink` — any object with the log methods it\n * cares about — and the framework will route the diagnostics it already\n * produces (runtime errors, resource failures, hydration mismatches, router\n * transitions) to it. With no sink attached there is no logging and no cost.\n *\n * This is deliberately smaller than a logging library: it duplicates neither\n * `console` nor any structured-diagnostic type. It is a boundary, not a logger.\n */\n\n/**\n * Where a framework diagnostic originated. Every field is optional so a caller\n * supplies only what is meaningful for the situation. Values are intended to be\n * non-sensitive identifiers — never tokens, secrets, cookies, or form values.\n */\nexport interface DiagnosticContext {\n /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */\n readonly package?: string;\n /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */\n readonly operation?: string;\n /** The graph node id involved, when applicable. */\n readonly nodeId?: string;\n /** The route path involved, when applicable. */\n readonly route?: string;\n /** A resource identifier involved, when applicable. */\n readonly resource?: string;\n}\n\n/**\n * The application-provided logging seam. Every method is optional; the\n * framework calls only the ones present. Implementations must not throw.\n */\nexport interface DiagnosticSink {\n debug?(message: string, context?: DiagnosticContext): void;\n info?(message: string, context?: DiagnosticContext): void;\n warn?(message: string, context?: DiagnosticContext): void;\n error?(message: string, context?: DiagnosticContext): void;\n}\n\n/** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */\nexport function formatDiagnosticContext(context?: DiagnosticContext): string {\n if (context === undefined) return '';\n const parts: string[] = [];\n if (context.package !== undefined) parts.push(`package=${context.package}`);\n if (context.operation !== undefined) parts.push(`operation=${context.operation}`);\n if (context.nodeId !== undefined) parts.push(`node=${context.nodeId}`);\n if (context.route !== undefined) parts.push(`route=${context.route}`);\n if (context.resource !== undefined) parts.push(`resource=${context.resource}`);\n return parts.length > 0 ? ` [${parts.join(', ')}]` : '';\n}\n\n/**\n * A framework error whose message carries structured, non-sensitive context so\n * a developer immediately sees which package/operation/node was involved. The\n * message never embeds a stack or environment values; production stack\n * disclosure decisions stay with the server layer.\n */\nexport class StreetFrameworkError extends Error {\n readonly context: DiagnosticContext | undefined;\n\n constructor(message: string, context?: DiagnosticContext) {\n super(`${message}${formatDiagnosticContext(context)}`);\n this.name = 'StreetFrameworkError';\n this.context = context ?? undefined;\n }\n}\n\n/** Build a `StreetFrameworkError` with the given context. */\nexport function frameworkError(\n message: string,\n context?: DiagnosticContext,\n): StreetFrameworkError {\n return new StreetFrameworkError(message, context);\n}\n\n/**\n * Route a diagnostic to a sink if it implements the matching level. Safe to\n * call with `undefined` — it simply does nothing, which is the default (no\n * logging) posture. Never throws even if the sink method does.\n */\nexport function reportDiagnostic(\n sink: DiagnosticSink | undefined,\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n context?: DiagnosticContext,\n): void {\n if (sink === undefined) return;\n const fn = sink[level];\n if (typeof fn !== 'function') return;\n try {\n fn.call(sink, message, context);\n } catch {\n // A misbehaving sink must never break the framework.\n }\n}\n\n/** A sink that forwards to a `console`-like object, one call per level. */\nexport function consoleDiagnosticSink(\n logger: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>> = console,\n): DiagnosticSink {\n return {\n debug: (m, c) => logger.debug?.(`${m}${formatDiagnosticContext(c)}`),\n info: (m, c) => logger.info?.(`${m}${formatDiagnosticContext(c)}`),\n warn: (m, c) => logger.warn?.(`${m}${formatDiagnosticContext(c)}`),\n error: (m, c) => logger.error?.(`${m}${formatDiagnosticContext(c)}`),\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -189,7 +189,7 @@ declare function createApplication(options: ApplicationOptions): Application;
|
|
|
189
189
|
* in the Semantic Application Graph.
|
|
190
190
|
*/
|
|
191
191
|
|
|
192
|
-
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional';
|
|
192
|
+
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal';
|
|
193
193
|
interface NodeMetadata {
|
|
194
194
|
readonly createdAt: number;
|
|
195
195
|
readonly [key: string]: unknown;
|
package/dist/index.d.ts
CHANGED
|
@@ -189,7 +189,7 @@ declare function createApplication(options: ApplicationOptions): Application;
|
|
|
189
189
|
* in the Semantic Application Graph.
|
|
190
190
|
*/
|
|
191
191
|
|
|
192
|
-
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional';
|
|
192
|
+
type SemanticNodeType = 'application' | 'page' | 'section' | 'container' | 'heading' | 'text' | 'button' | 'input' | 'form' | 'list' | 'list-item' | 'image' | 'link' | 'component' | 'slot' | 'fragment' | 'reactive-list' | 'conditional' | 'portal';
|
|
193
193
|
interface NodeMetadata {
|
|
194
194
|
readonly createdAt: number;
|
|
195
195
|
readonly [key: string]: unknown;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/a11y-ids.ts","../src/identity.ts","../src/lifecycle.ts","../src/environment.ts","../src/diagnostics.ts","../src/application.ts","../src/node.ts","../src/observability.ts"],"sourcesContent":["/**\n * Deterministic accessibility id helpers.\n *\n * Accessible markup often needs stable id relationships — a `<label for>` (or\n * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a\n * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids\n * must be IDENTICAL on the server and the client, otherwise a hydrated subtree\n * that re-renders (e.g. a toggled `when()` branch) would compute a different id\n * than the server emitted and break the association.\n *\n * These helpers derive ids purely from a caller-supplied stable base string\n * (typically a form field name or a dialog name). They use NO incrementing\n * counter and NO randomness, so `a11yIds('email')` yields the same ids in every\n * environment and on every call — which is exactly what SSR + hydration needs.\n */\n\nconst UNSAFE = /[^A-Za-z0-9_-]+/g;\n\n/** Normalise an arbitrary base into a token safe for use in an id/selector. */\nexport function toIdToken(base: string): string {\n const token = base.trim().replace(UNSAFE, '-').replace(/^-+|-+$/g, '');\n return token.length > 0 ? token : 'field';\n}\n\nexport interface A11yIds {\n /** The normalised base token. */\n readonly base: string;\n /** Id for the primary interactive element (e.g. the input). */\n readonly input: string;\n /** Id for a label element / labelling text. */\n readonly label: string;\n /** Id for descriptive/help text. */\n readonly description: string;\n /** Id for an error message element. */\n readonly error: string;\n /** Id for a title element (e.g. a dialog title). */\n readonly title: string;\n /** Derive an arbitrary suffixed id from the same base. */\n id(suffix: string): string;\n}\n\n/**\n * Build a set of deterministic, SSR-stable ids from a base string.\n *\n * @example\n * const ids = a11yIds('email');\n * // ids.input === 'email-input', ids.label === 'email-label', ...\n * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });\n * text('Email', { id: ids.label });\n */\nexport function a11yIds(base: string): A11yIds {\n const token = toIdToken(base);\n return {\n base: token,\n input: `${token}-input`,\n label: `${token}-label`,\n description: `${token}-description`,\n error: `${token}-error`,\n title: `${token}-title`,\n id: (suffix: string) => `${token}-${toIdToken(suffix)}`,\n };\n}\n","/**\n * Node and application identity utilities.\n * Every node in the semantic graph has a stable, unique identity.\n */\n\nlet _counter = 0;\n\n/** Generate a framework-internal monotonic integer ID. */\nexport function nextId(): number {\n return ++_counter;\n}\n\n/** Reset the counter (test use only). */\nexport function resetIdCounter(): void {\n _counter = 0;\n}\n\n/** Opaque branded type for node IDs. */\nexport type NodeId = string & { readonly __brand: 'NodeId' };\n\n/** Create a NodeId from a string (must be unique at call site). */\nexport function createNodeId(value: string): NodeId {\n return value as NodeId;\n}\n\n/** Generate a fresh, unique NodeId. */\nexport function generateNodeId(prefix: string = 'node'): NodeId {\n return createNodeId(`${prefix}:${nextId()}`);\n}\n\n/** Parse the prefix from a NodeId. */\nexport function nodeIdPrefix(id: NodeId): string {\n const colon = id.indexOf(':');\n return colon === -1 ? id : id.slice(0, colon);\n}\n\n/** Branded type for application IDs. */\nexport type ApplicationId = string & { readonly __brand: 'ApplicationId' };\n\n/** Generate a fresh application ID. */\nexport function generateApplicationId(name: string): ApplicationId {\n return `app:${name}:${nextId()}` as ApplicationId;\n}\n","/**\n * Application and component lifecycle primitives.\n *\n * Lifecycle phases:\n * created → mounted → active ⇄ updating → unmounting → destroyed\n */\n\nexport type LifecyclePhase =\n | 'created'\n | 'mounted'\n | 'active'\n | 'updating'\n | 'unmounting'\n | 'destroyed';\n\nexport type LifecycleHook = () => void | Promise<void>;\n\nexport class Lifecycle {\n private _phase: LifecyclePhase = 'created';\n private readonly _hooks: Map<LifecyclePhase, LifecycleHook[]> = new Map();\n\n get phase(): LifecyclePhase {\n return this._phase;\n }\n\n get isMounted(): boolean {\n return this._phase === 'mounted' || this._phase === 'active' || this._phase === 'updating';\n }\n\n get isDestroyed(): boolean {\n return this._phase === 'destroyed';\n }\n\n on(phase: LifecyclePhase, hook: LifecycleHook): () => void {\n const hooks = this._hooks.get(phase) ?? [];\n hooks.push(hook);\n this._hooks.set(phase, hooks);\n return () => {\n const current = this._hooks.get(phase);\n if (current !== undefined) {\n const idx = current.indexOf(hook);\n if (idx !== -1) current.splice(idx, 1);\n }\n };\n }\n\n async transition(to: LifecyclePhase): Promise<void> {\n this._phase = to;\n const hooks = this._hooks.get(to) ?? [];\n for (const hook of hooks) {\n await hook();\n }\n }\n\n onMount(hook: LifecycleHook): () => void {\n return this.on('mounted', hook);\n }\n\n onUnmount(hook: LifecycleHook): () => void {\n return this.on('unmounting', hook);\n }\n\n onDestroy(hook: LifecycleHook): () => void {\n return this.on('destroyed', hook);\n }\n}\n\n/** A simple cleanup registry — collect teardown functions and run them all at once. */\nexport class CleanupRegistry {\n private readonly _fns: Array<() => void> = [];\n\n add(fn: () => void): void {\n this._fns.push(fn);\n }\n\n run(): void {\n for (const fn of this._fns) {\n try {\n fn();\n } catch {\n // Best-effort cleanup; don't let one failure block others\n }\n }\n this._fns.length = 0;\n }\n}\n","/**\n * Environment detection and capability flags.\n * The framework behaves slightly differently in browser vs. server vs. test.\n *\n * We use `typeof` checks throughout to remain safe across environments\n * without depending on @types/node.\n */\n\nexport type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';\n\nexport interface EnvironmentCapabilities {\n readonly hasDom: boolean;\n readonly hasWindow: boolean;\n readonly hasDocument: boolean;\n readonly isSecureContext: boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ndeclare const process: any;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction detectEnvironment(): EnvironmentKind {\n // Explicit test override via process.env\n try {\n if (\n typeof process !== 'undefined' &&\n process !== null &&\n typeof process === 'object' &&\n (process.env?.['NODE_ENV'] === 'test' || process.env?.['VITEST'] === 'true')\n ) {\n return 'test';\n }\n } catch {\n // process may not be defined in all environments\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return 'browser';\n }\n\n if (\n typeof self !== 'undefined' &&\n typeof (self as unknown as Record<string, unknown>)['importScripts'] === 'function'\n ) {\n return 'worker';\n }\n\n try {\n if (typeof process !== 'undefined' && typeof process === 'object') {\n return 'server';\n }\n } catch {\n // ignore\n }\n\n return 'unknown';\n}\n\nfunction detectCapabilities(): EnvironmentCapabilities {\n return {\n hasDom: typeof document !== 'undefined',\n hasWindow: typeof window !== 'undefined',\n hasDocument: typeof document !== 'undefined',\n isSecureContext:\n typeof window !== 'undefined'\n ? ((window as unknown as Record<string, unknown>)['isSecureContext'] === true)\n : false,\n };\n}\n\nexport class Environment {\n readonly kind: EnvironmentKind;\n readonly capabilities: EnvironmentCapabilities;\n\n constructor(kind?: EnvironmentKind) {\n this.kind = kind ?? detectEnvironment();\n this.capabilities = detectCapabilities();\n }\n\n get isBrowser(): boolean {\n return this.kind === 'browser';\n }\n\n get isServer(): boolean {\n return this.kind === 'server';\n }\n\n get isTest(): boolean {\n return this.kind === 'test';\n }\n\n get isWorker(): boolean {\n return this.kind === 'worker';\n }\n}\n\n/** The singleton environment for this execution context. */\nexport const environment = new Environment();\n","/**\n * Framework diagnostics — structured errors, warnings, and hints\n * that flow through the compiler, validator, and runtime.\n */\n\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info';\n\nexport interface DiagnosticLocation {\n readonly file?: string;\n readonly line?: number;\n readonly column?: number;\n readonly nodeId?: string;\n}\n\nexport interface Diagnostic {\n readonly severity: DiagnosticSeverity;\n readonly code: string;\n readonly message: string;\n readonly location: DiagnosticLocation | undefined;\n readonly cause: unknown;\n}\n\nexport class DiagnosticError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n const summary = diagnostics\n .filter(d => d.severity === 'error')\n .map(d => `[${d.code}] ${d.message}`)\n .join('\\n');\n super(`StreetUI diagnostics:\\n${summary}`);\n this.name = 'DiagnosticError';\n this.diagnostics = diagnostics;\n }\n}\n\nexport class DiagnosticCollector {\n private readonly _diagnostics: Diagnostic[] = [];\n\n get diagnostics(): readonly Diagnostic[] {\n return this._diagnostics;\n }\n\n get hasErrors(): boolean {\n return this._diagnostics.some(d => d.severity === 'error');\n }\n\n get hasWarnings(): boolean {\n return this._diagnostics.some(d => d.severity === 'warning');\n }\n\n error(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n cause?: unknown,\n ): void {\n this._diagnostics.push({ severity: 'error', code, message, location: location ?? undefined, cause: cause ?? undefined });\n }\n\n warn(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'warning', code, message, location: location ?? undefined, cause: undefined });\n }\n\n info(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'info', code, message, location: location ?? undefined, cause: undefined });\n }\n\n merge(other: DiagnosticCollector): void {\n for (const d of other.diagnostics) {\n this._diagnostics.push(d);\n }\n }\n\n throwIfErrors(): void {\n if (this.hasErrors) {\n throw new DiagnosticError(this._diagnostics);\n }\n }\n\n clear(): void {\n this._diagnostics.length = 0;\n }\n}\n\n/** Format a single diagnostic as a human-readable string. */\nexport function formatDiagnostic(d: Diagnostic): string {\n const loc = d.location !== undefined\n ? ` (${[d.location.file, d.location.line, d.location.column]\n .filter(Boolean)\n .join(':')})`\n : '';\n return `[${d.severity.toUpperCase()}] ${d.code}: ${d.message}${loc}`;\n}\n","/**\n * Top-level Application primitive.\n * Owns lifecycle, identity, and the root of the application graph.\n */\n\nimport { type ApplicationId, generateApplicationId } from './identity.js';\nimport { Lifecycle, CleanupRegistry } from './lifecycle.js';\nimport { Environment, environment as defaultEnvironment } from './environment.js';\nimport { DiagnosticCollector } from './diagnostics.js';\n\nexport interface ApplicationOptions {\n readonly name: string;\n readonly version?: string;\n readonly environment?: Environment;\n}\n\nexport class Application {\n readonly id: ApplicationId;\n readonly name: string;\n readonly version: string;\n readonly lifecycle: Lifecycle;\n readonly cleanup: CleanupRegistry;\n readonly diagnostics: DiagnosticCollector;\n readonly environment: Environment;\n\n constructor(options: ApplicationOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.id = generateApplicationId(options.name);\n this.lifecycle = new Lifecycle();\n this.cleanup = new CleanupRegistry();\n this.diagnostics = new DiagnosticCollector();\n this.environment = options.environment ?? defaultEnvironment;\n }\n\n async mount(): Promise<void> {\n if (this.lifecycle.phase !== 'created') {\n throw new Error(`Application \"${this.name}\" is already mounted (phase: ${this.lifecycle.phase})`);\n }\n await this.lifecycle.transition('mounted');\n await this.lifecycle.transition('active');\n }\n\n async unmount(): Promise<void> {\n if (!this.lifecycle.isMounted) {\n return;\n }\n await this.lifecycle.transition('unmounting');\n this.cleanup.run();\n await this.lifecycle.transition('destroyed');\n }\n\n onMount(fn: () => void | Promise<void>): void {\n this.lifecycle.onMount(fn);\n }\n\n onUnmount(fn: () => void | Promise<void>): void {\n this.lifecycle.onUnmount(fn);\n }\n}\n\n/** Factory convenience wrapper. */\nexport function createApplication(options: ApplicationOptions): Application {\n return new Application(options);\n}\n","/**\n * Framework node primitives — the base abstraction for every node\n * in the Semantic Application Graph.\n */\n\nimport { type NodeId, generateNodeId } from './identity.js';\n\nexport type SemanticNodeType =\n | 'application'\n | 'page'\n | 'section'\n | 'container'\n | 'heading'\n | 'text'\n | 'button'\n | 'input'\n | 'form'\n | 'list'\n | 'list-item'\n | 'image'\n | 'link'\n | 'component'\n | 'slot'\n | 'fragment'\n | 'reactive-list'\n | 'conditional';\n\nexport interface NodeMetadata {\n readonly createdAt: number;\n readonly [key: string]: unknown;\n}\n\nexport abstract class BaseNode {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly metadata: NodeMetadata;\n\n constructor(type: SemanticNodeType, id?: NodeId) {\n this.type = type;\n this.id = id ?? generateNodeId(type);\n this.metadata = { createdAt: Date.now() };\n }\n\n abstract clone(): BaseNode;\n}\n","/**\n * Observability boundary — a tiny, optional logging seam plus contextual\n * framework errors.\n *\n * StreetUI never ships a telemetry service, never sends anything over the\n * network, and never logs on its own by default. Instead an application MAY\n * hand the framework a `DiagnosticSink` — any object with the log methods it\n * cares about — and the framework will route the diagnostics it already\n * produces (runtime errors, resource failures, hydration mismatches, router\n * transitions) to it. With no sink attached there is no logging and no cost.\n *\n * This is deliberately smaller than a logging library: it duplicates neither\n * `console` nor any structured-diagnostic type. It is a boundary, not a logger.\n */\n\n/**\n * Where a framework diagnostic originated. Every field is optional so a caller\n * supplies only what is meaningful for the situation. Values are intended to be\n * non-sensitive identifiers — never tokens, secrets, cookies, or form values.\n */\nexport interface DiagnosticContext {\n /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */\n readonly package?: string;\n /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */\n readonly operation?: string;\n /** The graph node id involved, when applicable. */\n readonly nodeId?: string;\n /** The route path involved, when applicable. */\n readonly route?: string;\n /** A resource identifier involved, when applicable. */\n readonly resource?: string;\n}\n\n/**\n * The application-provided logging seam. Every method is optional; the\n * framework calls only the ones present. Implementations must not throw.\n */\nexport interface DiagnosticSink {\n debug?(message: string, context?: DiagnosticContext): void;\n info?(message: string, context?: DiagnosticContext): void;\n warn?(message: string, context?: DiagnosticContext): void;\n error?(message: string, context?: DiagnosticContext): void;\n}\n\n/** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */\nexport function formatDiagnosticContext(context?: DiagnosticContext): string {\n if (context === undefined) return '';\n const parts: string[] = [];\n if (context.package !== undefined) parts.push(`package=${context.package}`);\n if (context.operation !== undefined) parts.push(`operation=${context.operation}`);\n if (context.nodeId !== undefined) parts.push(`node=${context.nodeId}`);\n if (context.route !== undefined) parts.push(`route=${context.route}`);\n if (context.resource !== undefined) parts.push(`resource=${context.resource}`);\n return parts.length > 0 ? ` [${parts.join(', ')}]` : '';\n}\n\n/**\n * A framework error whose message carries structured, non-sensitive context so\n * a developer immediately sees which package/operation/node was involved. The\n * message never embeds a stack or environment values; production stack\n * disclosure decisions stay with the server layer.\n */\nexport class StreetFrameworkError extends Error {\n readonly context: DiagnosticContext | undefined;\n\n constructor(message: string, context?: DiagnosticContext) {\n super(`${message}${formatDiagnosticContext(context)}`);\n this.name = 'StreetFrameworkError';\n this.context = context ?? undefined;\n }\n}\n\n/** Build a `StreetFrameworkError` with the given context. */\nexport function frameworkError(\n message: string,\n context?: DiagnosticContext,\n): StreetFrameworkError {\n return new StreetFrameworkError(message, context);\n}\n\n/**\n * Route a diagnostic to a sink if it implements the matching level. Safe to\n * call with `undefined` — it simply does nothing, which is the default (no\n * logging) posture. Never throws even if the sink method does.\n */\nexport function reportDiagnostic(\n sink: DiagnosticSink | undefined,\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n context?: DiagnosticContext,\n): void {\n if (sink === undefined) return;\n const fn = sink[level];\n if (typeof fn !== 'function') return;\n try {\n fn.call(sink, message, context);\n } catch {\n // A misbehaving sink must never break the framework.\n }\n}\n\n/** A sink that forwards to a `console`-like object, one call per level. */\nexport function consoleDiagnosticSink(\n logger: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>> = console,\n): DiagnosticSink {\n return {\n debug: (m, c) => logger.debug?.(`${m}${formatDiagnosticContext(c)}`),\n info: (m, c) => logger.info?.(`${m}${formatDiagnosticContext(c)}`),\n warn: (m, c) => logger.warn?.(`${m}${formatDiagnosticContext(c)}`),\n error: (m, c) => logger.error?.(`${m}${formatDiagnosticContext(c)}`),\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/a11y-ids.ts","../src/identity.ts","../src/lifecycle.ts","../src/environment.ts","../src/diagnostics.ts","../src/application.ts","../src/node.ts","../src/observability.ts"],"sourcesContent":["/**\n * Deterministic accessibility id helpers.\n *\n * Accessible markup often needs stable id relationships — a `<label for>` (or\n * `aria-labelledby`) pointing at an input, an `aria-describedby` pointing at a\n * hint/error, an `aria-labelledby` on a dialog pointing at its title. Those ids\n * must be IDENTICAL on the server and the client, otherwise a hydrated subtree\n * that re-renders (e.g. a toggled `when()` branch) would compute a different id\n * than the server emitted and break the association.\n *\n * These helpers derive ids purely from a caller-supplied stable base string\n * (typically a form field name or a dialog name). They use NO incrementing\n * counter and NO randomness, so `a11yIds('email')` yields the same ids in every\n * environment and on every call — which is exactly what SSR + hydration needs.\n */\n\nconst UNSAFE = /[^A-Za-z0-9_-]+/g;\n\n/** Normalise an arbitrary base into a token safe for use in an id/selector. */\nexport function toIdToken(base: string): string {\n const token = base.trim().replace(UNSAFE, '-').replace(/^-+|-+$/g, '');\n return token.length > 0 ? token : 'field';\n}\n\nexport interface A11yIds {\n /** The normalised base token. */\n readonly base: string;\n /** Id for the primary interactive element (e.g. the input). */\n readonly input: string;\n /** Id for a label element / labelling text. */\n readonly label: string;\n /** Id for descriptive/help text. */\n readonly description: string;\n /** Id for an error message element. */\n readonly error: string;\n /** Id for a title element (e.g. a dialog title). */\n readonly title: string;\n /** Derive an arbitrary suffixed id from the same base. */\n id(suffix: string): string;\n}\n\n/**\n * Build a set of deterministic, SSR-stable ids from a base string.\n *\n * @example\n * const ids = a11yIds('email');\n * // ids.input === 'email-input', ids.label === 'email-label', ...\n * input({ bind: value, id: ids.input, ariaLabelledBy: ids.label, ariaDescribedBy: ids.error });\n * text('Email', { id: ids.label });\n */\nexport function a11yIds(base: string): A11yIds {\n const token = toIdToken(base);\n return {\n base: token,\n input: `${token}-input`,\n label: `${token}-label`,\n description: `${token}-description`,\n error: `${token}-error`,\n title: `${token}-title`,\n id: (suffix: string) => `${token}-${toIdToken(suffix)}`,\n };\n}\n","/**\n * Node and application identity utilities.\n * Every node in the semantic graph has a stable, unique identity.\n */\n\nlet _counter = 0;\n\n/** Generate a framework-internal monotonic integer ID. */\nexport function nextId(): number {\n return ++_counter;\n}\n\n/** Reset the counter (test use only). */\nexport function resetIdCounter(): void {\n _counter = 0;\n}\n\n/** Opaque branded type for node IDs. */\nexport type NodeId = string & { readonly __brand: 'NodeId' };\n\n/** Create a NodeId from a string (must be unique at call site). */\nexport function createNodeId(value: string): NodeId {\n return value as NodeId;\n}\n\n/** Generate a fresh, unique NodeId. */\nexport function generateNodeId(prefix: string = 'node'): NodeId {\n return createNodeId(`${prefix}:${nextId()}`);\n}\n\n/** Parse the prefix from a NodeId. */\nexport function nodeIdPrefix(id: NodeId): string {\n const colon = id.indexOf(':');\n return colon === -1 ? id : id.slice(0, colon);\n}\n\n/** Branded type for application IDs. */\nexport type ApplicationId = string & { readonly __brand: 'ApplicationId' };\n\n/** Generate a fresh application ID. */\nexport function generateApplicationId(name: string): ApplicationId {\n return `app:${name}:${nextId()}` as ApplicationId;\n}\n","/**\n * Application and component lifecycle primitives.\n *\n * Lifecycle phases:\n * created → mounted → active ⇄ updating → unmounting → destroyed\n */\n\nexport type LifecyclePhase =\n | 'created'\n | 'mounted'\n | 'active'\n | 'updating'\n | 'unmounting'\n | 'destroyed';\n\nexport type LifecycleHook = () => void | Promise<void>;\n\nexport class Lifecycle {\n private _phase: LifecyclePhase = 'created';\n private readonly _hooks: Map<LifecyclePhase, LifecycleHook[]> = new Map();\n\n get phase(): LifecyclePhase {\n return this._phase;\n }\n\n get isMounted(): boolean {\n return this._phase === 'mounted' || this._phase === 'active' || this._phase === 'updating';\n }\n\n get isDestroyed(): boolean {\n return this._phase === 'destroyed';\n }\n\n on(phase: LifecyclePhase, hook: LifecycleHook): () => void {\n const hooks = this._hooks.get(phase) ?? [];\n hooks.push(hook);\n this._hooks.set(phase, hooks);\n return () => {\n const current = this._hooks.get(phase);\n if (current !== undefined) {\n const idx = current.indexOf(hook);\n if (idx !== -1) current.splice(idx, 1);\n }\n };\n }\n\n async transition(to: LifecyclePhase): Promise<void> {\n this._phase = to;\n const hooks = this._hooks.get(to) ?? [];\n for (const hook of hooks) {\n await hook();\n }\n }\n\n onMount(hook: LifecycleHook): () => void {\n return this.on('mounted', hook);\n }\n\n onUnmount(hook: LifecycleHook): () => void {\n return this.on('unmounting', hook);\n }\n\n onDestroy(hook: LifecycleHook): () => void {\n return this.on('destroyed', hook);\n }\n}\n\n/** A simple cleanup registry — collect teardown functions and run them all at once. */\nexport class CleanupRegistry {\n private readonly _fns: Array<() => void> = [];\n\n add(fn: () => void): void {\n this._fns.push(fn);\n }\n\n run(): void {\n for (const fn of this._fns) {\n try {\n fn();\n } catch {\n // Best-effort cleanup; don't let one failure block others\n }\n }\n this._fns.length = 0;\n }\n}\n","/**\n * Environment detection and capability flags.\n * The framework behaves slightly differently in browser vs. server vs. test.\n *\n * We use `typeof` checks throughout to remain safe across environments\n * without depending on @types/node.\n */\n\nexport type EnvironmentKind = 'browser' | 'server' | 'worker' | 'test' | 'unknown';\n\nexport interface EnvironmentCapabilities {\n readonly hasDom: boolean;\n readonly hasWindow: boolean;\n readonly hasDocument: boolean;\n readonly isSecureContext: boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ndeclare const process: any;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nfunction detectEnvironment(): EnvironmentKind {\n // Explicit test override via process.env\n try {\n if (\n typeof process !== 'undefined' &&\n process !== null &&\n typeof process === 'object' &&\n (process.env?.['NODE_ENV'] === 'test' || process.env?.['VITEST'] === 'true')\n ) {\n return 'test';\n }\n } catch {\n // process may not be defined in all environments\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n return 'browser';\n }\n\n if (\n typeof self !== 'undefined' &&\n typeof (self as unknown as Record<string, unknown>)['importScripts'] === 'function'\n ) {\n return 'worker';\n }\n\n try {\n if (typeof process !== 'undefined' && typeof process === 'object') {\n return 'server';\n }\n } catch {\n // ignore\n }\n\n return 'unknown';\n}\n\nfunction detectCapabilities(): EnvironmentCapabilities {\n return {\n hasDom: typeof document !== 'undefined',\n hasWindow: typeof window !== 'undefined',\n hasDocument: typeof document !== 'undefined',\n isSecureContext:\n typeof window !== 'undefined'\n ? ((window as unknown as Record<string, unknown>)['isSecureContext'] === true)\n : false,\n };\n}\n\nexport class Environment {\n readonly kind: EnvironmentKind;\n readonly capabilities: EnvironmentCapabilities;\n\n constructor(kind?: EnvironmentKind) {\n this.kind = kind ?? detectEnvironment();\n this.capabilities = detectCapabilities();\n }\n\n get isBrowser(): boolean {\n return this.kind === 'browser';\n }\n\n get isServer(): boolean {\n return this.kind === 'server';\n }\n\n get isTest(): boolean {\n return this.kind === 'test';\n }\n\n get isWorker(): boolean {\n return this.kind === 'worker';\n }\n}\n\n/** The singleton environment for this execution context. */\nexport const environment = new Environment();\n","/**\n * Framework diagnostics — structured errors, warnings, and hints\n * that flow through the compiler, validator, and runtime.\n */\n\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info';\n\nexport interface DiagnosticLocation {\n readonly file?: string;\n readonly line?: number;\n readonly column?: number;\n readonly nodeId?: string;\n}\n\nexport interface Diagnostic {\n readonly severity: DiagnosticSeverity;\n readonly code: string;\n readonly message: string;\n readonly location: DiagnosticLocation | undefined;\n readonly cause: unknown;\n}\n\nexport class DiagnosticError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n const summary = diagnostics\n .filter(d => d.severity === 'error')\n .map(d => `[${d.code}] ${d.message}`)\n .join('\\n');\n super(`StreetUI diagnostics:\\n${summary}`);\n this.name = 'DiagnosticError';\n this.diagnostics = diagnostics;\n }\n}\n\nexport class DiagnosticCollector {\n private readonly _diagnostics: Diagnostic[] = [];\n\n get diagnostics(): readonly Diagnostic[] {\n return this._diagnostics;\n }\n\n get hasErrors(): boolean {\n return this._diagnostics.some(d => d.severity === 'error');\n }\n\n get hasWarnings(): boolean {\n return this._diagnostics.some(d => d.severity === 'warning');\n }\n\n error(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n cause?: unknown,\n ): void {\n this._diagnostics.push({ severity: 'error', code, message, location: location ?? undefined, cause: cause ?? undefined });\n }\n\n warn(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'warning', code, message, location: location ?? undefined, cause: undefined });\n }\n\n info(\n code: string,\n message: string,\n location?: DiagnosticLocation,\n ): void {\n this._diagnostics.push({ severity: 'info', code, message, location: location ?? undefined, cause: undefined });\n }\n\n merge(other: DiagnosticCollector): void {\n for (const d of other.diagnostics) {\n this._diagnostics.push(d);\n }\n }\n\n throwIfErrors(): void {\n if (this.hasErrors) {\n throw new DiagnosticError(this._diagnostics);\n }\n }\n\n clear(): void {\n this._diagnostics.length = 0;\n }\n}\n\n/** Format a single diagnostic as a human-readable string. */\nexport function formatDiagnostic(d: Diagnostic): string {\n const loc = d.location !== undefined\n ? ` (${[d.location.file, d.location.line, d.location.column]\n .filter(Boolean)\n .join(':')})`\n : '';\n return `[${d.severity.toUpperCase()}] ${d.code}: ${d.message}${loc}`;\n}\n","/**\n * Top-level Application primitive.\n * Owns lifecycle, identity, and the root of the application graph.\n */\n\nimport { type ApplicationId, generateApplicationId } from './identity.js';\nimport { Lifecycle, CleanupRegistry } from './lifecycle.js';\nimport { Environment, environment as defaultEnvironment } from './environment.js';\nimport { DiagnosticCollector } from './diagnostics.js';\n\nexport interface ApplicationOptions {\n readonly name: string;\n readonly version?: string;\n readonly environment?: Environment;\n}\n\nexport class Application {\n readonly id: ApplicationId;\n readonly name: string;\n readonly version: string;\n readonly lifecycle: Lifecycle;\n readonly cleanup: CleanupRegistry;\n readonly diagnostics: DiagnosticCollector;\n readonly environment: Environment;\n\n constructor(options: ApplicationOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.id = generateApplicationId(options.name);\n this.lifecycle = new Lifecycle();\n this.cleanup = new CleanupRegistry();\n this.diagnostics = new DiagnosticCollector();\n this.environment = options.environment ?? defaultEnvironment;\n }\n\n async mount(): Promise<void> {\n if (this.lifecycle.phase !== 'created') {\n throw new Error(`Application \"${this.name}\" is already mounted (phase: ${this.lifecycle.phase})`);\n }\n await this.lifecycle.transition('mounted');\n await this.lifecycle.transition('active');\n }\n\n async unmount(): Promise<void> {\n if (!this.lifecycle.isMounted) {\n return;\n }\n await this.lifecycle.transition('unmounting');\n this.cleanup.run();\n await this.lifecycle.transition('destroyed');\n }\n\n onMount(fn: () => void | Promise<void>): void {\n this.lifecycle.onMount(fn);\n }\n\n onUnmount(fn: () => void | Promise<void>): void {\n this.lifecycle.onUnmount(fn);\n }\n}\n\n/** Factory convenience wrapper. */\nexport function createApplication(options: ApplicationOptions): Application {\n return new Application(options);\n}\n","/**\n * Framework node primitives — the base abstraction for every node\n * in the Semantic Application Graph.\n */\n\nimport { type NodeId, generateNodeId } from './identity.js';\n\nexport type SemanticNodeType =\n | 'application'\n | 'page'\n | 'section'\n | 'container'\n | 'heading'\n | 'text'\n | 'button'\n | 'input'\n | 'form'\n | 'list'\n | 'list-item'\n | 'image'\n | 'link'\n | 'component'\n | 'slot'\n | 'fragment'\n | 'reactive-list'\n | 'conditional'\n | 'portal';\n\nexport interface NodeMetadata {\n readonly createdAt: number;\n readonly [key: string]: unknown;\n}\n\nexport abstract class BaseNode {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly metadata: NodeMetadata;\n\n constructor(type: SemanticNodeType, id?: NodeId) {\n this.type = type;\n this.id = id ?? generateNodeId(type);\n this.metadata = { createdAt: Date.now() };\n }\n\n abstract clone(): BaseNode;\n}\n","/**\n * Observability boundary — a tiny, optional logging seam plus contextual\n * framework errors.\n *\n * StreetUI never ships a telemetry service, never sends anything over the\n * network, and never logs on its own by default. Instead an application MAY\n * hand the framework a `DiagnosticSink` — any object with the log methods it\n * cares about — and the framework will route the diagnostics it already\n * produces (runtime errors, resource failures, hydration mismatches, router\n * transitions) to it. With no sink attached there is no logging and no cost.\n *\n * This is deliberately smaller than a logging library: it duplicates neither\n * `console` nor any structured-diagnostic type. It is a boundary, not a logger.\n */\n\n/**\n * Where a framework diagnostic originated. Every field is optional so a caller\n * supplies only what is meaningful for the situation. Values are intended to be\n * non-sensitive identifiers — never tokens, secrets, cookies, or form values.\n */\nexport interface DiagnosticContext {\n /** The package that produced the diagnostic, e.g. `@streetui/renderer`. */\n readonly package?: string;\n /** The operation underway, e.g. `hydrate`, `compile`, `navigate`. */\n readonly operation?: string;\n /** The graph node id involved, when applicable. */\n readonly nodeId?: string;\n /** The route path involved, when applicable. */\n readonly route?: string;\n /** A resource identifier involved, when applicable. */\n readonly resource?: string;\n}\n\n/**\n * The application-provided logging seam. Every method is optional; the\n * framework calls only the ones present. Implementations must not throw.\n */\nexport interface DiagnosticSink {\n debug?(message: string, context?: DiagnosticContext): void;\n info?(message: string, context?: DiagnosticContext): void;\n warn?(message: string, context?: DiagnosticContext): void;\n error?(message: string, context?: DiagnosticContext): void;\n}\n\n/** Format a context object as a compact ` [k=v, …]` suffix (empty when bare). */\nexport function formatDiagnosticContext(context?: DiagnosticContext): string {\n if (context === undefined) return '';\n const parts: string[] = [];\n if (context.package !== undefined) parts.push(`package=${context.package}`);\n if (context.operation !== undefined) parts.push(`operation=${context.operation}`);\n if (context.nodeId !== undefined) parts.push(`node=${context.nodeId}`);\n if (context.route !== undefined) parts.push(`route=${context.route}`);\n if (context.resource !== undefined) parts.push(`resource=${context.resource}`);\n return parts.length > 0 ? ` [${parts.join(', ')}]` : '';\n}\n\n/**\n * A framework error whose message carries structured, non-sensitive context so\n * a developer immediately sees which package/operation/node was involved. The\n * message never embeds a stack or environment values; production stack\n * disclosure decisions stay with the server layer.\n */\nexport class StreetFrameworkError extends Error {\n readonly context: DiagnosticContext | undefined;\n\n constructor(message: string, context?: DiagnosticContext) {\n super(`${message}${formatDiagnosticContext(context)}`);\n this.name = 'StreetFrameworkError';\n this.context = context ?? undefined;\n }\n}\n\n/** Build a `StreetFrameworkError` with the given context. */\nexport function frameworkError(\n message: string,\n context?: DiagnosticContext,\n): StreetFrameworkError {\n return new StreetFrameworkError(message, context);\n}\n\n/**\n * Route a diagnostic to a sink if it implements the matching level. Safe to\n * call with `undefined` — it simply does nothing, which is the default (no\n * logging) posture. Never throws even if the sink method does.\n */\nexport function reportDiagnostic(\n sink: DiagnosticSink | undefined,\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n context?: DiagnosticContext,\n): void {\n if (sink === undefined) return;\n const fn = sink[level];\n if (typeof fn !== 'function') return;\n try {\n fn.call(sink, message, context);\n } catch {\n // A misbehaving sink must never break the framework.\n }\n}\n\n/** A sink that forwards to a `console`-like object, one call per level. */\nexport function consoleDiagnosticSink(\n logger: Partial<Record<'debug' | 'info' | 'warn' | 'error', (msg: string) => void>> = console,\n): DiagnosticSink {\n return {\n debug: (m, c) => logger.debug?.(`${m}${formatDiagnosticContext(c)}`),\n info: (m, c) => logger.info?.(`${m}${formatDiagnosticContext(c)}`),\n warn: (m, c) => logger.warn?.(`${m}${formatDiagnosticContext(c)}`),\n error: (m, c) => logger.error?.(`${m}${formatDiagnosticContext(c)}`),\n };\n}\n"],"mappings":"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","names":[]}
|