@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,79 @@
|
|
|
1
|
+
import type { HotReloadConfig } from '@objectstack/spec/system';
|
|
2
|
+
import type { ObjectLogger } from './logger.js';
|
|
3
|
+
import type { Plugin } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Plugin State Manager
|
|
6
|
+
*
|
|
7
|
+
* Handles state persistence and restoration during hot reloads
|
|
8
|
+
*/
|
|
9
|
+
declare class PluginStateManager {
|
|
10
|
+
private logger;
|
|
11
|
+
private stateSnapshots;
|
|
12
|
+
private memoryStore;
|
|
13
|
+
constructor(logger: ObjectLogger);
|
|
14
|
+
/**
|
|
15
|
+
* Save plugin state before reload
|
|
16
|
+
*/
|
|
17
|
+
saveState(pluginId: string, version: string, state: Record<string, any>, config: HotReloadConfig): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Restore plugin state after reload
|
|
20
|
+
*/
|
|
21
|
+
restoreState(pluginId: string, snapshotId?: string): Promise<Record<string, any> | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Clear state for a plugin
|
|
24
|
+
*/
|
|
25
|
+
clearState(pluginId: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* Calculate simple checksum for state verification
|
|
28
|
+
* WARNING: This is a simple hash for demo purposes.
|
|
29
|
+
* In production, use a cryptographic hash like SHA-256.
|
|
30
|
+
*/
|
|
31
|
+
private calculateChecksum;
|
|
32
|
+
/**
|
|
33
|
+
* Shutdown state manager
|
|
34
|
+
*/
|
|
35
|
+
shutdown(): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Hot Reload Manager
|
|
39
|
+
*
|
|
40
|
+
* Manages hot reloading of plugins with state preservation
|
|
41
|
+
*/
|
|
42
|
+
export declare class HotReloadManager {
|
|
43
|
+
private logger;
|
|
44
|
+
private stateManager;
|
|
45
|
+
private reloadConfigs;
|
|
46
|
+
private watchHandles;
|
|
47
|
+
private reloadTimers;
|
|
48
|
+
constructor(logger: ObjectLogger);
|
|
49
|
+
/**
|
|
50
|
+
* Register a plugin for hot reload
|
|
51
|
+
*/
|
|
52
|
+
registerPlugin(pluginName: string, config: HotReloadConfig): void;
|
|
53
|
+
/**
|
|
54
|
+
* Start watching for changes (requires file system integration)
|
|
55
|
+
*/
|
|
56
|
+
startWatching(pluginName: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Stop watching for changes
|
|
59
|
+
*/
|
|
60
|
+
stopWatching(pluginName: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Trigger hot reload for a plugin
|
|
63
|
+
*/
|
|
64
|
+
reloadPlugin(pluginName: string, plugin: Plugin, version: string, getPluginState: () => Record<string, any>, restorePluginState: (state: Record<string, any>) => void): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Schedule a reload with debouncing
|
|
67
|
+
*/
|
|
68
|
+
scheduleReload(pluginName: string, reloadFn: () => Promise<void>): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get state manager for direct access
|
|
71
|
+
*/
|
|
72
|
+
getStateManager(): PluginStateManager;
|
|
73
|
+
/**
|
|
74
|
+
* Shutdown hot reload manager
|
|
75
|
+
*/
|
|
76
|
+
shutdown(): void;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=hot-reload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hot-reload.d.ts","sourceRoot":"","sources":["../src/hot-reload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAezC;;;;GAIG;AACH,cAAM,kBAAkB;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,WAAW,CAA0B;gBAEjC,MAAM,EAAE,YAAY;IAIhC;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC;IA8ClB;;OAEG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;IAgC3C;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMlC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,QAAQ,IAAI,IAAI;CAKjB;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,YAAY,CAAqC;gBAE7C,MAAM,EAAE,YAAY;IAKhC;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IAcjE;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAcvC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAgBtC;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzC,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IA8EnB;;OAEG;IACH,cAAc,CACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAC5B,IAAI;IAiCP;;OAEG;IACH,eAAe,IAAI,kBAAkB;IAIrC;;OAEG;IACH,QAAQ,IAAI,IAAI;CAkBjB"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// Polyfill for UUID generation to support both Node.js and Browser
|
|
2
|
+
const generateUUID = () => {
|
|
3
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
4
|
+
return crypto.randomUUID();
|
|
5
|
+
}
|
|
6
|
+
// Basic UUID v4 fallback
|
|
7
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
8
|
+
const r = Math.random() * 16 | 0;
|
|
9
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
10
|
+
return v.toString(16);
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Plugin State Manager
|
|
15
|
+
*
|
|
16
|
+
* Handles state persistence and restoration during hot reloads
|
|
17
|
+
*/
|
|
18
|
+
class PluginStateManager {
|
|
19
|
+
constructor(logger) {
|
|
20
|
+
this.stateSnapshots = new Map();
|
|
21
|
+
this.memoryStore = new Map();
|
|
22
|
+
this.logger = logger.child({ component: 'StateManager' });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Save plugin state before reload
|
|
26
|
+
*/
|
|
27
|
+
async saveState(pluginId, version, state, config) {
|
|
28
|
+
const snapshot = {
|
|
29
|
+
pluginId,
|
|
30
|
+
version,
|
|
31
|
+
timestamp: new Date().toISOString(),
|
|
32
|
+
state,
|
|
33
|
+
metadata: {
|
|
34
|
+
checksum: this.calculateChecksum(state),
|
|
35
|
+
compressed: false,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const snapshotId = generateUUID();
|
|
39
|
+
switch (config.stateStrategy) {
|
|
40
|
+
case 'memory':
|
|
41
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
42
|
+
this.logger.debug('State saved to memory', { pluginId, snapshotId });
|
|
43
|
+
break;
|
|
44
|
+
case 'disk':
|
|
45
|
+
// For disk storage, we would write to file system
|
|
46
|
+
// For now, store in memory as fallback
|
|
47
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
48
|
+
this.logger.debug('State saved to disk (memory fallback)', { pluginId, snapshotId });
|
|
49
|
+
break;
|
|
50
|
+
case 'distributed':
|
|
51
|
+
// For distributed storage, would use Redis/etcd
|
|
52
|
+
// For now, store in memory as fallback
|
|
53
|
+
this.memoryStore.set(snapshotId, snapshot);
|
|
54
|
+
this.logger.debug('State saved to distributed store (memory fallback)', {
|
|
55
|
+
pluginId,
|
|
56
|
+
snapshotId
|
|
57
|
+
});
|
|
58
|
+
break;
|
|
59
|
+
case 'none':
|
|
60
|
+
this.logger.debug('State persistence disabled', { pluginId });
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
this.stateSnapshots.set(pluginId, snapshot);
|
|
64
|
+
return snapshotId;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Restore plugin state after reload
|
|
68
|
+
*/
|
|
69
|
+
async restoreState(pluginId, snapshotId) {
|
|
70
|
+
// Try to get from snapshot ID first, otherwise use latest for plugin
|
|
71
|
+
let snapshot;
|
|
72
|
+
if (snapshotId) {
|
|
73
|
+
snapshot = this.memoryStore.get(snapshotId);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
snapshot = this.stateSnapshots.get(pluginId);
|
|
77
|
+
}
|
|
78
|
+
if (!snapshot) {
|
|
79
|
+
this.logger.warn('No state snapshot found', { pluginId, snapshotId });
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
// Verify checksum if available
|
|
83
|
+
if (snapshot.metadata?.checksum) {
|
|
84
|
+
const currentChecksum = this.calculateChecksum(snapshot.state);
|
|
85
|
+
if (currentChecksum !== snapshot.metadata.checksum) {
|
|
86
|
+
this.logger.error('State checksum mismatch - data may be corrupted', {
|
|
87
|
+
pluginId,
|
|
88
|
+
expected: snapshot.metadata.checksum,
|
|
89
|
+
actual: currentChecksum
|
|
90
|
+
});
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
this.logger.debug('State restored', { pluginId, version: snapshot.version });
|
|
95
|
+
return snapshot.state;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Clear state for a plugin
|
|
99
|
+
*/
|
|
100
|
+
clearState(pluginId) {
|
|
101
|
+
this.stateSnapshots.delete(pluginId);
|
|
102
|
+
// Note: We don't clear memory store as it might have multiple snapshots
|
|
103
|
+
this.logger.debug('State cleared', { pluginId });
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Calculate simple checksum for state verification
|
|
107
|
+
* WARNING: This is a simple hash for demo purposes.
|
|
108
|
+
* In production, use a cryptographic hash like SHA-256.
|
|
109
|
+
*/
|
|
110
|
+
calculateChecksum(state) {
|
|
111
|
+
// Simple checksum using JSON serialization
|
|
112
|
+
// TODO: Replace with crypto.createHash('sha256') for production
|
|
113
|
+
const stateStr = JSON.stringify(state);
|
|
114
|
+
let hash = 0;
|
|
115
|
+
for (let i = 0; i < stateStr.length; i++) {
|
|
116
|
+
const char = stateStr.charCodeAt(i);
|
|
117
|
+
hash = ((hash << 5) - hash) + char;
|
|
118
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
119
|
+
}
|
|
120
|
+
return hash.toString(16);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Shutdown state manager
|
|
124
|
+
*/
|
|
125
|
+
shutdown() {
|
|
126
|
+
this.stateSnapshots.clear();
|
|
127
|
+
this.memoryStore.clear();
|
|
128
|
+
this.logger.info('State manager shutdown complete');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Hot Reload Manager
|
|
133
|
+
*
|
|
134
|
+
* Manages hot reloading of plugins with state preservation
|
|
135
|
+
*/
|
|
136
|
+
export class HotReloadManager {
|
|
137
|
+
constructor(logger) {
|
|
138
|
+
this.reloadConfigs = new Map();
|
|
139
|
+
this.watchHandles = new Map();
|
|
140
|
+
this.reloadTimers = new Map();
|
|
141
|
+
this.logger = logger.child({ component: 'HotReload' });
|
|
142
|
+
this.stateManager = new PluginStateManager(logger);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Register a plugin for hot reload
|
|
146
|
+
*/
|
|
147
|
+
registerPlugin(pluginName, config) {
|
|
148
|
+
if (!config.enabled) {
|
|
149
|
+
this.logger.debug('Hot reload disabled for plugin', { plugin: pluginName });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.reloadConfigs.set(pluginName, config);
|
|
153
|
+
this.logger.info('Plugin registered for hot reload', {
|
|
154
|
+
plugin: pluginName,
|
|
155
|
+
watchPatterns: config.watchPatterns,
|
|
156
|
+
stateStrategy: config.stateStrategy
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Start watching for changes (requires file system integration)
|
|
161
|
+
*/
|
|
162
|
+
startWatching(pluginName) {
|
|
163
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
164
|
+
if (!config || !config.enabled) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Note: Actual file watching would require chokidar or similar
|
|
168
|
+
// This is a placeholder for the integration point
|
|
169
|
+
this.logger.info('File watching started', {
|
|
170
|
+
plugin: pluginName,
|
|
171
|
+
patterns: config.watchPatterns
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Stop watching for changes
|
|
176
|
+
*/
|
|
177
|
+
stopWatching(pluginName) {
|
|
178
|
+
const handle = this.watchHandles.get(pluginName);
|
|
179
|
+
if (handle) {
|
|
180
|
+
// Stop watching (would call chokidar close())
|
|
181
|
+
this.watchHandles.delete(pluginName);
|
|
182
|
+
this.logger.info('File watching stopped', { plugin: pluginName });
|
|
183
|
+
}
|
|
184
|
+
// Clear any pending reload timers
|
|
185
|
+
const timer = this.reloadTimers.get(pluginName);
|
|
186
|
+
if (timer) {
|
|
187
|
+
clearTimeout(timer);
|
|
188
|
+
this.reloadTimers.delete(pluginName);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Trigger hot reload for a plugin
|
|
193
|
+
*/
|
|
194
|
+
async reloadPlugin(pluginName, plugin, version, getPluginState, restorePluginState) {
|
|
195
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
196
|
+
if (!config) {
|
|
197
|
+
this.logger.warn('Cannot reload - plugin not registered', { plugin: pluginName });
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
this.logger.info('Starting hot reload', { plugin: pluginName });
|
|
201
|
+
try {
|
|
202
|
+
// Call before reload hooks
|
|
203
|
+
if (config.beforeReload) {
|
|
204
|
+
this.logger.debug('Executing before reload hooks', {
|
|
205
|
+
plugin: pluginName,
|
|
206
|
+
hooks: config.beforeReload
|
|
207
|
+
});
|
|
208
|
+
// Hook execution would be done through kernel's hook system
|
|
209
|
+
}
|
|
210
|
+
// Save state if configured
|
|
211
|
+
let snapshotId;
|
|
212
|
+
if (config.preserveState && config.stateStrategy !== 'none') {
|
|
213
|
+
const state = getPluginState();
|
|
214
|
+
snapshotId = await this.stateManager.saveState(pluginName, version, state, config);
|
|
215
|
+
this.logger.debug('Plugin state saved', { plugin: pluginName, snapshotId });
|
|
216
|
+
}
|
|
217
|
+
// Gracefully shutdown the plugin
|
|
218
|
+
if (plugin.destroy) {
|
|
219
|
+
this.logger.debug('Destroying plugin', { plugin: pluginName });
|
|
220
|
+
const shutdownPromise = plugin.destroy();
|
|
221
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
222
|
+
setTimeout(() => reject(new Error('Shutdown timeout')), config.shutdownTimeout);
|
|
223
|
+
});
|
|
224
|
+
await Promise.race([shutdownPromise, timeoutPromise]);
|
|
225
|
+
this.logger.debug('Plugin destroyed successfully', { plugin: pluginName });
|
|
226
|
+
}
|
|
227
|
+
// At this point, the kernel would reload the plugin module
|
|
228
|
+
// This would be handled by the plugin loader
|
|
229
|
+
this.logger.debug('Plugin module would be reloaded here', { plugin: pluginName });
|
|
230
|
+
// Restore state if we saved it
|
|
231
|
+
if (snapshotId && config.preserveState) {
|
|
232
|
+
const restoredState = await this.stateManager.restoreState(pluginName, snapshotId);
|
|
233
|
+
if (restoredState) {
|
|
234
|
+
restorePluginState(restoredState);
|
|
235
|
+
this.logger.debug('Plugin state restored', { plugin: pluginName });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Call after reload hooks
|
|
239
|
+
if (config.afterReload) {
|
|
240
|
+
this.logger.debug('Executing after reload hooks', {
|
|
241
|
+
plugin: pluginName,
|
|
242
|
+
hooks: config.afterReload
|
|
243
|
+
});
|
|
244
|
+
// Hook execution would be done through kernel's hook system
|
|
245
|
+
}
|
|
246
|
+
this.logger.info('Hot reload completed successfully', { plugin: pluginName });
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
this.logger.error('Hot reload failed', {
|
|
251
|
+
plugin: pluginName,
|
|
252
|
+
error
|
|
253
|
+
});
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Schedule a reload with debouncing
|
|
259
|
+
*/
|
|
260
|
+
scheduleReload(pluginName, reloadFn) {
|
|
261
|
+
const config = this.reloadConfigs.get(pluginName);
|
|
262
|
+
if (!config) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// Clear existing timer
|
|
266
|
+
const existingTimer = this.reloadTimers.get(pluginName);
|
|
267
|
+
if (existingTimer) {
|
|
268
|
+
clearTimeout(existingTimer);
|
|
269
|
+
}
|
|
270
|
+
// Schedule new reload with debounce
|
|
271
|
+
const timer = setTimeout(() => {
|
|
272
|
+
this.logger.debug('Debounce period elapsed, executing reload', {
|
|
273
|
+
plugin: pluginName
|
|
274
|
+
});
|
|
275
|
+
reloadFn().catch(error => {
|
|
276
|
+
this.logger.error('Scheduled reload failed', {
|
|
277
|
+
plugin: pluginName,
|
|
278
|
+
error
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
this.reloadTimers.delete(pluginName);
|
|
282
|
+
}, config.debounceDelay);
|
|
283
|
+
this.reloadTimers.set(pluginName, timer);
|
|
284
|
+
this.logger.debug('Reload scheduled with debounce', {
|
|
285
|
+
plugin: pluginName,
|
|
286
|
+
delay: config.debounceDelay
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get state manager for direct access
|
|
291
|
+
*/
|
|
292
|
+
getStateManager() {
|
|
293
|
+
return this.stateManager;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Shutdown hot reload manager
|
|
297
|
+
*/
|
|
298
|
+
shutdown() {
|
|
299
|
+
// Stop all watching
|
|
300
|
+
for (const pluginName of this.watchHandles.keys()) {
|
|
301
|
+
this.stopWatching(pluginName);
|
|
302
|
+
}
|
|
303
|
+
// Clear all timers
|
|
304
|
+
for (const timer of this.reloadTimers.values()) {
|
|
305
|
+
clearTimeout(timer);
|
|
306
|
+
}
|
|
307
|
+
this.reloadConfigs.clear();
|
|
308
|
+
this.watchHandles.clear();
|
|
309
|
+
this.reloadTimers.clear();
|
|
310
|
+
this.stateManager.shutdown();
|
|
311
|
+
this.logger.info('Hot reload manager shutdown complete');
|
|
312
|
+
}
|
|
313
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export * from './kernel-base.js';
|
|
8
8
|
export * from './kernel.js';
|
|
9
|
+
export * from './lite-kernel.js';
|
|
9
10
|
export * from './types.js';
|
|
10
11
|
export * from './logger.js';
|
|
11
12
|
export * from './plugin-loader.js';
|
|
12
|
-
export * from './enhanced-kernel.js';
|
|
13
13
|
export * from './api-registry.js';
|
|
14
14
|
export * from './api-registry-plugin.js';
|
|
15
15
|
export * as QA from './qa/index.js';
|
|
16
16
|
export * from './security/index.js';
|
|
17
|
+
export * from './health-monitor.js';
|
|
18
|
+
export * from './hot-reload.js';
|
|
19
|
+
export * from './dependency-resolver.js';
|
|
17
20
|
export type { Logger, IHttpServer, IHttpRequest, IHttpResponse, RouteHandler, Middleware, IDataEngine, DriverInterface } from '@objectstack/spec/contracts';
|
|
18
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,eAAe,CAAC;AAGpC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AAGzC,YAAY,EACR,MAAM,EACN,WAAW,EACX,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EAClB,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export * from './kernel-base.js';
|
|
8
8
|
export * from './kernel.js';
|
|
9
|
+
export * from './lite-kernel.js';
|
|
9
10
|
export * from './types.js';
|
|
10
11
|
export * from './logger.js';
|
|
11
12
|
export * from './plugin-loader.js';
|
|
12
|
-
export * from './enhanced-kernel.js';
|
|
13
13
|
export * from './api-registry.js';
|
|
14
14
|
export * from './api-registry-plugin.js';
|
|
15
15
|
export * as QA from './qa/index.js';
|
|
16
16
|
// Export security utilities
|
|
17
17
|
export * from './security/index.js';
|
|
18
|
+
// Export Phase 2 components - Advanced lifecycle management
|
|
19
|
+
export * from './health-monitor.js';
|
|
20
|
+
export * from './hot-reload.js';
|
|
21
|
+
export * from './dependency-resolver.js';
|
package/dist/kernel-base.d.ts
CHANGED
|
@@ -8,14 +8,14 @@ export type KernelState = 'idle' | 'initializing' | 'running' | 'stopping' | 'st
|
|
|
8
8
|
/**
|
|
9
9
|
* ObjectKernelBase - Abstract Base Class for Microkernel
|
|
10
10
|
*
|
|
11
|
-
* Provides common functionality for
|
|
11
|
+
* Provides common functionality for ObjectKernel and LiteKernel:
|
|
12
12
|
* - Plugin management (Map storage)
|
|
13
13
|
* - Dependency resolution (topological sort)
|
|
14
14
|
* - Hook/Event system
|
|
15
15
|
* - Context creation
|
|
16
16
|
* - State validation
|
|
17
17
|
*
|
|
18
|
-
* This eliminates
|
|
18
|
+
* This eliminates code duplication between the implementations.
|
|
19
19
|
*/
|
|
20
20
|
export declare abstract class ObjectKernelBase {
|
|
21
21
|
protected plugins: Map<string, Plugin>;
|
package/dist/kernel-base.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ObjectKernelBase - Abstract Base Class for Microkernel
|
|
3
3
|
*
|
|
4
|
-
* Provides common functionality for
|
|
4
|
+
* Provides common functionality for ObjectKernel and LiteKernel:
|
|
5
5
|
* - Plugin management (Map storage)
|
|
6
6
|
* - Dependency resolution (topological sort)
|
|
7
7
|
* - Hook/Event system
|
|
8
8
|
* - Context creation
|
|
9
9
|
* - State validation
|
|
10
10
|
*
|
|
11
|
-
* This eliminates
|
|
11
|
+
* This eliminates code duplication between the implementations.
|
|
12
12
|
*/
|
|
13
13
|
export class ObjectKernelBase {
|
|
14
14
|
constructor(logger) {
|
package/dist/kernel.d.ts
CHANGED
|
@@ -1,55 +1,103 @@
|
|
|
1
1
|
import { Plugin } from './types.js';
|
|
2
2
|
import type { LoggerConfig } from '@objectstack/spec/system';
|
|
3
|
-
import {
|
|
3
|
+
import { ServiceLifecycle, ServiceFactory } from './plugin-loader.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
* Enhanced Kernel Configuration
|
|
6
|
+
*/
|
|
7
|
+
export interface ObjectKernelConfig {
|
|
8
|
+
logger?: Partial<LoggerConfig>;
|
|
9
|
+
/** Default plugin startup timeout in milliseconds */
|
|
10
|
+
defaultStartupTimeout?: number;
|
|
11
|
+
/** Whether to enable graceful shutdown */
|
|
12
|
+
gracefulShutdown?: boolean;
|
|
13
|
+
/** Graceful shutdown timeout in milliseconds */
|
|
14
|
+
shutdownTimeout?: number;
|
|
15
|
+
/** Whether to rollback on startup failure */
|
|
16
|
+
rollbackOnFailure?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Enhanced ObjectKernel with Advanced Plugin Management
|
|
13
20
|
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
21
|
+
* Extends the basic ObjectKernel with:
|
|
22
|
+
* - Async plugin loading with validation
|
|
23
|
+
* - Version compatibility checking
|
|
24
|
+
* - Plugin signature verification
|
|
25
|
+
* - Configuration validation (Zod)
|
|
26
|
+
* - Factory-based dependency injection
|
|
27
|
+
* - Service lifecycle management (singleton/transient/scoped)
|
|
28
|
+
* - Circular dependency detection
|
|
29
|
+
* - Lazy loading services
|
|
30
|
+
* - Graceful shutdown
|
|
31
|
+
* - Plugin startup timeout control
|
|
32
|
+
* - Startup failure rollback
|
|
33
|
+
* - Plugin health checks
|
|
18
34
|
*/
|
|
19
|
-
export declare class ObjectKernel
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
export declare class ObjectKernel {
|
|
36
|
+
private plugins;
|
|
37
|
+
private services;
|
|
38
|
+
private hooks;
|
|
39
|
+
private state;
|
|
40
|
+
private logger;
|
|
41
|
+
private context;
|
|
42
|
+
private pluginLoader;
|
|
43
|
+
private config;
|
|
44
|
+
private startedPlugins;
|
|
45
|
+
private pluginStartTimes;
|
|
46
|
+
private shutdownHandlers;
|
|
47
|
+
constructor(config?: ObjectKernelConfig);
|
|
23
48
|
/**
|
|
24
|
-
* Register a plugin
|
|
25
|
-
* @param plugin - Plugin instance
|
|
49
|
+
* Register a plugin with enhanced validation
|
|
26
50
|
*/
|
|
27
|
-
use(plugin: Plugin): this
|
|
51
|
+
use(plugin: Plugin): Promise<this>;
|
|
28
52
|
/**
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*
|
|
53
|
+
* Register a service factory with lifecycle management
|
|
54
|
+
*/
|
|
55
|
+
registerServiceFactory<T>(name: string, factory: ServiceFactory<T>, lifecycle?: ServiceLifecycle, dependencies?: string[]): this;
|
|
56
|
+
/**
|
|
57
|
+
* Bootstrap the kernel with enhanced features
|
|
34
58
|
*/
|
|
35
59
|
bootstrap(): Promise<void>;
|
|
36
60
|
/**
|
|
37
|
-
*
|
|
38
|
-
* Calls destroy on all plugins in reverse order
|
|
61
|
+
* Graceful shutdown with timeout
|
|
39
62
|
*/
|
|
40
63
|
shutdown(): Promise<void>;
|
|
41
64
|
/**
|
|
42
|
-
*
|
|
65
|
+
* Check health of a specific plugin
|
|
66
|
+
*/
|
|
67
|
+
checkPluginHealth(pluginName: string): Promise<any>;
|
|
68
|
+
/**
|
|
69
|
+
* Check health of all plugins
|
|
43
70
|
*/
|
|
44
|
-
|
|
71
|
+
checkAllPluginsHealth(): Promise<Map<string, any>>;
|
|
45
72
|
/**
|
|
46
|
-
* Get
|
|
47
|
-
|
|
73
|
+
* Get plugin startup metrics
|
|
74
|
+
*/
|
|
75
|
+
getPluginMetrics(): Map<string, number>;
|
|
76
|
+
/**
|
|
77
|
+
* Get a service (sync helper)
|
|
48
78
|
*/
|
|
49
79
|
getService<T>(name: string): T;
|
|
80
|
+
/**
|
|
81
|
+
* Get a service asynchronously (supports factories)
|
|
82
|
+
*/
|
|
83
|
+
getServiceAsync<T>(name: string, scopeId?: string): Promise<T>;
|
|
50
84
|
/**
|
|
51
85
|
* Check if kernel is running
|
|
52
86
|
*/
|
|
53
87
|
isRunning(): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Get kernel state
|
|
90
|
+
*/
|
|
91
|
+
getState(): string;
|
|
92
|
+
private initPluginWithTimeout;
|
|
93
|
+
private startPluginWithTimeout;
|
|
94
|
+
private rollbackStartedPlugins;
|
|
95
|
+
private performShutdown;
|
|
96
|
+
private resolveDependencies;
|
|
97
|
+
private registerShutdownSignals;
|
|
98
|
+
/**
|
|
99
|
+
* Register a custom shutdown handler
|
|
100
|
+
*/
|
|
101
|
+
onShutdown(handler: () => Promise<void>): void;
|
|
54
102
|
}
|
|
55
103
|
//# sourceMappingURL=kernel.d.ts.map
|
package/dist/kernel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../src/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../src/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAgC,gBAAgB,EAAE,cAAc,EAAuB,MAAM,oBAAoB,CAAC;AAEzH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/B,qDAAqD;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAY;IACrB,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,KAAK,CAA2E;IACxF,OAAO,CAAC,KAAK,CAAwE;IACrF,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,gBAAgB,CAAkC;IAC1D,OAAO,CAAC,gBAAgB,CAAkC;gBAE9C,MAAM,GAAE,kBAAuB;IAyF3C;;OAEG;IACG,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxC;;OAEG;IACH,sBAAsB,CAAC,CAAC,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,SAAS,GAAE,gBAA6C,EACxD,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,IAAI;IAUP;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAqDhC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC/B;;OAEG;IACG,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIzD;;OAEG;IACG,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAWxD;;OAEG;IACH,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIvC;;OAEG;IACH,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC;IAI9B;;OAEG;IACG,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpE;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,QAAQ,IAAI,MAAM;YAMJ,qBAAqB;YAerB,sBAAsB;YA6CtB,sBAAsB;YAkBtB,eAAe;IA2B7B,OAAO,CAAC,mBAAmB;IAyC3B,OAAO,CAAC,uBAAuB;IA2B/B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;CAGjD"}
|