@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
@@ -0,0 +1,219 @@
1
+ /**
2
+ * ObjectKernelBase - Abstract Base Class for Microkernel
3
+ *
4
+ * Provides common functionality for both ObjectKernel and EnhancedObjectKernel:
5
+ * - Plugin management (Map storage)
6
+ * - Dependency resolution (topological sort)
7
+ * - Hook/Event system
8
+ * - Context creation
9
+ * - State validation
10
+ *
11
+ * This eliminates ~120 lines of duplicate code between the two implementations.
12
+ */
13
+ export class ObjectKernelBase {
14
+ constructor(logger) {
15
+ this.plugins = new Map();
16
+ this.services = new Map();
17
+ this.hooks = new Map();
18
+ this.state = 'idle';
19
+ this.logger = logger;
20
+ }
21
+ /**
22
+ * Validate kernel state
23
+ * @param requiredState - Required state for the operation
24
+ * @throws Error if current state doesn't match
25
+ */
26
+ validateState(requiredState) {
27
+ if (this.state !== requiredState) {
28
+ throw new Error(`[Kernel] Invalid state: expected '${requiredState}', got '${this.state}'`);
29
+ }
30
+ }
31
+ /**
32
+ * Validate kernel is in idle state (for plugin registration)
33
+ */
34
+ validateIdle() {
35
+ if (this.state !== 'idle') {
36
+ throw new Error('[Kernel] Cannot register plugins after bootstrap has started');
37
+ }
38
+ }
39
+ /**
40
+ * Create the plugin context
41
+ * Subclasses can override to customize context creation
42
+ */
43
+ createContext() {
44
+ return {
45
+ registerService: (name, service) => {
46
+ if (this.services instanceof Map) {
47
+ if (this.services.has(name)) {
48
+ throw new Error(`[Kernel] Service '${name}' already registered`);
49
+ }
50
+ this.services.set(name, service);
51
+ }
52
+ else {
53
+ // IServiceRegistry implementation
54
+ this.services.register(name, service);
55
+ }
56
+ this.logger.info(`Service '${name}' registered`, { service: name });
57
+ },
58
+ getService: (name) => {
59
+ if (this.services instanceof Map) {
60
+ const service = this.services.get(name);
61
+ if (!service) {
62
+ throw new Error(`[Kernel] Service '${name}' not found`);
63
+ }
64
+ return service;
65
+ }
66
+ else {
67
+ // IServiceRegistry implementation
68
+ return this.services.get(name);
69
+ }
70
+ },
71
+ hook: (name, handler) => {
72
+ if (!this.hooks.has(name)) {
73
+ this.hooks.set(name, []);
74
+ }
75
+ this.hooks.get(name).push(handler);
76
+ },
77
+ trigger: async (name, ...args) => {
78
+ const handlers = this.hooks.get(name) || [];
79
+ for (const handler of handlers) {
80
+ await handler(...args);
81
+ }
82
+ },
83
+ getServices: () => {
84
+ if (this.services instanceof Map) {
85
+ return new Map(this.services);
86
+ }
87
+ else {
88
+ // For IServiceRegistry, we need to return the underlying Map
89
+ // This is a compatibility method
90
+ return new Map();
91
+ }
92
+ },
93
+ logger: this.logger,
94
+ getKernel: () => this,
95
+ };
96
+ }
97
+ /**
98
+ * Resolve plugin dependencies using topological sort
99
+ * @returns Ordered list of plugins (dependencies first)
100
+ */
101
+ resolveDependencies() {
102
+ const resolved = [];
103
+ const visited = new Set();
104
+ const visiting = new Set();
105
+ const visit = (pluginName) => {
106
+ if (visited.has(pluginName))
107
+ return;
108
+ if (visiting.has(pluginName)) {
109
+ throw new Error(`[Kernel] Circular dependency detected: ${pluginName}`);
110
+ }
111
+ const plugin = this.plugins.get(pluginName);
112
+ if (!plugin) {
113
+ throw new Error(`[Kernel] Plugin '${pluginName}' not found`);
114
+ }
115
+ visiting.add(pluginName);
116
+ // Visit dependencies first
117
+ const deps = plugin.dependencies || [];
118
+ for (const dep of deps) {
119
+ if (!this.plugins.has(dep)) {
120
+ throw new Error(`[Kernel] Dependency '${dep}' not found for plugin '${pluginName}'`);
121
+ }
122
+ visit(dep);
123
+ }
124
+ visiting.delete(pluginName);
125
+ visited.add(pluginName);
126
+ resolved.push(plugin);
127
+ };
128
+ // Visit all plugins
129
+ for (const pluginName of this.plugins.keys()) {
130
+ visit(pluginName);
131
+ }
132
+ return resolved;
133
+ }
134
+ /**
135
+ * Run plugin init phase
136
+ * @param plugin - Plugin to initialize
137
+ */
138
+ async runPluginInit(plugin) {
139
+ const pluginName = plugin.name;
140
+ this.logger.info(`Initializing plugin: ${pluginName}`);
141
+ try {
142
+ await plugin.init(this.context);
143
+ this.logger.info(`Plugin initialized: ${pluginName}`);
144
+ }
145
+ catch (error) {
146
+ this.logger.error(`Plugin init failed: ${pluginName}`, error);
147
+ throw error;
148
+ }
149
+ }
150
+ /**
151
+ * Run plugin start phase
152
+ * @param plugin - Plugin to start
153
+ */
154
+ async runPluginStart(plugin) {
155
+ if (!plugin.start)
156
+ return;
157
+ const pluginName = plugin.name;
158
+ this.logger.info(`Starting plugin: ${pluginName}`);
159
+ try {
160
+ await plugin.start(this.context);
161
+ this.logger.info(`Plugin started: ${pluginName}`);
162
+ }
163
+ catch (error) {
164
+ this.logger.error(`Plugin start failed: ${pluginName}`, error);
165
+ throw error;
166
+ }
167
+ }
168
+ /**
169
+ * Run plugin destroy phase
170
+ * @param plugin - Plugin to destroy
171
+ */
172
+ async runPluginDestroy(plugin) {
173
+ if (!plugin.destroy)
174
+ return;
175
+ const pluginName = plugin.name;
176
+ this.logger.info(`Destroying plugin: ${pluginName}`);
177
+ try {
178
+ await plugin.destroy();
179
+ this.logger.info(`Plugin destroyed: ${pluginName}`);
180
+ }
181
+ catch (error) {
182
+ this.logger.error(`Plugin destroy failed: ${pluginName}`, error);
183
+ throw error;
184
+ }
185
+ }
186
+ /**
187
+ * Trigger a hook with all registered handlers
188
+ * @param name - Hook name
189
+ * @param args - Arguments to pass to handlers
190
+ */
191
+ async triggerHook(name, ...args) {
192
+ const handlers = this.hooks.get(name) || [];
193
+ this.logger.debug(`Triggering hook: ${name}`, {
194
+ hook: name,
195
+ handlerCount: handlers.length
196
+ });
197
+ for (const handler of handlers) {
198
+ try {
199
+ await handler(...args);
200
+ }
201
+ catch (error) {
202
+ this.logger.error(`Hook handler failed: ${name}`, error);
203
+ // Continue with other handlers even if one fails
204
+ }
205
+ }
206
+ }
207
+ /**
208
+ * Get current kernel state
209
+ */
210
+ getState() {
211
+ return this.state;
212
+ }
213
+ /**
214
+ * Get all registered plugins
215
+ */
216
+ getPlugins() {
217
+ return new Map(this.plugins);
218
+ }
219
+ }
package/dist/kernel.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { Plugin } from './types.js';
2
+ import type { LoggerConfig } from '@objectstack/spec/system';
3
+ import { ObjectKernelBase } from './kernel-base.js';
2
4
  /**
3
5
  * ObjectKernel - MiniKernel Architecture
4
6
  *
@@ -7,31 +9,22 @@ import { Plugin } from './types.js';
7
9
  * - Provides dependency injection via service registry
8
10
  * - Implements event/hook system for inter-plugin communication
9
11
  * - Handles dependency resolution (topological sort)
12
+ * - Provides configurable logging for server and browser
10
13
  *
11
14
  * Core philosophy:
12
15
  * - Business logic is completely separated into plugins
13
16
  * - Kernel only manages lifecycle, DI, and hooks
14
17
  * - Plugins are loaded as equal building blocks
15
18
  */
