@blac/core 2.0.0-rc-11 → 2.0.0-rc-13

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,192 @@
1
+ import { BlacPlugin, PluginRegistry, PluginMetrics, ErrorContext } from '../core/types';
2
+ import { BlocBase } from '../BlocBase';
3
+ import { Bloc } from '../Bloc';
4
+
5
+ /**
6
+ * Registry for system-wide plugins
7
+ */
8
+ export class SystemPluginRegistry implements PluginRegistry<BlacPlugin> {
9
+ private plugins = new Map<string, BlacPlugin>();
10
+ private metrics = new Map<string, Map<string, PluginMetrics>>();
11
+ private executionOrder: string[] = [];
12
+
13
+ /**
14
+ * Add a system plugin
15
+ */
16
+ add(plugin: BlacPlugin): void {
17
+ if (this.plugins.has(plugin.name)) {
18
+ throw new Error(`Plugin '${plugin.name}' is already registered`);
19
+ }
20
+
21
+ this.plugins.set(plugin.name, plugin);
22
+ this.executionOrder.push(plugin.name);
23
+ this.initializeMetrics(plugin.name);
24
+ }
25
+
26
+ /**
27
+ * Remove a system plugin
28
+ */
29
+ remove(pluginName: string): boolean {
30
+ const plugin = this.plugins.get(pluginName);
31
+ if (!plugin) return false;
32
+
33
+ this.plugins.delete(pluginName);
34
+ this.metrics.delete(pluginName);
35
+ this.executionOrder = this.executionOrder.filter(name => name !== pluginName);
36
+
37
+ return true;
38
+ }
39
+
40
+ /**
41
+ * Get a plugin by name
42
+ */
43
+ get(pluginName: string): BlacPlugin | undefined {
44
+ return this.plugins.get(pluginName);
45
+ }
46
+
47
+ /**
48
+ * Get all plugins in execution order
49
+ */
50
+ getAll(): ReadonlyArray<BlacPlugin> {
51
+ return this.executionOrder.map(name => this.plugins.get(name)!);
52
+ }
53
+
54
+ /**
55
+ * Clear all plugins
56
+ */
57
+ clear(): void {
58
+ this.plugins.clear();
59
+ this.metrics.clear();
60
+ this.executionOrder = [];
61
+ }
62
+
63
+ /**
64
+ * Execute a hook on all plugins
65
+ */
66
+ executeHook(
67
+ hookName: keyof BlacPlugin,
68
+ args: unknown[],
69
+ errorHandler?: (error: Error, plugin: BlacPlugin) => void
70
+ ): void {
71
+ for (const pluginName of this.executionOrder) {
72
+ const plugin = this.plugins.get(pluginName)!;
73
+ const hook = plugin[hookName] as Function | undefined;
74
+
75
+ if (typeof hook !== 'function') continue;
76
+
77
+ const startTime = performance.now();
78
+
79
+ try {
80
+ hook.apply(plugin, args);
81
+ this.recordSuccess(pluginName, hookName as string, startTime);
82
+ } catch (error) {
83
+ this.recordError(pluginName, hookName as string, error as Error);
84
+
85
+ if (errorHandler) {
86
+ errorHandler(error as Error, plugin);
87
+ } else {
88
+ // Default: log and continue
89
+ console.error(`Plugin '${pluginName}' error in hook '${hookName as string}':`, error);
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Bootstrap all plugins
97
+ */
98
+ bootstrap(): void {
99
+ this.executeHook('beforeBootstrap', []);
100
+ this.executeHook('afterBootstrap', []);
101
+ }
102
+
103
+ /**
104
+ * Shutdown all plugins
105
+ */
106
+ shutdown(): void {
107
+ this.executeHook('beforeShutdown', []);
108
+ this.executeHook('afterShutdown', []);
109
+ }
110
+
111
+ /**
112
+ * Notify plugins of bloc creation
113
+ */
114
+ notifyBlocCreated(bloc: BlocBase<any>): void {
115
+ this.executeHook('onBlocCreated', [bloc]);
116
+ }
117
+
118
+ /**
119
+ * Notify plugins of bloc disposal
120
+ */
121
+ notifyBlocDisposed(bloc: BlocBase<any>): void {
122
+ this.executeHook('onBlocDisposed', [bloc]);
123
+ }
124
+
125
+ /**
126
+ * Notify plugins of state change
127
+ */
128
+ notifyStateChanged(bloc: BlocBase<any>, previousState: any, currentState: any): void {
129
+ this.executeHook('onStateChanged', [bloc, previousState, currentState]);
130
+ }
131
+
132
+ /**
133
+ * Notify plugins of event addition
134
+ */
135
+ notifyEventAdded(bloc: Bloc<any, any>, event: any): void {
136
+ this.executeHook('onEventAdded', [bloc, event]);
137
+ }
138
+
139
+ /**
140
+ * Notify plugins of errors
141
+ */
142
+ notifyError(error: Error, bloc: BlocBase<unknown>, context: ErrorContext): void {
143
+ this.executeHook('onError', [error, bloc, context], (hookError, plugin) => {
144
+ // Double fault protection - if error handler fails, just log
145
+ console.error(`Plugin '${plugin.name}' error handler failed:`, hookError);
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Get metrics for a plugin
151
+ */
152
+ getMetrics(pluginName: string): Map<string, PluginMetrics> | undefined {
153
+ return this.metrics.get(pluginName);
154
+ }
155
+
156
+ private initializeMetrics(pluginName: string): void {
157
+ this.metrics.set(pluginName, new Map());
158
+ }
159
+
160
+ private recordSuccess(pluginName: string, hookName: string, startTime: number): void {
161
+ const pluginMetrics = this.metrics.get(pluginName)!;
162
+ const hookMetrics = pluginMetrics.get(hookName) || {
163
+ executionTime: 0,
164
+ executionCount: 0,
165
+ errorCount: 0
166
+ };
167
+
168
+ const executionTime = performance.now() - startTime;
169
+
170
+ pluginMetrics.set(hookName, {
171
+ ...hookMetrics,
172
+ executionTime: hookMetrics.executionTime + executionTime,
173
+ executionCount: hookMetrics.executionCount + 1,
174
+ lastExecutionTime: executionTime
175
+ });
176
+ }
177
+
178
+ private recordError(pluginName: string, hookName: string, error: Error): void {
179
+ const pluginMetrics = this.metrics.get(pluginName)!;
180
+ const hookMetrics = pluginMetrics.get(hookName) || {
181
+ executionTime: 0,
182
+ executionCount: 0,
183
+ errorCount: 0
184
+ };
185
+
186
+ pluginMetrics.set(hookName, {
187
+ ...hookMetrics,
188
+ errorCount: hookMetrics.errorCount + 1,
189
+ lastError: error
190
+ });
191
+ }
192
+ }
@@ -0,0 +1,8 @@
1
+ // Core types
2
+ export * from './types';
3
+
4
+ // System plugins
5
+ export { SystemPluginRegistry } from './SystemPluginRegistry';
6
+
7
+ // Bloc plugins
8
+ export { BlocPluginRegistry } from './BlocPluginRegistry';
@@ -0,0 +1,100 @@
1
+ import { BlocBase } from '../BlocBase';
2
+ import { Bloc } from '../Bloc';
3
+
4
+ /**
5
+ * Error context provided to error handlers
6
+ */
7
+ export interface ErrorContext {
8
+ readonly phase: 'initialization' | 'state-change' | 'event-processing' | 'disposal';
9
+ readonly operation: string;
10
+ readonly metadata?: Record<string, unknown>;
11
+ }
12
+
13
+ /**
14
+ * Plugin capabilities for security model
15
+ */
16
+ export interface PluginCapabilities {
17
+ readonly readState: boolean;
18
+ readonly transformState: boolean;
19
+ readonly interceptEvents: boolean;
20
+ readonly persistData: boolean;
21
+ readonly accessMetadata: boolean;
22
+ }
23
+
24
+ /**
25
+ * Base interface for all plugins
26
+ */
27
+ export interface Plugin {
28
+ readonly name: string;
29
+ readonly version: string;
30
+ readonly capabilities?: PluginCapabilities;
31
+ }
32
+
33
+ /**
34
+ * System-wide plugin that observes all blocs
35
+ */
36
+ export interface BlacPlugin extends Plugin {
37
+ // Lifecycle hooks - all synchronous
38
+ beforeBootstrap?(): void;
39
+ afterBootstrap?(): void;
40
+ beforeShutdown?(): void;
41
+ afterShutdown?(): void;
42
+
43
+ // System-wide observations
44
+ onBlocCreated?(bloc: BlocBase<any>): void;
45
+ onBlocDisposed?(bloc: BlocBase<any>): void;
46
+ onStateChanged?(bloc: BlocBase<any>, previousState: any, currentState: any): void;
47
+ onEventAdded?(bloc: Bloc<any, any>, event: any): void;
48
+ onError?(error: Error, bloc: BlocBase<unknown>, context: ErrorContext): void;
49
+ }
50
+
51
+ /**
52
+ * Bloc-specific plugin that can transform behavior
53
+ */
54
+ export interface BlocPlugin<TState = any, TEvent = never> extends Plugin {
55
+ // Transform hooks - can modify data
56
+ transformState?(previousState: TState, nextState: TState): TState;
57
+ transformEvent?(event: TEvent): TEvent | null;
58
+
59
+ // Lifecycle hooks
60
+ onAttach?(bloc: BlocBase<TState, any>): void;
61
+ onDetach?(): void;
62
+
63
+ // Observation hooks
64
+ onStateChange?(previousState: TState, currentState: TState): void;
65
+ onEvent?(event: TEvent): void;
66
+ onError?(error: Error, context: ErrorContext): void;
67
+ }
68
+
69
+ /**
70
+ * Plugin execution context for performance monitoring
71
+ */
72
+ export interface PluginExecutionContext {
73
+ readonly pluginName: string;
74
+ readonly hookName: string;
75
+ readonly startTime: number;
76
+ readonly blocName?: string;
77
+ readonly blocId?: string;
78
+ }
79
+
80
+ /**
81
+ * Plugin metrics for monitoring
82
+ */
83
+ export interface PluginMetrics {
84
+ readonly executionTime: number;
85
+ readonly executionCount: number;
86
+ readonly errorCount: number;
87
+ readonly lastError?: Error;
88
+ readonly lastExecutionTime?: number;
89
+ }
90
+
91
+ /**
92
+ * Plugin registry interface
93
+ */
94
+ export interface PluginRegistry<T extends Plugin> {
95
+ add(plugin: T): void;
96
+ remove(pluginName: string): boolean;
97
+ get(pluginName: string): T | undefined;
98
+ getAll(): ReadonlyArray<T>;
99
+ clear(): void;
100
+ }