@objectstack/core 4.0.4 → 4.0.5
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/README.md +95 -10
- package/dist/index.cjs +169 -507
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -223
- package/dist/index.d.ts +24 -223
- package/dist/index.js +175 -505
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +177 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +26 -0
- package/dist/logger.d.ts +26 -0
- package/dist/logger.js +158 -0
- package/dist/logger.js.map +1 -0
- package/package.json +36 -15
- package/.turbo/turbo-build.log +0 -22
- package/ADVANCED_FEATURES.md +0 -380
- package/API_REGISTRY.md +0 -392
- package/CHANGELOG.md +0 -472
- package/PHASE2_IMPLEMENTATION.md +0 -388
- package/REFACTORING_SUMMARY.md +0 -40
- package/examples/api-registry-example.ts +0 -559
- package/examples/kernel-features-example.ts +0 -311
- package/examples/phase2-integration.ts +0 -357
- package/src/api-registry-plugin.test.ts +0 -393
- package/src/api-registry-plugin.ts +0 -89
- package/src/api-registry.test.ts +0 -1089
- package/src/api-registry.ts +0 -739
- package/src/contracts/data-engine.ts +0 -57
- package/src/contracts/http-server.ts +0 -151
- package/src/contracts/logger.ts +0 -72
- package/src/dependency-resolver.test.ts +0 -287
- package/src/dependency-resolver.ts +0 -390
- package/src/fallbacks/fallbacks.test.ts +0 -281
- package/src/fallbacks/index.ts +0 -26
- package/src/fallbacks/memory-cache.ts +0 -34
- package/src/fallbacks/memory-i18n.ts +0 -112
- package/src/fallbacks/memory-job.ts +0 -23
- package/src/fallbacks/memory-metadata.ts +0 -50
- package/src/fallbacks/memory-queue.ts +0 -28
- package/src/health-monitor.test.ts +0 -81
- package/src/health-monitor.ts +0 -318
- package/src/hot-reload.ts +0 -382
- package/src/index.ts +0 -50
- package/src/kernel-base.ts +0 -273
- package/src/kernel.test.ts +0 -624
- package/src/kernel.ts +0 -631
- package/src/lite-kernel.test.ts +0 -248
- package/src/lite-kernel.ts +0 -137
- package/src/logger.test.ts +0 -116
- package/src/logger.ts +0 -355
- package/src/namespace-resolver.test.ts +0 -130
- package/src/namespace-resolver.ts +0 -188
- package/src/package-manager.test.ts +0 -225
- package/src/package-manager.ts +0 -428
- package/src/plugin-loader.test.ts +0 -421
- package/src/plugin-loader.ts +0 -484
- package/src/qa/adapter.ts +0 -16
- package/src/qa/http-adapter.ts +0 -116
- package/src/qa/index.ts +0 -5
- package/src/qa/runner.ts +0 -189
- package/src/security/index.ts +0 -50
- package/src/security/permission-manager.test.ts +0 -256
- package/src/security/permission-manager.ts +0 -338
- package/src/security/plugin-config-validator.test.ts +0 -276
- package/src/security/plugin-config-validator.ts +0 -193
- package/src/security/plugin-permission-enforcer.test.ts +0 -251
- package/src/security/plugin-permission-enforcer.ts +0 -436
- package/src/security/plugin-signature-verifier.ts +0 -403
- package/src/security/sandbox-runtime.ts +0 -462
- package/src/security/security-scanner.ts +0 -367
- package/src/types.ts +0 -120
- package/src/utils/env.test.ts +0 -62
- package/src/utils/env.ts +0 -53
- package/tsconfig.json +0 -10
- package/vitest.config.ts +0 -10
package/src/lite-kernel.test.ts
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { LiteKernel } from './lite-kernel';
|
|
3
|
-
import type { Plugin } from './types';
|
|
4
|
-
|
|
5
|
-
describe('LiteKernel with Configurable Logger', () => {
|
|
6
|
-
let kernel: LiteKernel;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
kernel = new LiteKernel();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe('Logger Configuration', () => {
|
|
13
|
-
it('should create kernel with default logger', () => {
|
|
14
|
-
expect(kernel).toBeDefined();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should create kernel with custom logger config', async () => {
|
|
18
|
-
const customKernel = new LiteKernel({
|
|
19
|
-
logger: {
|
|
20
|
-
level: 'debug',
|
|
21
|
-
format: 'pretty',
|
|
22
|
-
sourceLocation: true
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
expect(customKernel).toBeDefined();
|
|
27
|
-
|
|
28
|
-
// Cleanup
|
|
29
|
-
await customKernel.bootstrap();
|
|
30
|
-
await customKernel.shutdown();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should create kernel with file logging config', async () => {
|
|
34
|
-
const fileKernel = new LiteKernel({
|
|
35
|
-
logger: {
|
|
36
|
-
level: 'info',
|
|
37
|
-
format: 'json',
|
|
38
|
-
file: '/tmp/test-kernel.log'
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
expect(fileKernel).toBeDefined();
|
|
43
|
-
|
|
44
|
-
// Cleanup
|
|
45
|
-
await fileKernel.bootstrap();
|
|
46
|
-
await fileKernel.shutdown();
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('Plugin Context Logger', () => {
|
|
51
|
-
it('should provide logger to plugins', async () => {
|
|
52
|
-
let loggerReceived = false;
|
|
53
|
-
|
|
54
|
-
const testPlugin: Plugin = {
|
|
55
|
-
name: 'test-plugin',
|
|
56
|
-
init: async (ctx) => {
|
|
57
|
-
if (ctx.logger) {
|
|
58
|
-
loggerReceived = true;
|
|
59
|
-
ctx.logger.info('Plugin initialized', { plugin: 'test-plugin' });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
kernel.use(testPlugin);
|
|
65
|
-
await kernel.bootstrap();
|
|
66
|
-
|
|
67
|
-
expect(loggerReceived).toBe(true);
|
|
68
|
-
|
|
69
|
-
await kernel.shutdown();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should allow plugins to use all log levels', async () => {
|
|
73
|
-
const logCalls: string[] = [];
|
|
74
|
-
|
|
75
|
-
const loggingPlugin: Plugin = {
|
|
76
|
-
name: 'logging-plugin',
|
|
77
|
-
init: async (ctx) => {
|
|
78
|
-
ctx.logger.debug('Debug message');
|
|
79
|
-
logCalls.push('debug');
|
|
80
|
-
|
|
81
|
-
ctx.logger.info('Info message');
|
|
82
|
-
logCalls.push('info');
|
|
83
|
-
|
|
84
|
-
ctx.logger.warn('Warning message');
|
|
85
|
-
logCalls.push('warn');
|
|
86
|
-
|
|
87
|
-
ctx.logger.error('Error message');
|
|
88
|
-
logCalls.push('error');
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
kernel.use(loggingPlugin);
|
|
93
|
-
await kernel.bootstrap();
|
|
94
|
-
|
|
95
|
-
expect(logCalls).toContain('debug');
|
|
96
|
-
expect(logCalls).toContain('info');
|
|
97
|
-
expect(logCalls).toContain('warn');
|
|
98
|
-
expect(logCalls).toContain('error');
|
|
99
|
-
|
|
100
|
-
await kernel.shutdown();
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('should support metadata in logs', async () => {
|
|
104
|
-
const metadataPlugin: Plugin = {
|
|
105
|
-
name: 'metadata-plugin',
|
|
106
|
-
init: async (ctx) => {
|
|
107
|
-
ctx.logger.info('User action', {
|
|
108
|
-
userId: '123',
|
|
109
|
-
action: 'create',
|
|
110
|
-
resource: 'document'
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
kernel.use(metadataPlugin);
|
|
116
|
-
await kernel.bootstrap();
|
|
117
|
-
|
|
118
|
-
await kernel.shutdown();
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('Kernel Lifecycle Logging', () => {
|
|
123
|
-
it('should log bootstrap process', async () => {
|
|
124
|
-
const plugin: Plugin = {
|
|
125
|
-
name: 'lifecycle-test',
|
|
126
|
-
init: async () => {
|
|
127
|
-
// Init logic
|
|
128
|
-
},
|
|
129
|
-
start: async () => {
|
|
130
|
-
// Start logic
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
kernel.use(plugin);
|
|
135
|
-
await kernel.bootstrap();
|
|
136
|
-
|
|
137
|
-
expect(kernel.isRunning()).toBe(true);
|
|
138
|
-
|
|
139
|
-
await kernel.shutdown();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should log shutdown process', async () => {
|
|
143
|
-
const plugin: Plugin = {
|
|
144
|
-
name: 'shutdown-test',
|
|
145
|
-
init: async () => {},
|
|
146
|
-
destroy: async () => {
|
|
147
|
-
// Cleanup
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
kernel.use(plugin);
|
|
152
|
-
await kernel.bootstrap();
|
|
153
|
-
await kernel.shutdown();
|
|
154
|
-
|
|
155
|
-
expect(kernel.getState()).toBe('stopped');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
describe('Environment Compatibility', () => {
|
|
160
|
-
it('should work in Node.js environment', async () => {
|
|
161
|
-
const nodeKernel = new LiteKernel({
|
|
162
|
-
logger: {
|
|
163
|
-
level: 'info',
|
|
164
|
-
format: 'json'
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const plugin: Plugin = {
|
|
169
|
-
name: 'node-test',
|
|
170
|
-
init: async (ctx) => {
|
|
171
|
-
ctx.logger.info('Running in Node.js');
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
nodeKernel.use(plugin);
|
|
176
|
-
await nodeKernel.bootstrap();
|
|
177
|
-
await nodeKernel.shutdown();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should support browser-friendly logging', async () => {
|
|
181
|
-
const browserKernel = new LiteKernel({
|
|
182
|
-
logger: {
|
|
183
|
-
level: 'info',
|
|
184
|
-
format: 'pretty'
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const plugin: Plugin = {
|
|
189
|
-
name: 'browser-test',
|
|
190
|
-
init: async (ctx) => {
|
|
191
|
-
ctx.logger.info('Browser-friendly format');
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
browserKernel.use(plugin);
|
|
196
|
-
await browserKernel.bootstrap();
|
|
197
|
-
await browserKernel.shutdown();
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe('Service Replacement', () => {
|
|
202
|
-
it('should replace an existing service via replaceService', async () => {
|
|
203
|
-
const originalService = { value: 'original' };
|
|
204
|
-
const replacementService = { value: 'replaced' };
|
|
205
|
-
|
|
206
|
-
const plugin: Plugin = {
|
|
207
|
-
name: 'register-plugin',
|
|
208
|
-
init: async (ctx) => {
|
|
209
|
-
ctx.registerService('metadata', originalService);
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const optimizationPlugin: Plugin = {
|
|
214
|
-
name: 'optimization-plugin',
|
|
215
|
-
dependencies: ['register-plugin'],
|
|
216
|
-
init: async (ctx) => {
|
|
217
|
-
const existing = ctx.getService('metadata');
|
|
218
|
-
expect(existing).toBe(originalService);
|
|
219
|
-
ctx.replaceService('metadata', replacementService);
|
|
220
|
-
},
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
kernel.use(plugin);
|
|
224
|
-
kernel.use(optimizationPlugin);
|
|
225
|
-
await kernel.bootstrap();
|
|
226
|
-
|
|
227
|
-
const result = kernel.getService('metadata');
|
|
228
|
-
expect(result).toBe(replacementService);
|
|
229
|
-
|
|
230
|
-
await kernel.shutdown();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('should throw when replacing a non-existent service', async () => {
|
|
234
|
-
const plugin: Plugin = {
|
|
235
|
-
name: 'bad-replace-plugin',
|
|
236
|
-
init: async (ctx) => {
|
|
237
|
-
expect(() => {
|
|
238
|
-
ctx.replaceService('nonexistent', { value: 'test' });
|
|
239
|
-
}).toThrow("Service 'nonexistent' not found");
|
|
240
|
-
},
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
kernel.use(plugin);
|
|
244
|
-
await kernel.bootstrap();
|
|
245
|
-
await kernel.shutdown();
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
});
|
package/src/lite-kernel.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import { Plugin } from './types.js';
|
|
4
|
-
import { createLogger, ObjectLogger } from './logger.js';
|
|
5
|
-
import type { LoggerConfig } from '@objectstack/spec/system';
|
|
6
|
-
import { ObjectKernelBase } from './kernel-base.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* ObjectKernel - MiniKernel Architecture
|
|
10
|
-
*
|
|
11
|
-
* A highly modular, plugin-based microkernel that:
|
|
12
|
-
* - Manages plugin lifecycle (init, start, destroy)
|
|
13
|
-
* - Provides dependency injection via service registry
|
|
14
|
-
* - Implements event/hook system for inter-plugin communication
|
|
15
|
-
* - Handles dependency resolution (topological sort)
|
|
16
|
-
* - Provides configurable logging for server and browser
|
|
17
|
-
*
|
|
18
|
-
* Core philosophy:
|
|
19
|
-
* - Business logic is completely separated into plugins
|
|
20
|
-
* - Kernel only manages lifecycle, DI, and hooks
|
|
21
|
-
* - Plugins are loaded as equal building blocks
|
|
22
|
-
*/
|
|
23
|
-
export class LiteKernel extends ObjectKernelBase {
|
|
24
|
-
constructor(config?: { logger?: Partial<LoggerConfig> }) {
|
|
25
|
-
const logger = createLogger(config?.logger);
|
|
26
|
-
super(logger);
|
|
27
|
-
|
|
28
|
-
// Initialize context after logger is created
|
|
29
|
-
this.context = this.createContext();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Register a plugin
|
|
34
|
-
* @param plugin - Plugin instance
|
|
35
|
-
*/
|
|
36
|
-
use(plugin: Plugin): this {
|
|
37
|
-
this.validateIdle();
|
|
38
|
-
|
|
39
|
-
const pluginName = plugin.name;
|
|
40
|
-
if (this.plugins.has(pluginName)) {
|
|
41
|
-
throw new Error(`[Kernel] Plugin '${pluginName}' already registered`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.plugins.set(pluginName, plugin);
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Bootstrap the kernel
|
|
50
|
-
* 1. Resolve dependencies (topological sort)
|
|
51
|
-
* 2. Init phase - plugins register services
|
|
52
|
-
* 3. Start phase - plugins execute business logic
|
|
53
|
-
* 4. Trigger 'kernel:ready' hook
|
|
54
|
-
*/
|
|
55
|
-
async bootstrap(): Promise<void> {
|
|
56
|
-
this.validateState('idle');
|
|
57
|
-
|
|
58
|
-
this.state = 'initializing';
|
|
59
|
-
this.logger.info('Bootstrap started');
|
|
60
|
-
|
|
61
|
-
// Resolve dependencies
|
|
62
|
-
const orderedPlugins = this.resolveDependencies();
|
|
63
|
-
|
|
64
|
-
// Phase 1: Init - Plugins register services
|
|
65
|
-
this.logger.info('Phase 1: Init plugins');
|
|
66
|
-
for (const plugin of orderedPlugins) {
|
|
67
|
-
await this.runPluginInit(plugin);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Phase 2: Start - Plugins execute business logic
|
|
71
|
-
this.logger.info('Phase 2: Start plugins');
|
|
72
|
-
this.state = 'running';
|
|
73
|
-
|
|
74
|
-
for (const plugin of orderedPlugins) {
|
|
75
|
-
await this.runPluginStart(plugin);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Trigger ready hook
|
|
79
|
-
await this.triggerHook('kernel:ready');
|
|
80
|
-
this.logger.info('✅ Bootstrap complete', {
|
|
81
|
-
pluginCount: this.plugins.size
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Shutdown the kernel
|
|
87
|
-
* Calls destroy on all plugins in reverse order
|
|
88
|
-
*/
|
|
89
|
-
async shutdown(): Promise<void> {
|
|
90
|
-
await this.destroy();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Graceful shutdown - destroy all plugins in reverse order
|
|
95
|
-
*/
|
|
96
|
-
async destroy(): Promise<void> {
|
|
97
|
-
if (this.state === 'stopped') {
|
|
98
|
-
this.logger.warn('Kernel already stopped');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.state = 'stopping';
|
|
103
|
-
this.logger.info('Shutdown started');
|
|
104
|
-
|
|
105
|
-
// Trigger shutdown hook
|
|
106
|
-
await this.triggerHook('kernel:shutdown');
|
|
107
|
-
|
|
108
|
-
// Destroy plugins in reverse order
|
|
109
|
-
const orderedPlugins = this.resolveDependencies();
|
|
110
|
-
for (const plugin of orderedPlugins.reverse()) {
|
|
111
|
-
await this.runPluginDestroy(plugin);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
this.state = 'stopped';
|
|
115
|
-
this.logger.info('✅ Shutdown complete');
|
|
116
|
-
|
|
117
|
-
// Cleanup logger resources
|
|
118
|
-
if (this.logger && typeof (this.logger as ObjectLogger).destroy === 'function') {
|
|
119
|
-
await (this.logger as ObjectLogger).destroy();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Get a service from the registry
|
|
125
|
-
* Convenience method for external access
|
|
126
|
-
*/
|
|
127
|
-
getService<T>(name: string): T {
|
|
128
|
-
return this.context.getService<T>(name);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Check if kernel is running
|
|
133
|
-
*/
|
|
134
|
-
isRunning(): boolean {
|
|
135
|
-
return this.state === 'running';
|
|
136
|
-
}
|
|
137
|
-
}
|
package/src/logger.test.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { createLogger, ObjectLogger } from './logger';
|
|
3
|
-
|
|
4
|
-
describe('ObjectLogger', () => {
|
|
5
|
-
let logger: ObjectLogger;
|
|
6
|
-
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
logger = createLogger();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
await logger.destroy();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
describe('Basic Logging', () => {
|
|
16
|
-
it('should create a logger with default config', () => {
|
|
17
|
-
expect(logger).toBeDefined();
|
|
18
|
-
expect(logger.info).toBeDefined();
|
|
19
|
-
expect(logger.debug).toBeDefined();
|
|
20
|
-
expect(logger.warn).toBeDefined();
|
|
21
|
-
expect(logger.error).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should log info messages', () => {
|
|
25
|
-
expect(() => logger.info('Test message')).not.toThrow();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should log debug messages', () => {
|
|
29
|
-
expect(() => logger.debug('Debug message')).not.toThrow();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should log warn messages', () => {
|
|
33
|
-
expect(() => logger.warn('Warning message')).not.toThrow();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should log error messages', () => {
|
|
37
|
-
const error = new Error('Test error');
|
|
38
|
-
expect(() => logger.error('Error occurred', error)).not.toThrow();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should log with metadata', () => {
|
|
42
|
-
expect(() => logger.info('Message with metadata', { userId: '123', action: 'login' })).not.toThrow();
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('Configuration', () => {
|
|
47
|
-
it('should respect log level configuration', async () => {
|
|
48
|
-
const warnLogger = createLogger({ level: 'warn' });
|
|
49
|
-
|
|
50
|
-
// These should not throw but might not output anything
|
|
51
|
-
expect(() => warnLogger.debug('Debug message')).not.toThrow();
|
|
52
|
-
expect(() => warnLogger.info('Info message')).not.toThrow();
|
|
53
|
-
expect(() => warnLogger.warn('Warning message')).not.toThrow();
|
|
54
|
-
|
|
55
|
-
await warnLogger.destroy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should support different formats', async () => {
|
|
59
|
-
const jsonLogger = createLogger({ format: 'json' });
|
|
60
|
-
const textLogger = createLogger({ format: 'text' });
|
|
61
|
-
const prettyLogger = createLogger({ format: 'pretty' });
|
|
62
|
-
|
|
63
|
-
expect(() => jsonLogger.info('JSON format')).not.toThrow();
|
|
64
|
-
expect(() => textLogger.info('Text format')).not.toThrow();
|
|
65
|
-
expect(() => prettyLogger.info('Pretty format')).not.toThrow();
|
|
66
|
-
|
|
67
|
-
await jsonLogger.destroy();
|
|
68
|
-
await textLogger.destroy();
|
|
69
|
-
await prettyLogger.destroy();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should redact sensitive keys', async () => {
|
|
73
|
-
const logger = createLogger({ redact: ['password', 'apiKey'] });
|
|
74
|
-
|
|
75
|
-
// This should work without exposing the password
|
|
76
|
-
expect(() => logger.info('User login', {
|
|
77
|
-
username: 'john',
|
|
78
|
-
password: 'secret123',
|
|
79
|
-
apiKey: 'key-12345'
|
|
80
|
-
})).not.toThrow();
|
|
81
|
-
|
|
82
|
-
await logger.destroy();
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('Child Loggers', () => {
|
|
87
|
-
it('should create child logger with context', () => {
|
|
88
|
-
const childLogger = logger.child({ service: 'api', requestId: '123' });
|
|
89
|
-
|
|
90
|
-
expect(childLogger).toBeDefined();
|
|
91
|
-
expect(() => childLogger.info('Child log message')).not.toThrow();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should support trace context', () => {
|
|
95
|
-
const tracedLogger = logger.withTrace('trace-123', 'span-456');
|
|
96
|
-
|
|
97
|
-
expect(tracedLogger).toBeDefined();
|
|
98
|
-
expect(() => tracedLogger.info('Traced message')).not.toThrow();
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('Environment Detection', () => {
|
|
103
|
-
it('should detect Node.js environment', async () => {
|
|
104
|
-
// This test runs in Node.js, so logger should detect it
|
|
105
|
-
const nodeLogger = createLogger({ format: 'json' });
|
|
106
|
-
expect(() => nodeLogger.info('Node environment')).not.toThrow();
|
|
107
|
-
await nodeLogger.destroy();
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
describe('Compatibility', () => {
|
|
112
|
-
it('should support console.log compatibility', () => {
|
|
113
|
-
expect(() => logger.log('Compatible log')).not.toThrow();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
});
|