@objectstack/core 0.6.1 → 0.7.1

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 (56) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/ENHANCED_FEATURES.md +380 -0
  3. package/README.md +299 -12
  4. package/dist/contracts/data-engine.d.ts +39 -22
  5. package/dist/contracts/data-engine.d.ts.map +1 -1
  6. package/dist/contracts/logger.d.ts +63 -0
  7. package/dist/contracts/logger.d.ts.map +1 -0
  8. package/dist/contracts/logger.js +1 -0
  9. package/dist/enhanced-kernel.d.ts +103 -0
  10. package/dist/enhanced-kernel.d.ts.map +1 -0
  11. package/dist/enhanced-kernel.js +403 -0
  12. package/dist/enhanced-kernel.test.d.ts +2 -0
  13. package/dist/enhanced-kernel.test.d.ts.map +1 -0
  14. package/dist/enhanced-kernel.test.js +412 -0
  15. package/dist/index.d.ts +11 -2
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +10 -2
  18. package/dist/kernel-base.d.ts +84 -0
  19. package/dist/kernel-base.d.ts.map +1 -0
  20. package/dist/kernel-base.js +219 -0
  21. package/dist/kernel.d.ts +11 -18
  22. package/dist/kernel.d.ts.map +1 -1
  23. package/dist/kernel.js +43 -114
  24. package/dist/kernel.test.d.ts +2 -0
  25. package/dist/kernel.test.d.ts.map +1 -0
  26. package/dist/kernel.test.js +161 -0
  27. package/dist/logger.d.ts +70 -0
  28. package/dist/logger.d.ts.map +1 -0
  29. package/dist/logger.js +268 -0
  30. package/dist/logger.test.d.ts +2 -0
  31. package/dist/logger.test.d.ts.map +1 -0
  32. package/dist/logger.test.js +92 -0
  33. package/dist/plugin-loader.d.ts +148 -0
  34. package/dist/plugin-loader.d.ts.map +1 -0
  35. package/dist/plugin-loader.js +287 -0
  36. package/dist/plugin-loader.test.d.ts +2 -0
  37. package/dist/plugin-loader.test.d.ts.map +1 -0
  38. package/dist/plugin-loader.test.js +339 -0
  39. package/dist/types.d.ts +2 -1
  40. package/dist/types.d.ts.map +1 -1
  41. package/examples/enhanced-kernel-example.ts +309 -0
  42. package/package.json +19 -4
  43. package/src/contracts/data-engine.ts +46 -24
  44. package/src/contracts/logger.ts +70 -0
  45. package/src/enhanced-kernel.test.ts +535 -0
  46. package/src/enhanced-kernel.ts +496 -0
  47. package/src/index.ts +23 -2
  48. package/src/kernel-base.ts +256 -0
  49. package/src/kernel.test.ts +200 -0
  50. package/src/kernel.ts +55 -129
  51. package/src/logger.test.ts +116 -0
  52. package/src/logger.ts +306 -0
  53. package/src/plugin-loader.test.ts +412 -0
  54. package/src/plugin-loader.ts +435 -0
  55. package/src/types.ts +2 -1
  56. package/vitest.config.ts +8 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @objectstack/core
2
2
 
3
+ ## 0.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @objectstack/spec@0.7.1
9
+
3
10
  ## 0.6.1
4
11
 
5
12
  ### Patch Changes
