@objectstack/core 4.0.4 → 4.0.5

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.
Files changed (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +169 -507
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +24 -223
  5. package/dist/index.d.ts +24 -223
  6. package/dist/index.js +175 -505
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.cjs +177 -0
  9. package/dist/logger.cjs.map +1 -0
  10. package/dist/logger.d.cts +26 -0
  11. package/dist/logger.d.ts +26 -0
  12. package/dist/logger.js +158 -0
  13. package/dist/logger.js.map +1 -0
  14. package/package.json +36 -15
  15. package/.turbo/turbo-build.log +0 -22
  16. package/ADVANCED_FEATURES.md +0 -380
  17. package/API_REGISTRY.md +0 -392
  18. package/CHANGELOG.md +0 -472
  19. package/PHASE2_IMPLEMENTATION.md +0 -388
  20. package/REFACTORING_SUMMARY.md +0 -40
  21. package/examples/api-registry-example.ts +0 -559
  22. package/examples/kernel-features-example.ts +0 -311
  23. package/examples/phase2-integration.ts +0 -357
  24. package/src/api-registry-plugin.test.ts +0 -393
  25. package/src/api-registry-plugin.ts +0 -89
  26. package/src/api-registry.test.ts +0 -1089
  27. package/src/api-registry.ts +0 -739
  28. package/src/contracts/data-engine.ts +0 -57
  29. package/src/contracts/http-server.ts +0 -151
  30. package/src/contracts/logger.ts +0 -72
  31. package/src/dependency-resolver.test.ts +0 -287
  32. package/src/dependency-resolver.ts +0 -390
  33. package/src/fallbacks/fallbacks.test.ts +0 -281
  34. package/src/fallbacks/index.ts +0 -26
  35. package/src/fallbacks/memory-cache.ts +0 -34
  36. package/src/fallbacks/memory-i18n.ts +0 -112
  37. package/src/fallbacks/memory-job.ts +0 -23
  38. package/src/fallbacks/memory-metadata.ts +0 -50
  39. package/src/fallbacks/memory-queue.ts +0 -28
  40. package/src/health-monitor.test.ts +0 -81
  41. package/src/health-monitor.ts +0 -318
  42. package/src/hot-reload.ts +0 -382
  43. package/src/index.ts +0 -50
  44. package/src/kernel-base.ts +0 -273
  45. package/src/kernel.test.ts +0 -624
  46. package/src/kernel.ts +0 -631
  47. package/src/lite-kernel.test.ts +0 -248
  48. package/src/lite-kernel.ts +0 -137
  49. package/src/logger.test.ts +0 -116
  50. package/src/logger.ts +0 -355
  51. package/src/namespace-resolver.test.ts +0 -130
  52. package/src/namespace-resolver.ts +0 -188
  53. package/src/package-manager.test.ts +0 -225
  54. package/src/package-manager.ts +0 -428
  55. package/src/plugin-loader.test.ts +0 -421
  56. package/src/plugin-loader.ts +0 -484
  57. package/src/qa/adapter.ts +0 -16
  58. package/src/qa/http-adapter.ts +0 -116
  59. package/src/qa/index.ts +0 -5
  60. package/src/qa/runner.ts +0 -189
  61. package/src/security/index.ts +0 -50
  62. package/src/security/permission-manager.test.ts +0 -256
  63. package/src/security/permission-manager.ts +0 -338
  64. package/src/security/plugin-config-validator.test.ts +0 -276
  65. package/src/security/plugin-config-validator.ts +0 -193
  66. package/src/security/plugin-permission-enforcer.test.ts +0 -251
  67. package/src/security/plugin-permission-enforcer.ts +0 -436
  68. package/src/security/plugin-signature-verifier.ts +0 -403
  69. package/src/security/sandbox-runtime.ts +0 -462
  70. package/src/security/security-scanner.ts +0 -367
  71. package/src/types.ts +0 -120
  72. package/src/utils/env.test.ts +0 -62
  73. package/src/utils/env.ts +0 -53
  74. package/tsconfig.json +0 -10
  75. package/vitest.config.ts +0 -10
package/src/hot-reload.ts DELETED
@@ -1,382 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { createHash } from 'node:crypto';
4
-
5
- import type {
6
- HotReloadConfig,
7
- PluginStateSnapshot
8
- } from '@objectstack/spec/kernel';
9
- import type { ObjectLogger } from './logger.js';
10
- import type { Plugin } from './types.js';
11
-
12
- // Polyfill for UUID generation to support both Node.js and Browser
13
- const generateUUID = () => {
14
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
15
- return crypto.randomUUID();
16
- }
17
- // Basic UUID v4 fallback
18
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
19
- const r = Math.random() * 16 | 0;
20
- const v = c === 'x' ? r : (r & 0x3 | 0x8);
21
- return v.toString(16);
22
- });
23
- };
24
-
25
- /**
26
- * Plugin State Manager
27
- *
28
- * Handles state persistence and restoration during hot reloads
29
- */
30
- class PluginStateManager {
31
- private logger: ObjectLogger;
32
- private stateSnapshots = new Map<string, PluginStateSnapshot>();
33
- private memoryStore = new Map<string, any>();
34
-
35
- constructor(logger: ObjectLogger) {
36
- this.logger = logger.child({ component: 'StateManager' });
37
- }
38
-
39
- /**
40
- * Save plugin state before reload
41
- */
42
- async saveState(
43
- pluginId: string,
44
- version: string,
45
- state: Record<string, any>,
46
- config: HotReloadConfig
47
- ): Promise<string> {
48
- const snapshot: PluginStateSnapshot = {
49
- pluginId,
50
- version,
51
- timestamp: new Date().toISOString(),
52
- state,
53
- metadata: {
54
- checksum: this.calculateChecksum(state),
55
- compressed: false,
56
- },
57
- };
58
-
59
- const snapshotId = generateUUID();
60
-
61
- switch (config.stateStrategy) {
62
- case 'memory':
63
- this.memoryStore.set(snapshotId, snapshot);
64
- this.logger.debug('State saved to memory', { pluginId, snapshotId });
65
- break;
66
-
67
- case 'disk':
68
- // For disk storage, we would write to file system
69
- // For now, store in memory as fallback
70
- this.memoryStore.set(snapshotId, snapshot);
71
- this.logger.debug('State saved to disk (memory fallback)', { pluginId, snapshotId });
72
- break;
73
-
74
- case 'distributed':
75
- // For distributed storage, would use Redis/etcd
76
- // For now, store in memory as fallback
77
- this.memoryStore.set(snapshotId, snapshot);
78
- this.logger.debug('State saved to distributed store (memory fallback)', {
79
- pluginId,
80
- snapshotId
81
- });
82
- break;
83
-
84
- case 'none':
85
- this.logger.debug('State persistence disabled', { pluginId });
86
- break;
87
- }
88
-
89
- this.stateSnapshots.set(pluginId, snapshot);
90
- return snapshotId;
91
- }
92
-
93
- /**
94
- * Restore plugin state after reload
95
- */
96
- async restoreState(
97
- pluginId: string,
98
- snapshotId?: string
99
- ): Promise<Record<string, any> | undefined> {
100
- // Try to get from snapshot ID first, otherwise use latest for plugin
101
- let snapshot: PluginStateSnapshot | undefined;
102
-
103
- if (snapshotId) {
104
- snapshot = this.memoryStore.get(snapshotId);
105
- } else {
106
- snapshot = this.stateSnapshots.get(pluginId);
107
- }
108
-
109
- if (!snapshot) {
110
- this.logger.warn('No state snapshot found', { pluginId, snapshotId });
111
- return undefined;
112
- }
113
-
114
- // Verify checksum if available
115
- if (snapshot.metadata?.checksum) {
116
- const currentChecksum = this.calculateChecksum(snapshot.state);
117
- if (currentChecksum !== snapshot.metadata.checksum) {
118
- this.logger.error('State checksum mismatch - data may be corrupted', {
119
- pluginId,
120
- expected: snapshot.metadata.checksum,
121
- actual: currentChecksum
122
- });
123
- return undefined;
124
- }
125
- }
126
-
127
- this.logger.debug('State restored', { pluginId, version: snapshot.version });
128
- return snapshot.state;
129
- }
130
-
131
- /**
132
- * Clear state for a plugin
133
- */
134
- clearState(pluginId: string): void {
135
- this.stateSnapshots.delete(pluginId);
136
- // Note: We don't clear memory store as it might have multiple snapshots
137
- this.logger.debug('State cleared', { pluginId });
138
- }
139
-
140
- /**
141
- * Calculate checksum for state verification using SHA-256.
142
- */
143
- private calculateChecksum(state: Record<string, any>): string {
144
- const stateStr = JSON.stringify(state);
145
- return createHash('sha256').update(stateStr).digest('hex');
146
- }
147
-
148
- /**
149
- * Shutdown state manager
150
- */
151
- shutdown(): void {
152
- this.stateSnapshots.clear();
153
- this.memoryStore.clear();
154
- this.logger.info('State manager shutdown complete');
155
- }
156
- }
157
-
158
- /**
159
- * Hot Reload Manager
160
- *
161
- * Manages hot reloading of plugins with state preservation
162
- */
163
- export class HotReloadManager {
164
- private logger: ObjectLogger;
165
- private stateManager: PluginStateManager;
166
- private reloadConfigs = new Map<string, HotReloadConfig>();
167
- private watchHandles = new Map<string, any>();
168
- private reloadTimers = new Map<string, NodeJS.Timeout>();
169
-
170
- constructor(logger: ObjectLogger) {
171
- this.logger = logger.child({ component: 'HotReload' });
172
- this.stateManager = new PluginStateManager(logger);
173
- }
174
-
175
- /**
176
- * Register a plugin for hot reload
177
- */
178
- registerPlugin(pluginName: string, config: HotReloadConfig): void {
179
- if (!config.enabled) {
180
- this.logger.debug('Hot reload disabled for plugin', { plugin: pluginName });
181
- return;
182
- }
183
-
184
- this.reloadConfigs.set(pluginName, config);
185
- this.logger.info('Plugin registered for hot reload', {
186
- plugin: pluginName,
187
- watchPatterns: config.watchPatterns,
188
- stateStrategy: config.stateStrategy
189
- });
190
- }
191
-
192
- /**
193
- * Start watching for changes (requires file system integration)
194
- */
195
- startWatching(pluginName: string): void {
196
- const config = this.reloadConfigs.get(pluginName);
197
- if (!config || !config.enabled) {
198
- return;
199
- }
200
-
201
- // Note: Actual file watching would require chokidar or similar
202
- // This is a placeholder for the integration point
203
- this.logger.info('File watching started', {
204
- plugin: pluginName,
205
- patterns: config.watchPatterns
206
- });
207
- }
208
-
209
- /**
210
- * Stop watching for changes
211
- */
212
- stopWatching(pluginName: string): void {
213
- const handle = this.watchHandles.get(pluginName);
214
- if (handle) {
215
- // Stop watching (would call chokidar close())
216
- this.watchHandles.delete(pluginName);
217
- this.logger.info('File watching stopped', { plugin: pluginName });
218
- }
219
-
220
- // Clear any pending reload timers
221
- const timer = this.reloadTimers.get(pluginName);
222
- if (timer) {
223
- clearTimeout(timer);
224
- this.reloadTimers.delete(pluginName);
225
- }
226
- }
227
-
228
- /**
229
- * Trigger hot reload for a plugin
230
- */
231
- async reloadPlugin(
232
- pluginName: string,
233
- plugin: Plugin,
234
- version: string,
235
- getPluginState: () => Record<string, any>,
236
- restorePluginState: (state: Record<string, any>) => void
237
- ): Promise<boolean> {
238
- const config = this.reloadConfigs.get(pluginName);
239
- if (!config) {
240
- this.logger.warn('Cannot reload - plugin not registered', { plugin: pluginName });
241
- return false;
242
- }
243
-
244
- this.logger.info('Starting hot reload', { plugin: pluginName });
245
-
246
- try {
247
- // Call before reload hooks
248
- if (config.beforeReload) {
249
- this.logger.debug('Executing before reload hooks', {
250
- plugin: pluginName,
251
- hooks: config.beforeReload
252
- });
253
- // Hook execution would be done through kernel's hook system
254
- }
255
-
256
- // Save state if configured
257
- let snapshotId: string | undefined;
258
- if (config.preserveState && config.stateStrategy !== 'none') {
259
- const state = getPluginState();
260
- snapshotId = await this.stateManager.saveState(
261
- pluginName,
262
- version,
263
- state,
264
- config
265
- );
266
- this.logger.debug('Plugin state saved', { plugin: pluginName, snapshotId });
267
- }
268
-
269
- // Gracefully shutdown the plugin
270
- if (plugin.destroy) {
271
- this.logger.debug('Destroying plugin', { plugin: pluginName });
272
-
273
- const shutdownPromise = plugin.destroy();
274
- const timeoutPromise = new Promise((_, reject) => {
275
- setTimeout(() => reject(new Error('Shutdown timeout')), config.shutdownTimeout);
276
- });
277
-
278
- await Promise.race([shutdownPromise, timeoutPromise]);
279
- this.logger.debug('Plugin destroyed successfully', { plugin: pluginName });
280
- }
281
-
282
- // At this point, the kernel would reload the plugin module
283
- // This would be handled by the plugin loader
284
- this.logger.debug('Plugin module would be reloaded here', { plugin: pluginName });
285
-
286
- // Restore state if we saved it
287
- if (snapshotId && config.preserveState) {
288
- const restoredState = await this.stateManager.restoreState(pluginName, snapshotId);
289
- if (restoredState) {
290
- restorePluginState(restoredState);
291
- this.logger.debug('Plugin state restored', { plugin: pluginName });
292
- }
293
- }
294
-
295
- // Call after reload hooks
296
- if (config.afterReload) {
297
- this.logger.debug('Executing after reload hooks', {
298
- plugin: pluginName,
299
- hooks: config.afterReload
300
- });
301
- // Hook execution would be done through kernel's hook system
302
- }
303
-
304
- this.logger.info('Hot reload completed successfully', { plugin: pluginName });
305
- return true;
306
- } catch (error) {
307
- this.logger.error('Hot reload failed', {
308
- plugin: pluginName,
309
- error
310
- });
311
- return false;
312
- }
313
- }
314
-
315
- /**
316
- * Schedule a reload with debouncing
317
- */
318
- scheduleReload(
319
- pluginName: string,
320
- reloadFn: () => Promise<void>
321
- ): void {
322
- const config = this.reloadConfigs.get(pluginName);
323
- if (!config) {
324
- return;
325
- }
326
-
327
- // Clear existing timer
328
- const existingTimer = this.reloadTimers.get(pluginName);
329
- if (existingTimer) {
330
- clearTimeout(existingTimer);
331
- }
332
-
333
- // Schedule new reload with debounce
334
- const timer = setTimeout(() => {
335
- this.logger.debug('Debounce period elapsed, executing reload', {
336
- plugin: pluginName
337
- });
338
- reloadFn().catch(error => {
339
- this.logger.error('Scheduled reload failed', {
340
- plugin: pluginName,
341
- error
342
- });
343
- });
344
- this.reloadTimers.delete(pluginName);
345
- }, config.debounceDelay);
346
-
347
- this.reloadTimers.set(pluginName, timer);
348
- this.logger.debug('Reload scheduled with debounce', {
349
- plugin: pluginName,
350
- delay: config.debounceDelay
351
- });
352
- }
353
-
354
- /**
355
- * Get state manager for direct access
356
- */
357
- getStateManager(): PluginStateManager {
358
- return this.stateManager;
359
- }
360
-
361
- /**
362
- * Shutdown hot reload manager
363
- */
364
- shutdown(): void {
365
- // Stop all watching
366
- for (const pluginName of this.watchHandles.keys()) {
367
- this.stopWatching(pluginName);
368
- }
369
-
370
- // Clear all timers
371
- for (const timer of this.reloadTimers.values()) {
372
- clearTimeout(timer);
373
- }
374
-
375
- this.reloadConfigs.clear();
376
- this.watchHandles.clear();
377
- this.reloadTimers.clear();
378
- this.stateManager.shutdown();
379
-
380
- this.logger.info('Hot reload manager shutdown complete');
381
- }
382
- }
package/src/index.ts DELETED
@@ -1,50 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * @objectstack/core
5
- *
6
- * Core runtime for ObjectStack microkernel architecture.
7
- * Provides plugin system, dependency injection, and lifecycle management.
8
- */
9
-
10
- export * from './kernel-base.js';
11
- export * from './kernel.js';
12
- export * from './lite-kernel.js';
13
- export * from './types.js';
14
- export * from './logger.js';
15
- export * from './plugin-loader.js';
16
- export * from './api-registry.js';
17
- export * from './api-registry-plugin.js';
18
- export * as QA from './qa/index.js';
19
-
20
- // Export security utilities
21
- export * from './security/index.js';
22
-
23
- // Export environment utilities
24
- export * from './utils/env.js';
25
-
26
- // Export in-memory fallbacks for core-criticality services
27
- export * from './fallbacks/index.js';
28
-
29
- // Export Phase 2 components - Advanced lifecycle management
30
- export * from './health-monitor.js';
31
- export * from './hot-reload.js';
32
- export * from './dependency-resolver.js';
33
-
34
- // Export Phase 3 components - Package lifecycle management
35
- export * from './namespace-resolver.js';
36
- export * from './package-manager.js';
37
-
38
- // Re-export contracts from @objectstack/spec for backward compatibility
39
- export type {
40
- Logger,
41
- IHttpServer,
42
- IHttpRequest,
43
- IHttpResponse,
44
- RouteHandler,
45
- Middleware,
46
- IDataEngine,
47
- IDataDriver,
48
- /** @deprecated Use `IDataDriver` instead */
49
- DriverInterface
50
- } from '@objectstack/spec/contracts';
@@ -1,273 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { Plugin, PluginContext } from './types.js';
4
- import type { Logger } from '@objectstack/spec/contracts';
5
- import type { IServiceRegistry } from '@objectstack/spec/contracts';
6
-
7
- /**
8
- * Kernel state machine
9
- */
10
- export type KernelState = 'idle' | 'initializing' | 'running' | 'stopping' | 'stopped';
11
-
12
- /**
13
- * ObjectKernelBase - Abstract Base Class for Microkernel
14
- *
15
- * Provides common functionality for ObjectKernel and LiteKernel:
16
- * - Plugin management (Map storage)
17
- * - Dependency resolution (topological sort)
18
- * - Hook/Event system
19
- * - Context creation
20
- * - State validation
21
- *
22
- * This eliminates code duplication between the implementations.
23
- */
24
- export abstract class ObjectKernelBase {
25
- protected plugins: Map<string, Plugin> = new Map();
26
- protected services: IServiceRegistry | Map<string, any> = new Map();
27
- protected hooks: Map<string, Array<(...args: any[]) => void | Promise<void>>> = new Map();
28
- protected state: KernelState = 'idle';
29
- protected logger: Logger;
30
- protected context!: PluginContext;
31
-
32
- constructor(logger: Logger) {
33
- this.logger = logger;
34
- }
35
-
36
- /**
37
- * Validate kernel state
38
- * @param requiredState - Required state for the operation
39
- * @throws Error if current state doesn't match
40
- */
41
- protected validateState(requiredState: KernelState): void {
42
- if (this.state !== requiredState) {
43
- throw new Error(
44
- `[Kernel] Invalid state: expected '${requiredState}', got '${this.state}'`
45
- );
46
- }
47
- }
48
-
49
- /**
50
- * Validate kernel is in idle state (for plugin registration)
51
- */
52
- protected validateIdle(): void {
53
- if (this.state !== 'idle') {
54
- throw new Error('[Kernel] Cannot register plugins after bootstrap has started');
55
- }
56
- }
57
-
58
- /**
59
- * Create the plugin context
60
- * Subclasses can override to customize context creation
61
- */
62
- protected createContext(): PluginContext {
63
- return {
64
- registerService: (name, service) => {
65
- if (this.services instanceof Map) {
66
- if (this.services.has(name)) {
67
- throw new Error(`[Kernel] Service '${name}' already registered`);
68
- }
69
- this.services.set(name, service);
70
- } else {
71
- // IServiceRegistry implementation
72
- this.services.register(name, service);
73
- }
74
- this.logger.info(`Service '${name}' registered`, { service: name });
75
- },
76
- getService: <T>(name: string): T => {
77
- if (this.services instanceof Map) {
78
- const service = this.services.get(name);
79
- if (!service) {
80
- throw new Error(`[Kernel] Service '${name}' not found`);
81
- }
82
- return service as T;
83
- } else {
84
- // IServiceRegistry implementation
85
- return this.services.get<T>(name);
86
- }
87
- },
88
- replaceService: <T>(name: string, implementation: T): void => {
89
- if (this.services instanceof Map) {
90
- if (!this.services.has(name)) {
91
- throw new Error(`[Kernel] Service '${name}' not found. Use registerService() to add new services.`);
92
- }
93
- this.services.set(name, implementation);
94
- } else {
95
- // IServiceRegistry implementation
96
- if (!this.services.has(name)) {
97
- throw new Error(`[Kernel] Service '${name}' not found. Use registerService() to add new services.`);
98
- }
99
- this.services.register(name, implementation);
100
- }
101
- this.logger.info(`Service '${name}' replaced`, { service: name });
102
- },
103
- hook: (name, handler) => {
104
- if (!this.hooks.has(name)) {
105
- this.hooks.set(name, []);
106
- }
107
- this.hooks.get(name)!.push(handler);
108
- },
109
- trigger: async (name, ...args) => {
110
- const handlers = this.hooks.get(name) || [];
111
- for (const handler of handlers) {
112
- await handler(...args);
113
- }
114
- },
115
- getServices: () => {
116
- if (this.services instanceof Map) {
117
- return new Map(this.services);
118
- } else {
119
- // For IServiceRegistry, we need to return the underlying Map
120
- // This is a compatibility method
121
- return new Map();
122
- }
123
- },
124
- logger: this.logger,
125
- getKernel: () => this as any,
126
- };
127
- }
128
-
129
- /**
130
- * Resolve plugin dependencies using topological sort
131
- * @returns Ordered list of plugins (dependencies first)
132
- */
133
- protected resolveDependencies(): Plugin[] {
134
- const resolved: Plugin[] = [];
135
- const visited = new Set<string>();
136
- const visiting = new Set<string>();
137
-
138
- const visit = (pluginName: string) => {
139
- if (visited.has(pluginName)) return;
140
-
141
- if (visiting.has(pluginName)) {
142
- throw new Error(`[Kernel] Circular dependency detected: ${pluginName}`);
143
- }
144
-
145
- const plugin = this.plugins.get(pluginName);
146
- if (!plugin) {
147
- throw new Error(`[Kernel] Plugin '${pluginName}' not found`);
148
- }
149
-
150
- visiting.add(pluginName);
151
-
152
- // Visit dependencies first
153
- const deps = plugin.dependencies || [];
154
- for (const dep of deps) {
155
- if (!this.plugins.has(dep)) {
156
- throw new Error(
157
- `[Kernel] Dependency '${dep}' not found for plugin '${pluginName}'`
158
- );
159
- }
160
- visit(dep);
161
- }
162
-
163
- visiting.delete(pluginName);
164
- visited.add(pluginName);
165
- resolved.push(plugin);
166
- };
167
-
168
- // Visit all plugins
169
- for (const pluginName of this.plugins.keys()) {
170
- visit(pluginName);
171
- }
172
-
173
- return resolved;
174
- }
175
-
176
- /**
177
- * Run plugin init phase
178
- * @param plugin - Plugin to initialize
179
- */
180
- protected async runPluginInit(plugin: Plugin): Promise<void> {
181
- const pluginName = plugin.name;
182
- this.logger.info(`Initializing plugin: ${pluginName}`);
183
-
184
- try {
185
- await plugin.init(this.context);
186
- this.logger.info(`Plugin initialized: ${pluginName}`);
187
- } catch (error) {
188
- this.logger.error(`Plugin init failed: ${pluginName}`, error as Error);
189
- throw error;
190
- }
191
- }
192
-
193
- /**
194
- * Run plugin start phase
195
- * @param plugin - Plugin to start
196
- */
197
- protected async runPluginStart(plugin: Plugin): Promise<void> {
198
- if (!plugin.start) return;
199
-
200
- const pluginName = plugin.name;
201
- this.logger.info(`Starting plugin: ${pluginName}`);
202
-
203
- try {
204
- await plugin.start(this.context);
205
- this.logger.info(`Plugin started: ${pluginName}`);
206
- } catch (error) {
207
- this.logger.error(`Plugin start failed: ${pluginName}`, error as Error);
208
- throw error;
209
- }
210
- }
211
-
212
- /**
213
- * Run plugin destroy phase
214
- * @param plugin - Plugin to destroy
215
- */
216
- protected async runPluginDestroy(plugin: Plugin): Promise<void> {
217
- if (!plugin.destroy) return;
218
-
219
- const pluginName = plugin.name;
220
- this.logger.info(`Destroying plugin: ${pluginName}`);
221
-
222
- try {
223
- await plugin.destroy();
224
- this.logger.info(`Plugin destroyed: ${pluginName}`);
225
- } catch (error) {
226
- this.logger.error(`Plugin destroy failed: ${pluginName}`, error as Error);
227
- throw error;
228
- }
229
- }
230
-
231
- /**
232
- * Trigger a hook with all registered handlers
233
- * @param name - Hook name
234
- * @param args - Arguments to pass to handlers
235
- */
236
- protected async triggerHook(name: string, ...args: any[]): Promise<void> {
237
- const handlers = this.hooks.get(name) || [];
238
- this.logger.debug(`Triggering hook: ${name}`, {
239
- hook: name,
240
- handlerCount: handlers.length
241
- });
242
-
243
- for (const handler of handlers) {
244
- try {
245
- await handler(...args);
246
- } catch (error) {
247
- this.logger.error(`Hook handler failed: ${name}`, error as Error);
248
- // Continue with other handlers even if one fails
249
- }
250
- }
251
- }
252
-
253
- /**
254
- * Get current kernel state
255
- */
256
- getState(): KernelState {
257
- return this.state;
258
- }
259
-
260
- /**
261
- * Get all registered plugins
262
- */
263
- getPlugins(): Map<string, Plugin> {
264
- return new Map(this.plugins);
265
- }
266
-
267
- /**
268
- * Abstract methods to be implemented by subclasses
269
- */
270
- abstract use(plugin: Plugin): this | Promise<this>;
271
- abstract bootstrap(): Promise<void>;
272
- abstract destroy(): Promise<void>;
273
- }