@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.
Files changed (89) hide show
  1. package/{ENHANCED_FEATURES.md → ADVANCED_FEATURES.md} +13 -13
  2. package/CHANGELOG.md +7 -0
  3. package/PHASE2_IMPLEMENTATION.md +388 -0
  4. package/README.md +24 -11
  5. package/REFACTORING_SUMMARY.md +40 -0
  6. package/dist/api-registry-plugin.test.js +20 -20
  7. package/dist/dependency-resolver.d.ts +62 -0
  8. package/dist/dependency-resolver.d.ts.map +1 -0
  9. package/dist/dependency-resolver.js +317 -0
  10. package/dist/dependency-resolver.test.d.ts +2 -0
  11. package/dist/dependency-resolver.test.d.ts.map +1 -0
  12. package/dist/dependency-resolver.test.js +241 -0
  13. package/dist/health-monitor.d.ts +65 -0
  14. package/dist/health-monitor.d.ts.map +1 -0
  15. package/dist/health-monitor.js +269 -0
  16. package/dist/health-monitor.test.d.ts +2 -0
  17. package/dist/health-monitor.test.d.ts.map +1 -0
  18. package/dist/health-monitor.test.js +68 -0
  19. package/dist/hot-reload.d.ts +79 -0
  20. package/dist/hot-reload.d.ts.map +1 -0
  21. package/dist/hot-reload.js +313 -0
  22. package/dist/index.d.ts +4 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +5 -1
  25. package/dist/kernel-base.d.ts +2 -2
  26. package/dist/kernel-base.js +2 -2
  27. package/dist/kernel.d.ts +79 -31
  28. package/dist/kernel.d.ts.map +1 -1
  29. package/dist/kernel.js +383 -73
  30. package/dist/kernel.test.js +373 -122
  31. package/dist/lite-kernel.d.ts +55 -0
  32. package/dist/lite-kernel.d.ts.map +1 -0
  33. package/dist/lite-kernel.js +112 -0
  34. package/dist/lite-kernel.test.d.ts +2 -0
  35. package/dist/lite-kernel.test.d.ts.map +1 -0
  36. package/dist/lite-kernel.test.js +161 -0
  37. package/dist/logger.d.ts +2 -2
  38. package/dist/logger.d.ts.map +1 -1
  39. package/dist/logger.js +26 -7
  40. package/dist/plugin-loader.d.ts +11 -0
  41. package/dist/plugin-loader.d.ts.map +1 -1
  42. package/dist/plugin-loader.js +34 -10
  43. package/dist/plugin-loader.test.js +9 -0
  44. package/dist/security/index.d.ts +3 -0
  45. package/dist/security/index.d.ts.map +1 -1
  46. package/dist/security/index.js +4 -0
  47. package/dist/security/permission-manager.d.ts +96 -0
  48. package/dist/security/permission-manager.d.ts.map +1 -0
  49. package/dist/security/permission-manager.js +235 -0
  50. package/dist/security/permission-manager.test.d.ts +2 -0
  51. package/dist/security/permission-manager.test.d.ts.map +1 -0
  52. package/dist/security/permission-manager.test.js +220 -0
  53. package/dist/security/sandbox-runtime.d.ts +115 -0
  54. package/dist/security/sandbox-runtime.d.ts.map +1 -0
  55. package/dist/security/sandbox-runtime.js +310 -0
  56. package/dist/security/security-scanner.d.ts +92 -0
  57. package/dist/security/security-scanner.d.ts.map +1 -0
  58. package/dist/security/security-scanner.js +273 -0
  59. package/examples/{enhanced-kernel-example.ts → kernel-features-example.ts} +6 -6
  60. package/examples/phase2-integration.ts +355 -0
  61. package/package.json +2 -2
  62. package/src/api-registry-plugin.test.ts +20 -20
  63. package/src/dependency-resolver.test.ts +287 -0
  64. package/src/dependency-resolver.ts +388 -0
  65. package/src/health-monitor.test.ts +81 -0
  66. package/src/health-monitor.ts +316 -0
  67. package/src/hot-reload.ts +388 -0
  68. package/src/index.ts +6 -1
  69. package/src/kernel-base.ts +2 -2
  70. package/src/kernel.test.ts +469 -134
  71. package/src/kernel.ts +464 -78
  72. package/src/lite-kernel.test.ts +200 -0
  73. package/src/lite-kernel.ts +135 -0
  74. package/src/logger.ts +28 -7
  75. package/src/plugin-loader.test.ts +10 -1
  76. package/src/plugin-loader.ts +42 -13
  77. package/src/security/index.ts +19 -0
  78. package/src/security/permission-manager.test.ts +256 -0
  79. package/src/security/permission-manager.ts +336 -0
  80. package/src/security/sandbox-runtime.ts +432 -0
  81. package/src/security/security-scanner.ts +365 -0
  82. package/dist/enhanced-kernel.d.ts +0 -103
  83. package/dist/enhanced-kernel.d.ts.map +0 -1
  84. package/dist/enhanced-kernel.js +0 -403
  85. package/dist/enhanced-kernel.test.d.ts +0 -2
  86. package/dist/enhanced-kernel.test.d.ts.map +0 -1
  87. package/dist/enhanced-kernel.test.js +0 -412
  88. package/src/enhanced-kernel.test.ts +0 -535
  89. package/src/enhanced-kernel.ts +0 -496