@@ -0,0 +1,380 @@
1
+ # Enhanced ObjectKernel - Advanced Plugin Features
2
+
3
+ This document describes the enhanced features added to ObjectKernel for production-grade plugin management.
4
+
5
+ ## Overview
6
+
7
+ The `EnhancedObjectKernel` extends the basic `ObjectKernel` with enterprise-grade features for plugin lifecycle management, dependency injection, and operational resilience.
8
+
9
+ ## Features
10
+
11
+ ### 1. Enhanced Plugin Loading
12
+
13
+ Async plugin loading with comprehensive validation:
14
+
15
+ ```typescript
16
+ import { EnhancedObjectKernel, PluginMetadata } from '@objectstack/core';
17
+
18
+ const kernel = new EnhancedObjectKernel({
19
+ logger: { level: 'info' },
20
+ defaultStartupTimeout: 30000, // 30 seconds
21
+ gracefulShutdown: true,
22
+ shutdownTimeout: 60000, // 60 seconds
23
+ rollbackOnFailure: true, // Rollback on startup failure
24
+ });
25
+
26
+ // Plugin with version and timeout
27
+ const myPlugin: PluginMetadata = {
28
+ name: 'my-plugin',
29
+ version: '1.2.3', // Semantic version required
30
+ startupTimeout: 10000, // Override default timeout
31
+
32
+ async init(ctx) {
33
+ // Register services
34
+ ctx.registerService('my-service', serviceInstance);
35
+ },
36
+
37
+ async start(ctx) {
38
+ // Start business logic
39
+ },
40
+
41
+ async destroy() {
42
+ // Cleanup resources
43
+ },
44
+
45
+ // Optional: Health check
46
+ async healthCheck() {
47
+ return {
48
+ healthy: true,
49
+ message: 'Service is running',
50
+ details: { connections: 10 }
51
+ };
52
+ }
53
+ };
54
+
55
+ await kernel.use(myPlugin);
56
+ await kernel.bootstrap();
57
+ ```
58
+
59
+ ### 2. Advanced Dependency Injection
60
+
61
+ Factory-based service registration with lifecycle management:
62
+
63
+ ```typescript
64
+ import { ServiceLifecycle } from '@objectstack/core';
65
+
66
+ // Singleton: Created once, shared across all requests
67
+ kernel.registerServiceFactory(
68
+ 'database',
69
+ async (ctx) => {
70
+ const db = await connectToDatabase();
71
+ return db;
72
+ },
73
+ ServiceLifecycle.SINGLETON
74
+ );
75
+
76
+ // Transient: New instance on every request
77
+ kernel.registerServiceFactory(
78
+ 'request-id',
79
+ () => generateUUID(),
80
+ ServiceLifecycle.TRANSIENT
81
+ );
82
+
83
+ // Scoped: One instance per scope (e.g., per HTTP request)
84
+ kernel.registerServiceFactory(
85
+ 'user-session',
86
+ async (ctx) => {
87
+ return new UserSession();
88
+ },
89
+ ServiceLifecycle.SCOPED
90
+ );
91
+
92
+ // Get service (async)
93
+ const db = await kernel.getServiceAsync('database');
94
+
95
+ // Get scoped service
96
+ const session = await kernel.getServiceAsync('user-session', 'request-123');
97
+ ```
98
+
99
+ ### 3. Service Dependencies
100
+
101
+ Declare service dependencies for proper initialization order:
102
+
103
+ ```typescript
104
+ kernel.registerServiceFactory(
105
+ 'api-client',
106
+ async (ctx) => {
107
+ const auth = await ctx.getService('auth-service');
108
+ return new ApiClient(auth);
109
+ },
110
+ ServiceLifecycle.SINGLETON,
111
+ ['auth-service'] // Dependencies
112
+ );
113
+
114
+ // Detect circular dependencies
115
+ const cycles = kernel['pluginLoader'].detectCircularDependencies();
116
+ if (cycles.length > 0) {
117
+ console.error('Circular dependencies detected:', cycles);
118
+ }
119
+ ```
120
+
121
+ ### 4. Plugin Timeout Control
122
+
123
+ Prevent plugins from hanging during startup:
124
+
125
+ ```typescript
126
+ const plugin: PluginMetadata = {
127
+ name: 'slow-plugin',
128
+ version: '1.0.0',
129
+ startupTimeout: 5000, // 5 second timeout
130
+
131
+ async init(ctx) {
132
+ // If this takes longer than 5s, it will timeout
133
+ await slowInitialization();
134
+ }
135
+ };
136
+
137
+ await kernel.use(plugin);
138
+
139
+ try {
140
+ await kernel.bootstrap();
141
+ } catch (error) {
142
+ // Error: Plugin slow-plugin init timeout after 5000ms
143
+ }
144
+ ```
145
+
146
+ ### 5. Startup Failure Rollback
147
+
148
+ Automatically rollback started plugins if any plugin fails:
149
+
150
+ ```typescript
151
+ const plugin1: Plugin = {
152
+ name: 'plugin-1',
153
+ version: '1.0.0',
154
+ async init() {},
155
+ async start() {
156
+ // Starts successfully
157
+ },
158
+ async destroy() {
159
+ console.log('Rolling back plugin-1');
160
+ }
161
+ };
162
+
163
+ const plugin2: Plugin = {
164
+ name: 'plugin-2',
165
+ version: '1.0.0',
166
+ async init() {},
167
+ async start() {
168
+ throw new Error('Startup failed!');
169
+ }
170
+ };
171
+
172
+ await kernel.use(plugin1);
173
+ await kernel.use(plugin2);
174
+
175
+ try {
176
+ await kernel.bootstrap();
177
+ } catch (error) {
178
+ // plugin-1 will be automatically destroyed (rolled back)
179
+ // Error: Plugin plugin-2 failed to start - rollback complete
180
+ }
181
+ ```
182
+
183
+ ### 6. Plugin Health Checks
184
+
185
+ Monitor plugin health at runtime:
186
+
187
+ ```typescript
188
+ const plugin: PluginMetadata = {
189
+ name: 'database-plugin',
190
+ version: '1.0.0',
191
+
192
+ async init(ctx) {
193
+ // Initialize database connection
194
+ },
195
+
196
+ async healthCheck() {
197
+ const isConnected = await checkDatabaseConnection();
198
+ return {
199
+ healthy: isConnected,
200
+ message: isConnected ? 'Connected' : 'Disconnected',
201
+ details: {
202
+ connections: 10,
203
+ responseTime: 50
204
+ }
205
+ };
206
+ }
207
+ };
208
+
209
+ await kernel.use(plugin);
210
+ await kernel.bootstrap();
211
+
212
+ // Check individual plugin health
213
+ const health = await kernel.checkPluginHealth('database-plugin');
214
+ console.log(health);
215
+ // { healthy: true, message: 'Connected', details: {...}, lastCheck: Date }
216
+
217
+ // Check all plugins health
218
+ const allHealth = await kernel.checkAllPluginsHealth();
219
+ for (const [pluginName, health] of allHealth) {
220
+ console.log(`${pluginName}: ${health.healthy ? '✅' : '❌'}`);
221
+ }
222
+ ```
223
+
224
+ ### 7. Performance Metrics
225
+
226
+ Track plugin startup times:
227
+
228
+ ```typescript
229
+ await kernel.bootstrap();
230
+
231
+ const metrics = kernel.getPluginMetrics();
232
+ for (const [pluginName, startTime] of metrics) {
233
+ console.log(`${pluginName}: ${startTime}ms`);
234
+ }
235
+ // plugin-1: 150ms
236
+ // plugin-2: 320ms
237
+ // plugin-3: 45ms
238
+ ```
239
+
240
+ ### 8. Graceful Shutdown
241
+
242
+ Properly cleanup resources on shutdown:
243
+
244
+ ```typescript
245
+ const kernel = new EnhancedObjectKernel({
246
+ gracefulShutdown: true,
247
+ shutdownTimeout: 60000 // 60 second timeout
248
+ });
249
+
250
+ // Register custom shutdown handler
251
+ kernel.onShutdown(async () => {
252
+ console.log('Closing database connections...');
253
+ await db.close();
254
+ });
255
+
256
+ // Graceful shutdown
257
+ process.on('SIGTERM', async () => {
258
+ await kernel.shutdown();
259
+ process.exit(0);
260
+ });
261
+
262
+ // Manual shutdown
263
+ await kernel.shutdown();
264
+ // Triggers:
265
+ // 1. kernel:shutdown hook
266
+ // 2. Plugin destroy() in reverse order
267
+ // 3. Custom shutdown handlers
268
+ // 4. Logger cleanup
269
+ ```
270
+
271
+ ### 9. Version Compatibility
272
+
273
+ Plugins must use semantic versioning:
274
+
275
+ ```typescript
276
+ // Valid versions
277
+ '1.0.0'
278
+ '2.3.4'
279
+ '1.0.0-alpha.1'
280
+ '1.0.0+20230101'
281
+
282
+ // Invalid versions (will be rejected)
283
+ '1.0'
284
+ 'v1.0.0'
285
+ 'latest'
286
+ ```
287
+
288
+ ### 10. Plugin Configuration Validation
289
+
290
+ Use Zod schemas to validate plugin configuration:
291
+
292
+ ```typescript
293
+ import { z } from 'zod';
294
+
295
+ const MyPluginConfigSchema = z.object({
296
+ apiKey: z.string(),
297
+ timeout: z.number().min(1000).max(30000),
298
+ retries: z.number().int().min(0).default(3)
299
+ });
300
+
301
+ const plugin: PluginMetadata = {
302
+ name: 'my-plugin',
303
+ version: '1.0.0',
304
+ configSchema: MyPluginConfigSchema,
305
+
306
+ async init(ctx) {
307
+ // Config is validated before init is called
308
+ }
309
+ };
310
+ ```
311
+
312
+ ## Migration from ObjectKernel
313
+
314
+ To migrate from `ObjectKernel` to `EnhancedObjectKernel`:
315
+
316
+ ```typescript
317
+ // Before
318
+ import { ObjectKernel } from '@objectstack/core';
319
+ const kernel = new ObjectKernel();
320
+
321
+ // After
322
+ import { EnhancedObjectKernel } from '@objectstack/core';
323
+ const kernel = new EnhancedObjectKernel({
324
+ logger: { level: 'info' },
325
+ gracefulShutdown: true,
326
+ rollbackOnFailure: true
327
+ });
328
+ ```
329
+
330
+ Both kernels are compatible - `EnhancedObjectKernel` is a superset of `ObjectKernel`.
331
+
332
+ ## Best Practices
333
+
334
+ 1. **Always set timeouts**: Configure `startupTimeout` to prevent hanging plugins
335
+ 2. **Implement health checks**: Monitor plugin health at runtime
336
+ 3. **Use semantic versioning**: Ensures compatibility and proper dependency resolution
337
+ 4. **Enable rollback**: Set `rollbackOnFailure: true` to prevent partial startup states
338
+ 5. **Handle shutdown**: Implement `destroy()` to cleanup resources properly
339
+ 6. **Monitor metrics**: Track startup times to identify slow plugins
340
+ 7. **Use service factories**: Prefer factories over static instances for better control
341
+ 8. **Declare dependencies**: Use the dependencies array for proper initialization order
342
+
343
+ ## API Reference
344
+
345
+ ### EnhancedObjectKernel
346
+
347
+ - `constructor(config: EnhancedKernelConfig)`
348
+ - `async use(plugin: Plugin): Promise<this>`
349
+ - `registerServiceFactory<T>(name, factory, lifecycle, dependencies?): this`
350
+ - `async bootstrap(): Promise<void>`
351
+ - `async shutdown(): Promise<void>`
352
+ - `async checkPluginHealth(pluginName: string): Promise<PluginHealthStatus>`
353
+ - `async checkAllPluginsHealth(): Promise<Map<string, PluginHealthStatus>>`
354
+ - `getPluginMetrics(): Map<string, number>`
355
+ - `async getServiceAsync<T>(name: string, scopeId?: string): Promise<T>`
356
+ - `onShutdown(handler: () => Promise<void>): void`
357
+ - `getState(): string`
358
+ - `isRunning(): boolean`
359
+
360
+ ### ServiceLifecycle
361
+
362
+ - `SINGLETON`: Single instance shared across all requests
363
+ - `TRANSIENT`: New instance created for each request
364
+ - `SCOPED`: New instance per scope (e.g., per HTTP request)
365
+
366
+ ### PluginMetadata
367
+
368
+ Extended `Plugin` interface with:
369
+ - `version: string` - Semantic version
370
+ - `configSchema?: z.ZodSchema` - Configuration schema
371
+ - `signature?: string` - Plugin signature for verification
372
+ - `healthCheck?(): Promise<PluginHealthStatus>` - Health check function
373
+ - `startupTimeout?: number` - Startup timeout in milliseconds
374
+ - `hotReloadable?: boolean` - Whether plugin supports hot reload
375
+
376
+ ## Examples
377
+
378
+ See the test files for comprehensive examples:
379
+ - `packages/core/src/enhanced-kernel.test.ts`
380
+ - `packages/core/src/plugin-loader.test.ts`