-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlite-kernel.ts
More file actions
144 lines (122 loc) · 4.53 KB
/
Copy pathlite-kernel.ts
File metadata and controls
144 lines (122 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { Plugin } from './types.js';
import { createLogger, ObjectLogger } from './logger.js';
import type { LoggerConfig } from '@objectstack/spec/system';
import { ObjectKernelBase } from './kernel-base.js';
/**
* ObjectKernel - MiniKernel Architecture
*
* A highly modular, plugin-based microkernel that:
* - Manages plugin lifecycle (init, start, destroy)
* - Provides dependency injection via service registry
* - Implements event/hook system for inter-plugin communication
* - Handles dependency resolution (topological sort)
* - Provides configurable logging for server and browser
*
* Core philosophy:
* - Business logic is completely separated into plugins
* - Kernel only manages lifecycle, DI, and hooks
* - Plugins are loaded as equal building blocks
*/
export class LiteKernel extends ObjectKernelBase {
constructor(config?: { logger?: Partial<LoggerConfig> }) {
const logger = createLogger(config?.logger);
super(logger);
// Initialize context after logger is created
this.context = this.createContext();
}
/**
* Register a plugin
* @param plugin - Plugin instance
*/
use(plugin: Plugin): this {
this.validateIdle();
const pluginName = plugin.name;
if (this.plugins.has(pluginName)) {
throw new Error(`[Kernel] Plugin '${pluginName}' already registered`);
}
this.plugins.set(pluginName, plugin);
return this;
}
/**
* Bootstrap the kernel
* 1. Resolve dependencies (topological sort)
* 2. Init phase - plugins register services
* 3. Start phase - plugins execute business logic
* 4. Trigger 'kernel:ready' hook
*/
async bootstrap(): Promise<void> {
this.validateState('idle');
this.state = 'initializing';
this.logger.info('Bootstrap started');
// Resolve dependencies
const orderedPlugins = this.resolveDependencies();
// Phase 1: Init - Plugins register services
this.logger.info('Phase 1: Init plugins');
for (const plugin of orderedPlugins) {
await this.runPluginInit(plugin);
}
// Phase 2: Start - Plugins execute business logic
this.logger.info('Phase 2: Start plugins');
this.state = 'running';
for (const plugin of orderedPlugins) {
await this.runPluginStart(plugin);
}
// Trigger ready hook (route/middleware registration phase)
await this.triggerHook('kernel:ready');
// Trigger bootstrapped hook — "all bootstrap + seed data is ready"
// anchor, strictly after every kernel:ready handler has settled and
// before any HTTP socket opens (see plugin-lifecycle-events.ts).
await this.triggerHook('kernel:bootstrapped');
// Trigger listening hook (HTTP servers open their socket here —
// strictly after every kernel:ready handler has completed).
await this.triggerHook('kernel:listening');
this.logger.info('✅ Bootstrap complete', {
pluginCount: this.plugins.size
});
}
/**
* Shutdown the kernel
* Calls destroy on all plugins in reverse order
*/
async shutdown(): Promise<void> {
await this.destroy();
}
/**
* Graceful shutdown - destroy all plugins in reverse order
*/
async destroy(): Promise<void> {
if (this.state === 'stopped') {
this.logger.warn('Kernel already stopped');
return;
}
this.state = 'stopping';
this.logger.info('Shutdown started');
// Trigger shutdown hook
await this.triggerHook('kernel:shutdown');
// Destroy plugins in reverse order
const orderedPlugins = this.resolveDependencies();
for (const plugin of orderedPlugins.reverse()) {
await this.runPluginDestroy(plugin);
}
this.state = 'stopped';
this.logger.info('✅ Shutdown complete');
// Cleanup logger resources
if (this.logger && typeof (this.logger as ObjectLogger).destroy === 'function') {
await (this.logger as ObjectLogger).destroy();
}
}
/**
* Get a service from the registry
* Convenience method for external access
*/
getService<T>(name: string): T {
return this.context.getService<T>(name);
}
/**
* Check if kernel is running
*/
isRunning(): boolean {
return this.state === 'running';
}
}