@@ -1,403 +0,0 @@
1
- import { createLogger } from './logger.js';
2
- import { PluginLoader, ServiceLifecycle } from './plugin-loader.js';
3
- /**
4
- * Enhanced ObjectKernel with Advanced Plugin Management
5
- *
6
- * Extends the basic ObjectKernel with:
7
- * - Async plugin loading with validation
8
- * - Version compatibility checking
9
- * - Plugin signature verification
10
- * - Configuration validation (Zod)
11
- * - Factory-based dependency injection
12
- * - Service lifecycle management (singleton/transient/scoped)
13
- * - Circular dependency detection
14
- * - Lazy loading services
15
- * - Graceful shutdown
16
- * - Plugin startup timeout control
17
- * - Startup failure rollback
18
- * - Plugin health checks
19
- */
20
- export class EnhancedObjectKernel {
21
- constructor(config = {}) {
22
- this.plugins = new Map();
23
- this.services = new Map();
24
- this.hooks = new Map();
25
- this.state = 'idle';
26
- this.startedPlugins = new Set();
27
- this.pluginStartTimes = new Map();
28
- this.shutdownHandlers = [];
29
- this.config = {
30
- defaultStartupTimeout: 30000, // 30 seconds
31
- gracefulShutdown: true,
32
- shutdownTimeout: 60000, // 60 seconds
33
- rollbackOnFailure: true,
34
- ...config,
35
- };
36
- this.logger = createLogger(config.logger);
37
- this.pluginLoader = new PluginLoader(this.logger);
38
- // Initialize context
39
- this.context = {
40
- registerService: (name, service) => {
41
- if (this.services.has(name)) {
42
- throw new Error(`[Kernel] Service '${name}' already registered`);
43
- }
44
- this.services.set(name, service);
45
- this.pluginLoader.registerService(name, service);
46
- this.logger.info(`Service '${name}' registered`, { service: name });
47
- },
48
- getService: (name) => {
49
- // Try to get from plugin loader (supports factories and lifecycle)
50
- try {
51
- const service = this.pluginLoader.getService(name);
52
- if (service instanceof Promise) {
53
- throw new Error(`Service '${name}' is async - use await`);
54
- }
55
- return service;
56
- }
57
- catch {
58
- // Fall back to direct service map
59
- const service = this.services.get(name);
60
- if (!service) {
61
- throw new Error(`[Kernel] Service '${name}' not found`);
62
- }
63
- return service;
64
- }
65
- },
66
- hook: (name, handler) => {
67
- if (!this.hooks.has(name)) {
68
- this.hooks.set(name, []);
69
- }
70
- this.hooks.get(name).push(handler);
71
- },
72
- trigger: async (name, ...args) => {
73
- const handlers = this.hooks.get(name) || [];
74
- for (const handler of handlers) {
75
- await handler(...args);
76
- }
77
- },
78
- getServices: () => {
79
- return new Map(this.services);
80
- },
81
- logger: this.logger,
82
- getKernel: () => this, // Type compatibility
83
- };
84
- // Register shutdown handler
85
- if (this.config.gracefulShutdown) {
86
- this.registerShutdownSignals();
87
- }
88
- }
89
- /**
90
- * Register a plugin with enhanced validation
91
- */
92
- async use(plugin) {
93
- if (this.state !== 'idle') {
94
- throw new Error('[Kernel] Cannot register plugins after bootstrap has started');
95
- }
96
- // Load plugin through enhanced loader
97
- const result = await this.pluginLoader.loadPlugin(plugin);
98
- if (!result.success || !result.plugin) {
99
- throw new Error(`Failed to load plugin: ${plugin.name} - ${result.error?.message}`);
100
- }
101
- const pluginMeta = result.plugin;
102
- this.plugins.set(pluginMeta.name, pluginMeta);
103
- this.logger.info(`Plugin registered: ${pluginMeta.name}@${pluginMeta.version}`, {
104
- plugin: pluginMeta.name,
105
- version: pluginMeta.version,
106
- });
107
- return this;
108
- }
109
- /**
110
- * Register a service factory with lifecycle management
111
- */
112
- registerServiceFactory(name, factory, lifecycle = ServiceLifecycle.SINGLETON, dependencies) {
113
- this.pluginLoader.registerServiceFactory({
114
- name,
115
- factory,
116
- lifecycle,
117
- dependencies,
118
- });
119
- return this;
120
- }
121
- /**
122
- * Bootstrap the kernel with enhanced features
123
- */
124
- async bootstrap() {
125
- if (this.state !== 'idle') {
126
- throw new Error('[Kernel] Kernel already bootstrapped');
127
- }
128
- this.state = 'initializing';
129
- this.logger.info('Bootstrap started');
130
- try {
131
- // Check for circular dependencies
132
- const cycles = this.pluginLoader.detectCircularDependencies();
133
- if (cycles.length > 0) {
134
- this.logger.warn('Circular service dependencies detected:', { cycles });
135
- }
136
- // Resolve plugin dependencies
137
- const orderedPlugins = this.resolveDependencies();
138
- // Phase 1: Init - Plugins register services
139
- this.logger.info('Phase 1: Init plugins');
140
- for (const plugin of orderedPlugins) {
141
- await this.initPluginWithTimeout(plugin);
142
- }
143
- // Phase 2: Start - Plugins execute business logic
144
- this.logger.info('Phase 2: Start plugins');
145
- this.state = 'running';
146
- for (const plugin of orderedPlugins) {
147
- const result = await this.startPluginWithTimeout(plugin);
148
- if (!result.success) {
149
- this.logger.error(`Plugin startup failed: ${plugin.name}`, result.error);
150
- if (this.config.rollbackOnFailure) {
151
- this.logger.warn('Rolling back started plugins...');
152
- await this.rollbackStartedPlugins();
153
- throw new Error(`Plugin ${plugin.name} failed to start - rollback complete`);
154
- }
155
- }
156
- }
157
- // Phase 3: Trigger kernel:ready hook
158
- this.logger.debug('Triggering kernel:ready hook');
159
- await this.context.trigger('kernel:ready');
160
- this.logger.info('✅ Bootstrap complete');
161
- }
162
- catch (error) {
163
- this.state = 'stopped';
164
- throw error;
165
- }
166
- }
167
- /**
168
- * Graceful shutdown with timeout
169
- */
170
- async shutdown() {
171
- if (this.state === 'stopped' || this.state === 'stopping') {
172
- this.logger.warn('Kernel already stopped or stopping');
173
- return;
174
- }
175
- if (this.state !== 'running') {
176
- throw new Error('[Kernel] Kernel not running');
177
- }
178
- this.state = 'stopping';
179
- this.logger.info('Graceful shutdown started');
180
- try {
181
- // Create shutdown promise with timeout
182
- const shutdownPromise = this.performShutdown();
183
- const timeoutPromise = new Promise((_, reject) => {
184
- setTimeout(() => {
185
- reject(new Error('Shutdown timeout exceeded'));
186
- }, this.config.shutdownTimeout);
187
- });
188
- // Race between shutdown and timeout
189
- await Promise.race([shutdownPromise, timeoutPromise]);
190
- this.state = 'stopped';
191
- this.logger.info('✅ Graceful shutdown complete');
192
- }
193
- catch (error) {
194
- this.logger.error('Shutdown error - forcing stop', error);
195
- this.state = 'stopped';
196
- throw error;
197
- }
198
- finally {
199
- // Cleanup logger resources
200
- await this.logger.destroy();
201
- }
202
- }
203
- /**
204
- * Check health of a specific plugin
205
- */
206
- async checkPluginHealth(pluginName) {
207
- return await this.pluginLoader.checkPluginHealth(pluginName);
208
- }
209
- /**
210
- * Check health of all plugins
211
- */
212
- async checkAllPluginsHealth() {
213
- const results = new Map();
214
- for (const pluginName of this.plugins.keys()) {
215
- const health = await this.checkPluginHealth(pluginName);
216
- results.set(pluginName, health);
217
- }
218
- return results;
219
- }
220
- /**
221
- * Get plugin startup metrics
222
- */
223
- getPluginMetrics() {
224
- return new Map(this.pluginStartTimes);
225
- }
226
- /**
227
- * Get a service (sync helper)
228
- */
229
- getService(name) {
230
- return this.context.getService(name);
231
- }
232
- /**
233
- * Get a service asynchronously (supports factories)
234
- */
235
- async getServiceAsync(name, scopeId) {
236
- return await this.pluginLoader.getService(name, scopeId);
237
- }
238
- /**
239
- * Check if kernel is running
240
- */
241
- isRunning() {
242
- return this.state === 'running';
243
- }
244
- /**
245
- * Get kernel state
246
- */
247
- getState() {
248
- return this.state;
249
- }
250
- // Private methods
251
- async initPluginWithTimeout(plugin) {
252
- const timeout = plugin.startupTimeout || this.config.defaultStartupTimeout;
253
- this.logger.debug(`Init: ${plugin.name}`, { plugin: plugin.name });
254
- const initPromise = plugin.init(this.context);
255
- const timeoutPromise = new Promise((_, reject) => {
256
- setTimeout(() => {
257
- reject(new Error(`Plugin ${plugin.name} init timeout after ${timeout}ms`));
258
- }, timeout);
259
- });
260
- await Promise.race([initPromise, timeoutPromise]);
261
- }
262
- async startPluginWithTimeout(plugin) {
263
- if (!plugin.start) {
264
- return { success: true, pluginName: plugin.name };
265
- }
266
- const timeout = plugin.startupTimeout || this.config.defaultStartupTimeout;
267
- const startTime = Date.now();
268
- this.logger.debug(`Start: ${plugin.name}`, { plugin: plugin.name });
269
- try {
270
- const startPromise = plugin.start(this.context);
271
- const timeoutPromise = new Promise((_, reject) => {
272
- setTimeout(() => {
273
- reject(new Error(`Plugin ${plugin.name} start timeout after ${timeout}ms`));
274
- }, timeout);
275
- });
276
- await Promise.race([startPromise, timeoutPromise]);
277
- const duration = Date.now() - startTime;
278
- this.startedPlugins.add(plugin.name);
279
- this.pluginStartTimes.set(plugin.name, duration);
280
- this.logger.debug(`Plugin started: ${plugin.name} (${duration}ms)`);
281
- return {
282
- success: true,
283
- pluginName: plugin.name,
284
- startTime: duration,
285
- };
286
- }
287
- catch (error) {
288
- const duration = Date.now() - startTime;
289
- const isTimeout = error.message.includes('timeout');
290
- return {
291
- success: false,
292
- pluginName: plugin.name,
293
- error: error,
294
- startTime: duration,
295
- timedOut: isTimeout,
296
- };
297
- }
298
- }
299
- async rollbackStartedPlugins() {
300
- const pluginsToRollback = Array.from(this.startedPlugins).reverse();
301
- for (const pluginName of pluginsToRollback) {
302
- const plugin = this.plugins.get(pluginName);
303
- if (plugin?.destroy) {
304
- try {
305
- this.logger.debug(`Rollback: ${pluginName}`);
306
- await plugin.destroy();
307
- }
308
- catch (error) {
309
- this.logger.error(`Rollback failed for ${pluginName}`, error);
310
- }
311
- }
312
- }
313
- this.startedPlugins.clear();
314
- }
315
- async performShutdown() {
316
- // Trigger shutdown hook
317
- await this.context.trigger('kernel:shutdown');
318
- // Destroy plugins in reverse order
319
- const orderedPlugins = Array.from(this.plugins.values()).reverse();
320
- for (const plugin of orderedPlugins) {
321
- if (plugin.destroy) {
322
- this.logger.debug(`Destroy: ${plugin.name}`, { plugin: plugin.name });
323
- try {
324
- await plugin.destroy();
325
- }
326
- catch (error) {
327
- this.logger.error(`Error destroying plugin ${plugin.name}`, error);
328
- }
329
- }
330
- }
331
- // Execute custom shutdown handlers
332
- for (const handler of this.shutdownHandlers) {
333
- try {
334
- await handler();
335
- }
336
- catch (error) {
337
- this.logger.error('Shutdown handler error', error);
338
- }
339
- }
340
- }
341
- resolveDependencies() {
342
- const resolved = [];
343
- const visited = new Set();
344
- const visiting = new Set();
345
- const visit = (pluginName) => {
346
- if (visited.has(pluginName))
347
- return;
348
- if (visiting.has(pluginName)) {
349
- throw new Error(`[Kernel] Circular dependency detected: ${pluginName}`);
350
- }
351
- const plugin = this.plugins.get(pluginName);
352
- if (!plugin) {
353
- throw new Error(`[Kernel] Plugin '${pluginName}' not found`);
354
- }
355
- visiting.add(pluginName);
356
- // Visit dependencies first
357
- const deps = plugin.dependencies || [];
358
- for (const dep of deps) {
359
- if (!this.plugins.has(dep)) {
360
- throw new Error(`[Kernel] Dependency '${dep}' not found for plugin '${pluginName}'`);
361
- }
362
- visit(dep);
363
- }
364
- visiting.delete(pluginName);
365
- visited.add(pluginName);
366
- resolved.push(plugin);
367
- };
368
- // Visit all plugins
369
- for (const pluginName of this.plugins.keys()) {
370
- visit(pluginName);
371
- }
372
- return resolved;
373
- }
374
- registerShutdownSignals() {
375
- const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
376
- let shutdownInProgress = false;
377
- const handleShutdown = async (signal) => {
378
- if (shutdownInProgress) {
379
- this.logger.warn(`Shutdown already in progress, ignoring ${signal}`);
380
- return;
381
- }
382
- shutdownInProgress = true;
383
- this.logger.info(`Received ${signal} - initiating graceful shutdown`);
384
- try {
385
- await this.shutdown();
386
- process.exit(0);
387
- }
388
- catch (error) {
389
- this.logger.error('Shutdown failed', error);
390
- process.exit(1);
391
- }
392
- };
393
- for (const signal of signals) {
394
- process.on(signal, () => handleShutdown(signal));
395
- }
396
- }
397
- /**
398
- * Register a custom shutdown handler
399
- */
400
- onShutdown(handler) {
401
- this.shutdownHandlers.push(handler);
402
- }
403
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=enhanced-kernel.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enhanced-kernel.test.d.ts","sourceRoot":"","sources":["../src/enhanced-kernel.test.ts"],"names":[],"mappings":""}