@objectstack/core 0.9.1 → 0.9.2
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/{ENHANCED_FEATURES.md → ADVANCED_FEATURES.md} +13 -13
- package/CHANGELOG.md +7 -0
- package/PHASE2_IMPLEMENTATION.md +388 -0
- package/README.md +24 -11
- package/REFACTORING_SUMMARY.md +40 -0
- package/dist/api-registry-plugin.test.js +20 -20
- package/dist/dependency-resolver.d.ts +62 -0
- package/dist/dependency-resolver.d.ts.map +1 -0
- package/dist/dependency-resolver.js +317 -0
- package/dist/dependency-resolver.test.d.ts +2 -0
- package/dist/dependency-resolver.test.d.ts.map +1 -0
- package/dist/dependency-resolver.test.js +241 -0
- package/dist/health-monitor.d.ts +65 -0
- package/dist/health-monitor.d.ts.map +1 -0
- package/dist/health-monitor.js +269 -0
- package/dist/health-monitor.test.d.ts +2 -0
- package/dist/health-monitor.test.d.ts.map +1 -0
- package/dist/health-monitor.test.js +68 -0
- package/dist/hot-reload.d.ts +79 -0
- package/dist/hot-reload.d.ts.map +1 -0
- package/dist/hot-reload.js +313 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/kernel-base.d.ts +2 -2
- package/dist/kernel-base.js +2 -2
- package/dist/kernel.d.ts +79 -31
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +383 -73
- package/dist/kernel.test.js +373 -122
- package/dist/lite-kernel.d.ts +55 -0
- package/dist/lite-kernel.d.ts.map +1 -0
- package/dist/lite-kernel.js +112 -0
- package/dist/lite-kernel.test.d.ts +2 -0
- package/dist/lite-kernel.test.d.ts.map +1 -0
- package/dist/lite-kernel.test.js +161 -0
- package/dist/logger.d.ts +2 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +26 -7
- package/dist/plugin-loader.d.ts +11 -0
- package/dist/plugin-loader.d.ts.map +1 -1
- package/dist/plugin-loader.js +34 -10
- package/dist/plugin-loader.test.js +9 -0
- package/dist/security/index.d.ts +3 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +4 -0
- package/dist/security/permission-manager.d.ts +96 -0
- package/dist/security/permission-manager.d.ts.map +1 -0
- package/dist/security/permission-manager.js +235 -0
- package/dist/security/permission-manager.test.d.ts +2 -0
- package/dist/security/permission-manager.test.d.ts.map +1 -0
- package/dist/security/permission-manager.test.js +220 -0
- package/dist/security/sandbox-runtime.d.ts +115 -0
- package/dist/security/sandbox-runtime.d.ts.map +1 -0
- package/dist/security/sandbox-runtime.js +310 -0
- package/dist/security/security-scanner.d.ts +92 -0
- package/dist/security/security-scanner.d.ts.map +1 -0
- package/dist/security/security-scanner.js +273 -0
- package/examples/{enhanced-kernel-example.ts → kernel-features-example.ts} +6 -6
- package/examples/phase2-integration.ts +355 -0
- package/package.json +2 -2
- package/src/api-registry-plugin.test.ts +20 -20
- package/src/dependency-resolver.test.ts +287 -0
- package/src/dependency-resolver.ts +388 -0
- package/src/health-monitor.test.ts +81 -0
- package/src/health-monitor.ts +316 -0
- package/src/hot-reload.ts +388 -0
- package/src/index.ts +6 -1
- package/src/kernel-base.ts +2 -2
- package/src/kernel.test.ts +469 -134
- package/src/kernel.ts +464 -78
- package/src/lite-kernel.test.ts +200 -0
- package/src/lite-kernel.ts +135 -0
- package/src/logger.ts +28 -7
- package/src/plugin-loader.test.ts +10 -1
- package/src/plugin-loader.ts +42 -13
- package/src/security/index.ts +19 -0
- package/src/security/permission-manager.test.ts +256 -0
- package/src/security/permission-manager.ts +336 -0
- package/src/security/sandbox-runtime.ts +432 -0
- package/src/security/security-scanner.ts +365 -0
- package/dist/enhanced-kernel.d.ts +0 -103
- package/dist/enhanced-kernel.d.ts.map +0 -1
- package/dist/enhanced-kernel.js +0 -403
- package/dist/enhanced-kernel.test.d.ts +0 -2
- package/dist/enhanced-kernel.test.d.ts.map +0 -1
- package/dist/enhanced-kernel.test.js +0 -412
- package/src/enhanced-kernel.test.ts +0 -535
- package/src/enhanced-kernel.ts +0 -496
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HotReloadConfig,
|
|
3
|
+
PluginStateSnapshot
|
|
4
|
+
} from '@objectstack/spec/system';
|
|
5
|
+
import type { ObjectLogger } from './logger.js';
|
|
6
|
+
import type { Plugin } from './types.js';
|
|
7
|
+
|
|
8
|
+
// Polyfill for UUID generation to support both Node.js and Browser
|
|
9
|
+
const generateUUID = () => {
|
|
10
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
11
|
+
return crypto.randomUUID();
|
|
12
|
+
}
|
|
13
|
+
// Basic UUID v4 fallback
|
|
14
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
15
|
+
const r = Math.random() * 16 | 0;
|
|
16
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
17
|
+
return v.toString(16);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Plugin State Manager
|
|
23
|
+
*
|
|
24
|
+
* Handles state persistence and restoration during hot reloads
|
|
25
|
+
*/
|
|
26
|
+
class PluginStateManager {
|
|
27
|
+
private logger: ObjectLogger;
|
|
28
|
+
private stateSnapshots = new Map<string, PluginStateSnapshot>();
|
|
29
|
+
private memoryStore = new Map<string, any>();
|
|
30
|
+
|
|
31
|
+
constructor(logger: ObjectLogger) {
|
|
32
|
+
this.logger = logger.child({ component: 'StateManager' });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Save plugin state before reload
|
|
37
|
+
*/
|
|
38
|
+
async saveState(
|
|
39
|
+
pluginId: string,
|
|
40
|
+
version: string,
|
|
41
|
+
state: Record<string, any>,
|
|
42
|
+
config: HotReloadConfig
|
|
43
|
+
): Promise<string> {
|
|
44
|
+
const snapshot: PluginStateSnapshot = {
|
|
45
|
+
pluginId,
|
|
46
|
+
version,
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
state,
|
|
49
|
+
metadata: {
|
|
50
|
+
checksum: this.calculateChecksum(state),
|
|
51
|
+
compressed: false,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const snapshotId = generateUUID();
|
|
56
|
+
|
|
57
|
+
switch (config.stateStrategy) {
|
|
58
|
+
case 'memory':
|
|
59
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
60
|
+
this.logger.debug('State saved to memory', { pluginId, snapshotId });
|
|
61
|
+
break;
|
|
62
|
+
|
|
63
|
+
case 'disk':
|
|
64
|
+
// For disk storage, we would write to file system
|
|
65
|
+
// For now, store in memory as fallback
|
|
66
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
67
|
+
this.logger.debug('State saved to disk (memory fallback)', { pluginId, snapshotId });
|
|
68
|
+
break;
|
|
69
|
+
|
|
70
|
+
case 'distributed':
|
|
71
|
+
// For distributed storage, would use Redis/etcd
|
|
72
|
+
// For now, store in memory as fallback
|
|
73
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
74
|
+
this.logger.debug('State saved to distributed store (memory fallback)', {
|
|
75
|
+
pluginId,
|
|
76
|
+
snapshotId
|
|
77
|
+
});
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
case 'none':
|
|
81
|
+
this.logger.debug('State persistence disabled', { pluginId });
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.stateSnapshots.set(pluginId, snapshot);
|
|
86
|
+
return snapshotId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Restore plugin state after reload
|
|
91
|
+
*/
|
|
92
|
+
async restoreState(
|
|
93
|
+
pluginId: string,
|
|
94
|
+
snapshotId?: string
|
|
95
|
+
): Promise<Record<string, any> | undefined> {
|
|
96
|
+
// Try to get from snapshot ID first, otherwise use latest for plugin
|
|
97
|
+
let snapshot: PluginStateSnapshot | undefined;
|
|
98
|
+
|
|
99
|
+
if (snapshotId) {
|
|
100
|
+
snapshot = this.memoryStore.get(snapshotId);
|
|
101
|
+
} else {
|
|
102
|
+
snapshot = this.stateSnapshots.get(pluginId);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!snapshot) {
|
|
106
|
+
this.logger.warn('No state snapshot found', { pluginId, snapshotId });
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Verify checksum if available
|
|
111
|
+
if (snapshot.metadata?.checksum) {
|
|
112
|
+
const currentChecksum = this.calculateChecksum(snapshot.state);
|
|
113
|
+
if (currentChecksum !== snapshot.metadata.checksum) {
|
|
114
|
+
this.logger.error('State checksum mismatch - data may be corrupted', {
|
|
115
|
+
pluginId,
|
|
116
|
+
expected: snapshot.metadata.checksum,
|
|
117
|
+
actual: currentChecksum
|
|
118
|
+
});
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.logger.debug('State restored', { pluginId, version: snapshot.version });
|
|
124
|
+
return snapshot.state;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Clear state for a plugin
|
|
129
|
+
*/
|
|
130
|
+
clearState(pluginId: string): void {
|
|
131
|
+
this.stateSnapshots.delete(pluginId);
|
|
132
|
+
// Note: We don't clear memory store as it might have multiple snapshots
|
|
133
|
+
this.logger.debug('State cleared', { pluginId });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Calculate simple checksum for state verification
|
|
138
|
+
* WARNING: This is a simple hash for demo purposes.
|
|
139
|
+
* In production, use a cryptographic hash like SHA-256.
|
|
140
|
+
*/
|
|
141
|
+
private calculateChecksum(state: Record<string, any>): string {
|
|
142
|
+
// Simple checksum using JSON serialization
|
|
143
|
+
// TODO: Replace with crypto.createHash('sha256') for production
|
|
144
|
+
const stateStr = JSON.stringify(state);
|
|
145
|
+
let hash = 0;
|
|
146
|
+
for (let i = 0; i < stateStr.length; i++) {
|
|
147
|
+
const char = stateStr.charCodeAt(i);
|
|
148
|
+
hash = ((hash << 5) - hash) + char;
|
|
149
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
150
|
+
}
|
|
151
|
+
return hash.toString(16);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Shutdown state manager
|
|
156
|
+
*/
|
|
157
|
+
shutdown(): void {
|
|
158
|
+
this.stateSnapshots.clear();
|
|
159
|
+
this.memoryStore.clear();
|
|
160
|
+
this.logger.info('State manager shutdown complete');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Hot Reload Manager
|
|
166
|
+
*
|
|
167
|
+
* Manages hot reloading of plugins with state preservation
|
|
168
|
+
*/
|
|
169
|
+
export class HotReloadManager {
|
|
170
|
+
private logger: ObjectLogger;
|
|
171
|
+
private stateManager: PluginStateManager;
|
|
172
|
+
private reloadConfigs = new Map<string, HotReloadConfig>();
|
|
173
|
+
private watchHandles = new Map<string, any>();
|
|
174
|
+
private reloadTimers = new Map<string, NodeJS.Timeout>();
|
|
175
|
+
|
|
176
|
+
constructor(logger: ObjectLogger) {
|
|
177
|
+
this.logger = logger.child({ component: 'HotReload' });
|
|
178
|
+
this.stateManager = new PluginStateManager(logger);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Register a plugin for hot reload
|
|
183
|
+
*/
|
|
184
|
+
registerPlugin(pluginName: string, config: HotReloadConfig): void {
|
|
185
|
+
if (!config.enabled) {
|
|
186
|
+
this.logger.debug('Hot reload disabled for plugin', { plugin: pluginName });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
this.reloadConfigs.set(pluginName, config);
|
|
191
|
+
this.logger.info('Plugin registered for hot reload', {
|
|
192
|
+
plugin: pluginName,
|
|
193
|
+
watchPatterns: config.watchPatterns,
|
|
194
|
+
stateStrategy: config.stateStrategy
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Start watching for changes (requires file system integration)
|
|
200
|
+
*/
|
|
201
|
+
startWatching(pluginName: string): void {
|
|
202
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
203
|
+
if (!config || !config.enabled) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Note: Actual file watching would require chokidar or similar
|
|
208
|
+
// This is a placeholder for the integration point
|
|
209
|
+
this.logger.info('File watching started', {
|
|
210
|
+
plugin: pluginName,
|
|
211
|
+
patterns: config.watchPatterns
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Stop watching for changes
|
|
217
|
+
*/
|
|
218
|
+
stopWatching(pluginName: string): void {
|
|
219
|
+
const handle = this.watchHandles.get(pluginName);
|
|
220
|
+
if (handle) {
|
|
221
|
+
// Stop watching (would call chokidar close())
|
|
222
|
+
this.watchHandles.delete(pluginName);
|
|
223
|
+
this.logger.info('File watching stopped', { plugin: pluginName });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Clear any pending reload timers
|
|
227
|
+
const timer = this.reloadTimers.get(pluginName);
|
|
228
|
+
if (timer) {
|
|
229
|
+
clearTimeout(timer);
|
|
230
|
+
this.reloadTimers.delete(pluginName);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Trigger hot reload for a plugin
|
|
236
|
+
*/
|
|
237
|
+
async reloadPlugin(
|
|
238
|
+
pluginName: string,
|
|
239
|
+
plugin: Plugin,
|
|
240
|
+
version: string,
|
|
241
|
+
getPluginState: () => Record<string, any>,
|
|
242
|
+
restorePluginState: (state: Record<string, any>) => void
|
|
243
|
+
): Promise<boolean> {
|
|
244
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
245
|
+
if (!config) {
|
|
246
|
+
this.logger.warn('Cannot reload - plugin not registered', { plugin: pluginName });
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.logger.info('Starting hot reload', { plugin: pluginName });
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
// Call before reload hooks
|
|
254
|
+
if (config.beforeReload) {
|
|
255
|
+
this.logger.debug('Executing before reload hooks', {
|
|
256
|
+
plugin: pluginName,
|
|
257
|
+
hooks: config.beforeReload
|
|
258
|
+
});
|
|
259
|
+
// Hook execution would be done through kernel's hook system
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Save state if configured
|
|
263
|
+
let snapshotId: string | undefined;
|
|
264
|
+
if (config.preserveState && config.stateStrategy !== 'none') {
|
|
265
|
+
const state = getPluginState();
|
|
266
|
+
snapshotId = await this.stateManager.saveState(
|
|
267
|
+
pluginName,
|
|
268
|
+
version,
|
|
269
|
+
state,
|
|
270
|
+
config
|
|
271
|
+
);
|
|
272
|
+
this.logger.debug('Plugin state saved', { plugin: pluginName, snapshotId });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Gracefully shutdown the plugin
|
|
276
|
+
if (plugin.destroy) {
|
|
277
|
+
this.logger.debug('Destroying plugin', { plugin: pluginName });
|
|
278
|
+
|
|
279
|
+
const shutdownPromise = plugin.destroy();
|
|
280
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
281
|
+
setTimeout(() => reject(new Error('Shutdown timeout')), config.shutdownTimeout);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await Promise.race([shutdownPromise, timeoutPromise]);
|
|
285
|
+
this.logger.debug('Plugin destroyed successfully', { plugin: pluginName });
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// At this point, the kernel would reload the plugin module
|
|
289
|
+
// This would be handled by the plugin loader
|
|
290
|
+
this.logger.debug('Plugin module would be reloaded here', { plugin: pluginName });
|
|
291
|
+
|
|
292
|
+
// Restore state if we saved it
|
|
293
|
+
if (snapshotId && config.preserveState) {
|
|
294
|
+
const restoredState = await this.stateManager.restoreState(pluginName, snapshotId);
|
|
295
|
+
if (restoredState) {
|
|
296
|
+
restorePluginState(restoredState);
|
|
297
|
+
this.logger.debug('Plugin state restored', { plugin: pluginName });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Call after reload hooks
|
|
302
|
+
if (config.afterReload) {
|
|
303
|
+
this.logger.debug('Executing after reload hooks', {
|
|
304
|
+
plugin: pluginName,
|
|
305
|
+
hooks: config.afterReload
|
|
306
|
+
});
|
|
307
|
+
// Hook execution would be done through kernel's hook system
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.logger.info('Hot reload completed successfully', { plugin: pluginName });
|
|
311
|
+
return true;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
this.logger.error('Hot reload failed', {
|
|
314
|
+
plugin: pluginName,
|
|
315
|
+
error
|
|
316
|
+
});
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Schedule a reload with debouncing
|
|
323
|
+
*/
|
|
324
|
+
scheduleReload(
|
|
325
|
+
pluginName: string,
|
|
326
|
+
reloadFn: () => Promise<void>
|
|
327
|
+
): void {
|
|
328
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
329
|
+
if (!config) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Clear existing timer
|
|
334
|
+
const existingTimer = this.reloadTimers.get(pluginName);
|
|
335
|
+
if (existingTimer) {
|
|
336
|
+
clearTimeout(existingTimer);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Schedule new reload with debounce
|
|
340
|
+
const timer = setTimeout(() => {
|
|
341
|
+
this.logger.debug('Debounce period elapsed, executing reload', {
|
|
342
|
+
plugin: pluginName
|
|
343
|
+
});
|
|
344
|
+
reloadFn().catch(error => {
|
|
345
|
+
this.logger.error('Scheduled reload failed', {
|
|
346
|
+
plugin: pluginName,
|
|
347
|
+
error
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
this.reloadTimers.delete(pluginName);
|
|
351
|
+
}, config.debounceDelay);
|
|
352
|
+
|
|
353
|
+
this.reloadTimers.set(pluginName, timer);
|
|
354
|
+
this.logger.debug('Reload scheduled with debounce', {
|
|
355
|
+
plugin: pluginName,
|
|
356
|
+
delay: config.debounceDelay
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get state manager for direct access
|
|
362
|
+
*/
|
|
363
|
+
getStateManager(): PluginStateManager {
|
|
364
|
+
return this.stateManager;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Shutdown hot reload manager
|
|
369
|
+
*/
|
|
370
|
+
shutdown(): void {
|
|
371
|
+
// Stop all watching
|
|
372
|
+
for (const pluginName of this.watchHandles.keys()) {
|
|
373
|
+
this.stopWatching(pluginName);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Clear all timers
|
|
377
|
+
for (const timer of this.reloadTimers.values()) {
|
|
378
|
+
clearTimeout(timer);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
this.reloadConfigs.clear();
|
|
382
|
+
this.watchHandles.clear();
|
|
383
|
+
this.reloadTimers.clear();
|
|
384
|
+
this.stateManager.shutdown();
|
|
385
|
+
|
|
386
|
+
this.logger.info('Hot reload manager shutdown complete');
|
|
387
|
+
}
|
|
388
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
export * from './kernel-base.js';
|
|
9
9
|
export * from './kernel.js';
|
|
10
|
+
export * from './lite-kernel.js';
|
|
10
11
|
export * from './types.js';
|
|
11
12
|
export * from './logger.js';
|
|
12
13
|
export * from './plugin-loader.js';
|
|
13
|
-
export * from './enhanced-kernel.js';
|
|
14
14
|
export * from './api-registry.js';
|
|
15
15
|
export * from './api-registry-plugin.js';
|
|
16
16
|
export * as QA from './qa/index.js';
|
|
@@ -18,6 +18,11 @@ export * as QA from './qa/index.js';
|
|
|
18
18
|
// Export security utilities
|
|
19
19
|
export * from './security/index.js';
|
|
20
20
|
|
|
21
|
+
// Export Phase 2 components - Advanced lifecycle management
|
|
22
|
+
export * from './health-monitor.js';
|
|
23
|
+
export * from './hot-reload.js';
|
|
24
|
+
export * from './dependency-resolver.js';
|
|
25
|
+
|
|
21
26
|
// Re-export contracts from @objectstack/spec for backward compatibility
|
|
22
27
|
export type {
|
|
23
28
|
Logger,
|
package/src/kernel-base.ts
CHANGED
|
@@ -10,14 +10,14 @@ export type KernelState = 'idle' | 'initializing' | 'running' | 'stopping' | 'st
|
|
|
10
10
|
/**
|
|
11
11
|
* ObjectKernelBase - Abstract Base Class for Microkernel
|
|
12
12
|
*
|
|
13
|
-
* Provides common functionality for
|
|
13
|
+
* Provides common functionality for ObjectKernel and LiteKernel:
|
|
14
14
|
* - Plugin management (Map storage)
|
|
15
15
|
* - Dependency resolution (topological sort)
|
|
16
16
|
* - Hook/Event system
|
|
17
17
|
* - Context creation
|
|
18
18
|
* - State validation
|
|
19
19
|
*
|
|
20
|
-
* This eliminates
|
|
20
|
+
* This eliminates code duplication between the implementations.
|
|
21
21
|
*/
|
|
22
22
|
export abstract class ObjectKernelBase {
|
|
23
23
|
protected plugins: Map<string, Plugin> = new Map();
|