/** * Widget — kontrakt smart/dumb + manifest. * * DUMB widget: * - OnPush * - tylko @Input/@Output (lub signal equivalent) * - zero `inject()` poza: I18N, Clock (dla display), Logger * - NIE importuje HttpClient, DataBus, EventBus, Router, localStorage * - pure funkcja stanu wejściowego → DOM * - extends EchelonDumbWidget * * SMART (kontener) NIE JEST pisany ręcznie — runtime generuje WidgetHost * z manifestu. Zajmuje się: resolve bindingów, ACL gate, compliance gate, * error boundary, lifecycle events, propagacja outputs → event bus. * * Testowalność enforced: * - data-testid na root + interakcjach (generowane z ID z configu) * - getState(), getBindings(), lifecycle$ * - lifecycle: mounted → bindings-resolved → ready → busy/error/destroyed * - sygnalizowane przez data-echelon-state */ import type { Observable } from 'rxjs'; import type { WidgetId } from '../identity/index.js'; import type { AclKey } from '../acl/index.js'; import type { EchelonError } from '../errors/index.js'; export type WidgetLifecycleState = 'mounted' | 'bindings-resolved' | 'ready' | 'busy' | 'error' | 'destroyed'; export interface WidgetLifecycleEvent { readonly state: WidgetLifecycleState; readonly at: number; readonly error?: EchelonError; } export type BindingMap = ReadonlyMap; /** * Base contract dla dumb widgetu. Implementacja (klasa bazowa) żyje w `@echelon-framework/runtime` * jako `EchelonDumbWidget` — tu tylko kontrakt. */ export interface DumbWidget { readonly id: WidgetId; readonly lifecycle$: Observable; getState(): TState; getBindings(): BindingMap; } /** Klasy input / output manifestu. */ export interface WidgetInputSpec { readonly name: string; readonly type: string; readonly required?: boolean; readonly description?: string; } export interface WidgetOutputSpec { readonly name: string; readonly eventType?: string; readonly description?: string; } export interface WidgetActionSpec { readonly id: string; readonly acl?: AclKey; readonly description?: string; } export interface WidgetTestabilityManifest { readonly interactions: readonly { readonly action: string; readonly params?: readonly string[]; }[]; readonly observables: readonly string[]; readonly lifecycleGates: readonly WidgetLifecycleState[]; } export interface WidgetCapabilities { readonly dataBus?: 'read' | 'none'; readonly eventBus?: 'emit' | 'listen' | 'both' | 'none'; readonly audit?: 'write' | 'none'; readonly clock?: 'read' | 'none'; readonly random?: 'read' | 'none'; } /** * Manifest widgetu — single source of truth dla lintera, LSP, designera, codegenu. * Generowany z dekoratora TS przy buildzie (lub ręczny .manifest.json). */ export interface WidgetManifest { readonly type: string; readonly version: string; readonly description?: string; readonly category?: string; readonly icon?: string; readonly inputs: readonly WidgetInputSpec[]; readonly outputs: readonly WidgetOutputSpec[]; readonly actions: readonly WidgetActionSpec[]; readonly capabilities: WidgetCapabilities; readonly testability: WidgetTestabilityManifest; /** JSON Schema options sekcji configu widgetu — pozwala na walidację. */ readonly optionsSchema?: Readonly>; } /** * Runtime registry widgetów — immutable po rejestracji przy starcie. * Config JSON NIE MOŻE wprowadzić nowego typu — tylko wybierać z zarejestrowanych. */ export interface WidgetRegistry { register(manifest: WidgetManifest, ctor: unknown): void; has(type: string): boolean; get(type: string): { manifest: WidgetManifest; ctor: unknown; } | undefined; all(): readonly WidgetManifest[]; /** Zamraża registry — po tym `register` rzuca. Wołane przez runtime przy bootstrapie. */ freeze(): void; } export declare const WIDGET_REGISTRY: import("../index.js").EchelonToken; //# sourceMappingURL=index.d.ts.map