16
- export declare class ObjectKernel {
17
- private plugins;
18
- private services;
19
- private hooks;
20
- private state;
21
- /**
22
- * Plugin context - shared across all plugins
23
- */
24
- private context;
19
+ export declare class ObjectKernel extends ObjectKernelBase {
20
+ constructor(config?: {
21
+ logger?: Partial<LoggerConfig>;
22
+ });
25
23
  /**
26
24
  * Register a plugin
27
25
  * @param plugin - Plugin instance
28
26
  */
29
27
  use(plugin: Plugin): this;
30
- /**
31
- * Resolve plugin dependencies using topological sort
32
- * @returns Ordered list of plugins
33
- */
34
- private resolveDependencies;
35
28
  /**
36
29
  * Bootstrap the kernel
37
30
  * 1. Resolve dependencies (topological sort)
@@ -45,6 +38,10 @@ export declare class ObjectKernel {
45
38
  * Calls destroy on all plugins in reverse order
46
39
  */
47
40
  shutdown(): Promise<void>;
41
+ /**
42
+ * Graceful shutdown - destroy all plugins in reverse order
43
+ */
44
+ destroy(): Promise<void>;
48
45
  /**
49
46
  * Get a service from the registry
50
47
  * Convenience method for external access
@@ -54,9 +51,5 @@ export declare class ObjectKernel {
54
51
  * Check if kernel is running
55
52
  */
56
53
  isRunning(): boolean;
57
- /**
58
- * Get kernel state
59
- */
60
- getState(): string;
61
54
  }
62
55
  //# sourceMappingURL=kernel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../src/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAY;IACrB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,KAAK,CAA2E;IACxF,OAAO,CAAC,KAAK,CAA2D;IAExE;;OAEG;IACH,OAAO,CAAC,OAAO,CAgCb;IAEF;;;OAGG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM;IAclB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAyC3B;;;;;;OAMG;IACG,SAAS;IAmCf;;;OAGG;IACG,QAAQ;IAmBd;;;OAGG;IACH,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC;IAI9B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGrB"}
1
+ {"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../src/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,SAAQ,gBAAgB;gBAClC,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;KAAE;IAQvD;;;OAGG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAYzB;;;;;;OAMG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BhC;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B9B;;;OAGG;IACH,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC;IAI9B;;OAEG;IACH,SAAS,IAAI,OAAO;CAGvB"}
package/dist/kernel.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { createLogger } from './logger.js';
2
+ import { ObjectKernelBase } from './kernel-base.js';
1
3
  /**
2
4
  * ObjectKernel - MiniKernel Architecture
3
5
  *
@@ -6,63 +8,26 @@
6
8
  * - Provides dependency injection via service registry
7
9
  * - Implements event/hook system for inter-plugin communication
8
10
  * - Handles dependency resolution (topological sort)
11
+ * - Provides configurable logging for server and browser
9
12
  *
10
13
  * Core philosophy:
11
14
  * - Business logic is completely separated into plugins
12
15
  * - Kernel only manages lifecycle, DI, and hooks
13
16
  * - Plugins are loaded as equal building blocks
14
17
  */
15
- export class ObjectKernel {
16
- constructor() {
17
- this.plugins = new Map();
18
- this.services = new Map();
19
- this.hooks = new Map();
20
- this.state = 'idle';
21
- /**
22
- * Plugin context - shared across all plugins
23
- */
24
- this.context = {
25
- registerService: (name, service) => {
26
- if (this.services.has(name)) {
27
- throw new Error(`[Kernel] Service '${name}' already registered`);
28
- }
29
- this.services.set(name, service);
30
- this.context.logger.log(`[Kernel] Service '${name}' registered`);
31
- },
32
- getService: (name) => {
33
- const service = this.services.get(name);
34
- if (!service) {
35
- throw new Error(`[Kernel] Service '${name}' not found`);
36
- }
37
- return service;
38
- },
39
- hook: (name, handler) => {
40
- if (!this.hooks.has(name)) {
41
- this.hooks.set(name, []);
42
- }
43
- this.hooks.get(name).push(handler);
44
- },
45
- trigger: async (name, ...args) => {
46
- const handlers = this.hooks.get(name) || [];
47
- for (const handler of handlers) {
48
- await handler(...args);
49
- }
50
- },
51
- getServices: () => {
52
- return new Map(this.services);
53
- },
54
- logger: console,
55
- getKernel: () => this,
56
- };
18
+ export class ObjectKernel extends ObjectKernelBase {
19
+ constructor(config) {
20
+ const logger = createLogger(config?.logger);
21
+ super(logger);
22
+ // Initialize context after logger is created
23
+ this.context = this.createContext();
57
24
  }
58
25
  /**
59
26
  * Register a plugin
60
27
  * @param plugin - Plugin instance
61
28
  */
62
29
  use(plugin) {
63
- if (this.state !== 'idle') {
64
- throw new Error('[Kernel] Cannot register plugins after bootstrap has started');
65
- }
30
+ this.validateIdle();
66
31
  const pluginName = plugin.name;
67
32
  if (this.plugins.has(pluginName)) {
68
33
  throw new Error(`[Kernel] Plugin '${pluginName}' already registered`);
@@ -70,43 +35,6 @@ export class ObjectKernel {
70
35
  this.plugins.set(pluginName, plugin);
71
36
  return this;
72
37
  }
73
- /**
74
- * Resolve plugin dependencies using topological sort
75
- * @returns Ordered list of plugins
76
- */
77
- resolveDependencies() {
78
- const resolved = [];
79
- const visited = new Set();
80
- const visiting = new Set();
81
- const visit = (pluginName) => {
82
- if (visited.has(pluginName))
83
- return;
84
- if (visiting.has(pluginName)) {
85
- throw new Error(`[Kernel] Circular dependency detected: ${pluginName}`);
86
- }
87
- const plugin = this.plugins.get(pluginName);
88
- if (!plugin) {
89
- throw new Error(`[Kernel] Plugin '${pluginName}' not found`);
90
- }
91
- visiting.add(pluginName);
92
- // Visit dependencies first
93
- const deps = plugin.dependencies || [];
94
- for (const dep of deps) {
95
- if (!this.plugins.has(dep)) {
96
- throw new Error(`[Kernel] Dependency '${dep}' not found for plugin '${pluginName}'`);
97
- }
98
- visit(dep);
99
- }
100
- visiting.delete(pluginName);
101
- visited.add(pluginName);
102
- resolved.push(plugin);
103
- };
104
- // Visit all plugins
105
- for (const pluginName of this.plugins.keys()) {
106
- visit(pluginName);
107
- }
108
- return resolved;
109
- }
110
38
  /**
111
39
  * Bootstrap the kernel
112
40
  * 1. Resolve dependencies (topological sort)
@@ -115,51 +43,58 @@ export class ObjectKernel {
115
43
  * 4. Trigger 'kernel:ready' hook
116
44
  */
117
45
  async bootstrap() {
118
- if (this.state !== 'idle') {
119
- throw new Error('[Kernel] Kernel already bootstrapped');
120
- }
46
+ this.validateState('idle');
121
47
  this.state = 'initializing';
122
- this.context.logger.log('[Kernel] Bootstrap started...');
48
+ this.logger.info('Bootstrap started');
123
49
  // Resolve dependencies
124
50
  const orderedPlugins = this.resolveDependencies();
125
51
  // Phase 1: Init - Plugins register services
126
- this.context.logger.log('[Kernel] Phase 1: Init plugins...');
52
+ this.logger.info('Phase 1: Init plugins');
127
53
  for (const plugin of orderedPlugins) {
128
- this.context.logger.log(`[Kernel] Init: ${plugin.name}`);
129
- await plugin.init(this.context);
54
+ await this.runPluginInit(plugin);
130
55
  }
131
56
  // Phase 2: Start - Plugins execute business logic
132
- this.context.logger.log('[Kernel] Phase 2: Start plugins...');
57
+ this.logger.info('Phase 2: Start plugins');
133
58
  this.state = 'running';
134
59
  for (const plugin of orderedPlugins) {
135
- if (plugin.start) {
136
- this.context.logger.log(`[Kernel] Start: ${plugin.name}`);
137
- await plugin.start(this.context);
138
- }
60
+ await this.runPluginStart(plugin);
139
61
  }
140
- // Phase 3: Trigger kernel:ready hook
141
- this.context.logger.log('[Kernel] Triggering kernel:ready hook...');
142
- await this.context.trigger('kernel:ready');
143
- this.context.logger.log('[Kernel] ✅ Bootstrap complete');
62
+ // Trigger ready hook
63
+ await this.triggerHook('kernel:ready');
64
+ this.logger.info('✅ Bootstrap complete', {
65
+ pluginCount: this.plugins.size
66
+ });
144
67
  }
145
68
  /**
146
69
  * Shutdown the kernel
147
70
  * Calls destroy on all plugins in reverse order
148
71
  */
149
72
  async shutdown() {
150
- if (this.state !== 'running') {
151
- throw new Error('[Kernel] Kernel not running');
73
+ await this.destroy();
74
+ }
75
+ /**
76
+ * Graceful shutdown - destroy all plugins in reverse order
77
+ */
78
+ async destroy() {
79
+ if (this.state === 'stopped') {
80
+ this.logger.warn('Kernel already stopped');
81
+ return;
82
+ }
83
+ this.state = 'stopping';
84
+ this.logger.info('Shutdown started');
85
+ // Trigger shutdown hook
86
+ await this.triggerHook('kernel:shutdown');
87
+ // Destroy plugins in reverse order
88
+ const orderedPlugins = this.resolveDependencies();
89
+ for (const plugin of orderedPlugins.reverse()) {
90
+ await this.runPluginDestroy(plugin);
152
91
  }
153
- this.context.logger.log('[Kernel] Shutdown started...');
154
92
  this.state = 'stopped';
155
- const orderedPlugins = Array.from(this.plugins.values()).reverse();
156
- for (const plugin of orderedPlugins) {
157
- if (plugin.destroy) {
158
- this.context.logger.log(`[Kernel] Destroy: ${plugin.name}`);
159
- await plugin.destroy();
160
- }
93
+ this.logger.info('✅ Shutdown complete');
94
+ // Cleanup logger resources
95
+ if (this.logger && typeof this.logger.destroy === 'function') {
96
+ await this.logger.destroy();
161
97
  }
162
- this.context.logger.log('[Kernel] ✅ Shutdown complete');
163
98
  }
164
99
  /**
165
100
  * Get a service from the registry
@@ -174,10 +109,4 @@ export class ObjectKernel {
174
109
  isRunning() {
175
110
  return this.state === 'running';
176
111
  }
177
- /**
178
- * Get kernel state
179
- */
180
- getState() {
181
- return this.state;
182
- }
183
112
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=kernel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel.test.d.ts","sourceRoot":"","sources":["../src/kernel.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,161 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { ObjectKernel } from './kernel';
3
+ describe('ObjectKernel with Configurable Logger', () => {
4
+ let kernel;
5
+ beforeEach(() => {
6
+ kernel = new ObjectKernel();
7
+ });
8
+ describe('Logger Configuration', () => {
9
+ it('should create kernel with default logger', () => {
10
+ expect(kernel).toBeDefined();
11
+ });
12
+ it('should create kernel with custom logger config', async () => {
13
+ const customKernel = new ObjectKernel({
14
+ logger: {
15
+ level: 'debug',
16
+ format: 'pretty',
17
+ sourceLocation: true
18
+ }
19
+ });
20
+ expect(customKernel).toBeDefined();
21
+ // Cleanup
22
+ await customKernel.bootstrap();
23
+ await customKernel.shutdown();
24
+ });
25
+ it('should create kernel with file logging config', async () => {
26
+ const fileKernel = new ObjectKernel({
27
+ logger: {
28
+ level: 'info',
29
+ format: 'json',
30
+ file: '/tmp/test-kernel.log'
31
+ }
32
+ });
33
+ expect(fileKernel).toBeDefined();
34
+ // Cleanup
35
+ await fileKernel.bootstrap();
36
+ await fileKernel.shutdown();
37
+ });
38
+ });
39
+ describe('Plugin Context Logger', () => {
40
+ it('should provide logger to plugins', async () => {
41
+ let loggerReceived = false;
42
+ const testPlugin = {
43
+ name: 'test-plugin',
44
+ init: async (ctx) => {
45
+ if (ctx.logger) {
46
+ loggerReceived = true;
47
+ ctx.logger.info('Plugin initialized', { plugin: 'test-plugin' });
48
+ }
49
+ }
50
+ };
51
+ kernel.use(testPlugin);
52
+ await kernel.bootstrap();
53
+ expect(loggerReceived).toBe(true);
54
+ await kernel.shutdown();
55
+ });
56
+ it('should allow plugins to use all log levels', async () => {
57
+ const logCalls = [];
58
+ const loggingPlugin = {
59
+ name: 'logging-plugin',
60
+ init: async (ctx) => {
61
+ ctx.logger.debug('Debug message');
62
+ logCalls.push('debug');
63
+ ctx.logger.info('Info message');
64
+ logCalls.push('info');
65
+ ctx.logger.warn('Warning message');
66
+ logCalls.push('warn');
67
+ ctx.logger.error('Error message');
68
+ logCalls.push('error');
69
+ }
70
+ };
71
+ kernel.use(loggingPlugin);
72
+ await kernel.bootstrap();
73
+ expect(logCalls).toContain('debug');
74
+ expect(logCalls).toContain('info');
75
+ expect(logCalls).toContain('warn');
76
+ expect(logCalls).toContain('error');
77
+ await kernel.shutdown();
78
+ });
79
+ it('should support metadata in logs', async () => {
80
+ const metadataPlugin = {
81
+ name: 'metadata-plugin',
82
+ init: async (ctx) => {
83
+ ctx.logger.info('User action', {
84
+ userId: '123',
85
+ action: 'create',
86
+ resource: 'document'
87
+ });
88
+ }
89
+ };
90
+ kernel.use(metadataPlugin);
91
+ await kernel.bootstrap();
92
+ await kernel.shutdown();
93
+ });
94
+ });
95
+ describe('Kernel Lifecycle Logging', () => {
96
+ it('should log bootstrap process', async () => {
97
+ const plugin = {
98
+ name: 'lifecycle-test',
99
+ init: async () => {
100
+ // Init logic
101
+ },
102
+ start: async () => {
103
+ // Start logic
104
+ }
105
+ };
106
+ kernel.use(plugin);
107
+ await kernel.bootstrap();
108
+ expect(kernel.isRunning()).toBe(true);
109
+ await kernel.shutdown();
110
+ });
111
+ it('should log shutdown process', async () => {
112
+ const plugin = {
113
+ name: 'shutdown-test',
114
+ init: async () => { },
115
+ destroy: async () => {
116
+ // Cleanup
117
+ }
118
+ };
119
+ kernel.use(plugin);
120
+ await kernel.bootstrap();
121
+ await kernel.shutdown();
122
+ expect(kernel.getState()).toBe('stopped');
123
+ });
124
+ });
125
+ describe('Environment Compatibility', () => {
126
+ it('should work in Node.js environment', async () => {
127
+ const nodeKernel = new ObjectKernel({
128
+ logger: {
129
+ level: 'info',
130
+ format: 'json'
131
+ }
132
+ });
133
+ const plugin = {
134
+ name: 'node-test',
135
+ init: async (ctx) => {
136
+ ctx.logger.info('Running in Node.js');
137
+ }
138
+ };
139
+ nodeKernel.use(plugin);
140
+ await nodeKernel.bootstrap();
141
+ await nodeKernel.shutdown();
142
+ });
143
+ it('should support browser-friendly logging', async () => {
144
+ const browserKernel = new ObjectKernel({
145
+ logger: {
146
+ level: 'info',
147
+ format: 'pretty'
148
+ }
149
+ });
150
+ const plugin = {
151
+ name: 'browser-test',
152
+ init: async (ctx) => {
153
+ ctx.logger.info('Browser-friendly format');
154
+ }
155
+ };
156
+ browserKernel.use(plugin);
157
+ await browserKernel.bootstrap();
158
+ await browserKernel.shutdown();
159
+ });
160
+ });
161
+ });