@objectstack/core 0.9.2 → 1.0.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.
- package/CHANGELOG.md +20 -0
- package/README.md +12 -354
- package/dist/api-registry-plugin.test.js +3 -1
- package/dist/api-registry.test.js +2 -2
- package/dist/dependency-resolver.d.ts +1 -1
- package/dist/health-monitor.d.ts +1 -1
- package/dist/hot-reload.d.ts +1 -1
- package/dist/kernel.d.ts +10 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +53 -6
- package/dist/kernel.test.js +2 -0
- package/dist/plugin-loader.d.ts +4 -0
- package/dist/plugin-loader.d.ts.map +1 -1
- package/dist/plugin-loader.js +6 -0
- package/dist/security/permission-manager.d.ts +1 -1
- package/dist/security/plugin-permission-enforcer.d.ts +1 -1
- package/dist/security/sandbox-runtime.d.ts +1 -1
- package/dist/security/security-scanner.d.ts +1 -1
- package/package.json +3 -2
- package/src/api-registry-plugin.test.ts +3 -1
- package/src/api-registry.test.ts +2 -2
- package/src/dependency-resolver.ts +1 -1
- package/src/health-monitor.test.ts +1 -1
- package/src/health-monitor.ts +1 -1
- package/src/hot-reload.ts +1 -1
- package/src/kernel.test.ts +2 -0
- package/src/kernel.ts +62 -6
- package/src/plugin-loader.ts +7 -0
- package/src/security/permission-manager.test.ts +1 -1
- package/src/security/permission-manager.ts +1 -1
- package/src/security/plugin-permission-enforcer.test.ts +1 -1
- package/src/security/plugin-permission-enforcer.ts +1 -1
- package/src/security/sandbox-runtime.ts +1 -1
- package/src/security/security-scanner.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @objectstack/core
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @objectstack/spec@1.0.1
|
|
8
|
+
|
|
9
|
+
## 1.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- Major version release for ObjectStack Protocol v1.0.
|
|
14
|
+
- Stabilized Protocol Definitions
|
|
15
|
+
- Enhanced Runtime Plugin Support
|
|
16
|
+
- Fixed Type Compliance across Monorepo
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @objectstack/spec@1.0.0
|
|
22
|
+
|
|
3
23
|
## 0.9.2
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,377 +1,35 @@
|
|
|
1
1
|
# @objectstack/core
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
This package defines the fundamental runtime mechanics of the ObjectStack architecture:
|
|
8
|
-
1. **Dependency Injection (DI)**: Advanced service registry with factory functions and lifecycle management
|
|
9
|
-
2. **Plugin Lifecycle**: `init` (Registration) -> `start` (Execution) -> `destroy` (Cleanup)
|
|
10
|
-
3. **Event Bus**: Simple hook system (`hook`, `trigger`) for event-driven communication
|
|
11
|
-
4. **Configurable Logging**: Universal logger using [Pino](https://github.com/pinojs/pino) for Node.js and simple console for browsers
|
|
12
|
-
5. **Enhanced Features**: Version compatibility, health checks, timeout control, graceful shutdown, and more
|
|
13
|
-
|
|
14
|
-
It is completely agnostic of "Data", "HTTP", or "Apps". It only knows `Plugin` and `Service`.
|
|
15
|
-
|
|
16
|
-
## 🤖 AI Development Context
|
|
17
|
-
|
|
18
|
-
**Role**: Microkernel / Runtime Orchestrator
|
|
19
|
-
**Usage**:
|
|
20
|
-
- Use `ObjectKernel` to bootstrap the application.
|
|
21
|
-
- Implement `Plugin` interface to add functionality (not business logic directly).
|
|
22
|
-
- Use `PluginLoader` features for dependency injection.
|
|
23
|
-
|
|
24
|
-
**Architectural Interaction**:
|
|
25
|
-
- `Kernel` loads `Plugins`.
|
|
26
|
-
- `Plugins` register `Services`.
|
|
27
|
-
- `Services` implement logic defined in `spec`.
|
|
3
|
+
The **Kernel** of the ObjectStack architecture. It provides the fundamental building blocks for a modular, plugin-based system.
|
|
28
4
|
|
|
29
5
|
## Features
|
|
30
6
|
|
|
31
|
-
|
|
32
|
-
- **Plugin
|
|
33
|
-
- **Service
|
|
34
|
-
- **
|
|
35
|
-
- **High-Performance Logging**:
|
|
36
|
-
- Node.js: Powered by [Pino](https://github.com/pinojs/pino) - extremely fast, low-overhead structured logging
|
|
37
|
-
- Browser: Lightweight console-based logger
|
|
38
|
-
- **Environment Detection**: Automatic runtime detection (Node.js/browser)
|
|
39
|
-
- **Dependency Resolution**: Automatic topological sorting of plugin dependencies
|
|
40
|
-
- **Security**: Automatic sensitive data redaction in logs
|
|
41
|
-
|
|
42
|
-
### Enhanced Features (EnhancedObjectKernel)
|
|
43
|
-
- **Async Plugin Loading**: Load plugins asynchronously with validation
|
|
44
|
-
- **Version Compatibility**: Semantic versioning support and validation
|
|
45
|
-
- **Plugin Signatures**: Security verification (extensible)
|
|
46
|
-
- **Configuration Validation**: Zod-based schema validation for plugin configs
|
|
47
|
-
- **Service Factories**: Factory-based service instantiation with lifecycle control
|
|
48
|
-
- **Service Lifecycles**: Singleton, Transient, and Scoped service management
|
|
49
|
-
- **Circular Dependency Detection**: Automatic detection and reporting
|
|
50
|
-
- **Lazy Loading**: Services created on-demand
|
|
51
|
-
- **Timeout Control**: Configurable timeouts for plugin initialization
|
|
52
|
-
- **Failure Rollback**: Automatic rollback on startup failures
|
|
53
|
-
- **Health Checks**: Monitor plugin health at runtime
|
|
54
|
-
- **Performance Metrics**: Track plugin startup times
|
|
55
|
-
- **Graceful Shutdown**: Proper cleanup with timeout control
|
|
7
|
+
- **ObjectKernel**: A robust Dependency Injection (DI) container and plugin manager.
|
|
8
|
+
- **Plugin Architecture**: A standard interface (`Plugin`) with lifecycle hooks (`init`, `start`, `stop`).
|
|
9
|
+
- **Service Management**: Register and resolve services with type safety.
|
|
10
|
+
- **Logging**: Structured logging interface with swappable backends.
|
|
56
11
|
|
|
57
12
|
## Installation
|
|
58
13
|
|
|
59
14
|
```bash
|
|
60
|
-
npm install @objectstack/core
|
|
61
|
-
# or
|
|
62
15
|
pnpm add @objectstack/core
|
|
63
16
|
```
|
|
64
17
|
|
|
65
|
-
##
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
import { ObjectKernel, Plugin, PluginContext } from '@objectstack/core';
|
|
69
|
-
|
|
70
|
-
// 1. Define a Plugin
|
|
71
|
-
const myPlugin: Plugin = {
|
|
72
|
-
name: 'my-plugin',
|
|
73
|
-
|
|
74
|
-
async init(ctx: PluginContext) {
|
|
75
|
-
ctx.logger.info('Initializing plugin');
|
|
76
|
-
ctx.registerService('my-service', { hello: 'world' });
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// 2. Boot Kernel with logging config
|
|
81
|
-
const kernel = new ObjectKernel({
|
|
82
|
-
logger: {
|
|
83
|
-
level: 'info',
|
|
84
|
-
format: 'pretty'
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
kernel.use(myPlugin);
|
|
89
|
-
await kernel.bootstrap();
|
|
90
|
-
|
|
91
|
-
// 3. Use Service
|
|
92
|
-
const service = kernel.getService('my-service');
|
|
93
|
-
|
|
94
|
-
// 4. Cleanup
|
|
95
|
-
await kernel.shutdown();
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## 🤖 AI Quick Reference
|
|
99
|
-
|
|
100
|
-
**For AI Agents:** This package implements a microkernel architecture. Key concepts:
|
|
101
|
-
|
|
102
|
-
1. **Plugin Lifecycle**: `init()` → `start()` → `destroy()`
|
|
103
|
-
2. **Service Registry**: Share functionality via `ctx.registerService(name, service)` and `ctx.getService(name)`
|
|
104
|
-
3. **Dependencies**: Declare plugin dependencies for automatic load ordering
|
|
105
|
-
4. **Hooks/Events**: Decouple plugins with `ctx.hook(event, handler)` and `ctx.trigger(event, ...args)`
|
|
106
|
-
5. **Logger**: Always use `ctx.logger` for consistent, structured logging
|
|
107
|
-
|
|
108
|
-
**Common Plugin Pattern:**
|
|
109
|
-
```typescript
|
|
110
|
-
const plugin: Plugin = {
|
|
111
|
-
name: 'my-plugin',
|
|
112
|
-
dependencies: ['other-plugin'], // Load after these plugins
|
|
113
|
-
|
|
114
|
-
async init(ctx: PluginContext) {
|
|
115
|
-
// Register services and hooks
|
|
116
|
-
const otherService = ctx.getService('other-service');
|
|
117
|
-
ctx.registerService('my-service', new MyService(otherService));
|
|
118
|
-
ctx.hook('data:created', async (data) => { /* ... */ });
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
async start(ctx: PluginContext) {
|
|
122
|
-
// Execute business logic
|
|
123
|
-
const service = ctx.getService('my-service');
|
|
124
|
-
await service.initialize();
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
async destroy() {
|
|
128
|
-
// Cleanup resources
|
|
129
|
-
await service.close();
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Configurable Logger
|
|
135
|
-
|
|
136
|
-
The logger uses **[Pino](https://github.com/pinojs/pino)** for Node.js environments (high-performance, low-overhead) and a simple console-based logger for browsers. It automatically detects the runtime environment.
|
|
137
|
-
|
|
138
|
-
### Why Pino?
|
|
139
|
-
|
|
140
|
-
- **Fast**: One of the fastest Node.js loggers available
|
|
141
|
-
- **Low Overhead**: Minimal performance impact on your application
|
|
142
|
-
- **Structured Logging**: Native JSON output for log aggregation tools
|
|
143
|
-
- **Production Ready**: Battle-tested in production environments
|
|
144
|
-
- **Feature Rich**: Automatic log rotation, transports, child loggers, and more
|
|
145
|
-
|
|
146
|
-
### Logger Configuration
|
|
18
|
+
## Basic Usage
|
|
147
19
|
|
|
148
20
|
```typescript
|
|
149
|
-
|
|
150
|
-
logger: {
|
|
151
|
-
level: 'debug', // 'debug' | 'info' | 'warn' | 'error' | 'fatal'
|
|
152
|
-
format: 'pretty', // 'json' | 'text' | 'pretty'
|
|
153
|
-
sourceLocation: true, // Include file/line numbers
|
|
154
|
-
redact: ['password', 'token', 'apiKey'], // Keys to redact
|
|
155
|
-
file: './logs/app.log', // Node.js only
|
|
156
|
-
rotation: { // File rotation (Node.js only)
|
|
157
|
-
maxSize: '10m',
|
|
158
|
-
maxFiles: 5
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
```
|
|
21
|
+
import { ObjectKernel } from '@objectstack/core';
|
|
163
22
|
|
|
164
|
-
|
|
23
|
+
const kernel = new ObjectKernel();
|
|
165
24
|
|
|
166
|
-
|
|
167
|
-
|
|
25
|
+
// Register a simple plugin
|
|
26
|
+
kernel.use({
|
|
168
27
|
name: 'my-plugin',
|
|
169
|
-
|
|
170
|
-
init: async (ctx: PluginContext) => {
|
|
171
|
-
// Basic logging
|
|
172
|
-
ctx.logger.info('Plugin initialized');
|
|
173
|
-
ctx.logger.debug('Debug info', { details: 'data' });
|
|
174
|
-
ctx.logger.warn('Warning message');
|
|
175
|
-
ctx.logger.error('Error occurred', new Error('Oops'));
|
|
176
|
-
|
|
177
|
-
// Sensitive data is automatically redacted
|
|
178
|
-
ctx.logger.info('User login', {
|
|
179
|
-
username: 'john',
|
|
180
|
-
password: 'secret123' // Logged as '***REDACTED***'
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Standalone Logger
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
import { createLogger } from '@objectstack/core';
|
|
190
|
-
|
|
191
|
-
const logger = createLogger({
|
|
192
|
-
level: 'info',
|
|
193
|
-
format: 'json'
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
logger.info('Application started');
|
|
197
|
-
|
|
198
|
-
// Child logger with context
|
|
199
|
-
const requestLogger = logger.child({
|
|
200
|
-
requestId: '123',
|
|
201
|
-
userId: 'user-456'
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
requestLogger.info('Processing request');
|
|
205
|
-
|
|
206
|
-
// Distributed tracing
|
|
207
|
-
const tracedLogger = logger.withTrace('trace-id-123', 'span-id-456');
|
|
208
|
-
|
|
209
|
-
// Cleanup
|
|
210
|
-
await logger.destroy();
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
## Log Formats
|
|
214
|
-
|
|
215
|
-
### JSON (default for Node.js)
|
|
216
|
-
```json
|
|
217
|
-
{"timestamp":"2026-01-29T22:47:36.441Z","level":"info","message":"User action","context":{"userId":"123"}}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Text
|
|
221
|
-
```
|
|
222
|
-
2026-01-29T22:47:36.441Z | INFO | User action | {"userId":"123"}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Pretty (default for browser)
|
|
226
|
-
```
|
|
227
|
-
[INFO] User action { userId: '123' }
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## Plugin Development
|
|
231
|
-
|
|
232
|
-
```typescript
|
|
233
|
-
import { Plugin, PluginContext } from '@objectstack/core';
|
|
234
|
-
|
|
235
|
-
const databasePlugin: Plugin = {
|
|
236
|
-
name: 'database',
|
|
237
28
|
version: '1.0.0',
|
|
238
|
-
|
|
239
|
-
init: async (ctx: PluginContext) => {
|
|
240
|
-
const db = await connectToDatabase();
|
|
241
|
-
ctx.registerService('db', db);
|
|
242
|
-
ctx.logger.info('Database connected');
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
start: async (ctx: PluginContext) => {
|
|
246
|
-
ctx.logger.info('Database ready');
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
destroy: async () => {
|
|
250
|
-
await db.close();
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const apiPlugin: Plugin = {
|
|
255
|
-
name: 'api',
|
|
256
|
-
dependencies: ['database'], // Load after database
|
|
257
|
-
|
|
258
|
-
init: async (ctx: PluginContext) => {
|
|
259
|
-
const db = ctx.getService('db');
|
|
260
|
-
const server = createServer(db);
|
|
261
|
-
ctx.registerService('api', server);
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
kernel.use(databasePlugin);
|
|
266
|
-
kernel.use(apiPlugin);
|
|
267
|
-
await kernel.bootstrap();
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Advanced Kernel Usage
|
|
271
|
-
|
|
272
|
-
For production applications, use `ObjectKernel` (formerly `EnhancedObjectKernel`) for advanced features:
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
import { ObjectKernel, PluginMetadata, ServiceLifecycle } from '@objectstack/core';
|
|
276
|
-
|
|
277
|
-
// Create kernel with advanced configuration
|
|
278
|
-
const kernel = new ObjectKernel({
|
|
279
|
-
logger: { level: 'info', format: 'pretty' },
|
|
280
|
-
defaultStartupTimeout: 30000, // 30 seconds
|
|
281
|
-
gracefulShutdown: true,
|
|
282
|
-
shutdownTimeout: 60000, // 60 seconds
|
|
283
|
-
rollbackOnFailure: true, // Rollback on failures
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Plugin with version and health check
|
|
287
|
-
const plugin: PluginMetadata = {
|
|
288
|
-
name: 'my-plugin',
|
|
289
|
-
version: '1.2.3',
|
|
290
|
-
startupTimeout: 10000,
|
|
291
|
-
|
|
292
29
|
async init(ctx) {
|
|
293
|
-
ctx.
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
async healthCheck() {
|
|
297
|
-
return {
|
|
298
|
-
healthy: true,
|
|
299
|
-
message: 'Service is operational'
|
|
300
|
-
};
|
|
30
|
+
ctx.logger.info('Plugin initializing...');
|
|
301
31
|
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
// Register service factory with lifecycle
|
|
305
|
-
kernel.registerServiceFactory(
|
|
306
|
-
'database',
|
|
307
|
-
async (ctx) => await connectToDatabase(),
|
|
308
|
-
ServiceLifecycle.SINGLETON
|
|
309
|
-
);
|
|
32
|
+
});
|
|
310
33
|
|
|
311
|
-
await kernel.use(plugin);
|
|
312
34
|
await kernel.bootstrap();
|
|
313
|
-
|
|
314
|
-
// Check health
|
|
315
|
-
const health = await kernel.checkPluginHealth('my-plugin');
|
|
316
|
-
console.log(health);
|
|
317
|
-
|
|
318
|
-
// Get metrics
|
|
319
|
-
const metrics = kernel.getPluginMetrics();
|
|
320
|
-
console.log(metrics);
|
|
321
|
-
|
|
322
|
-
// Graceful shutdown
|
|
323
|
-
await kernel.shutdown();
|
|
324
35
|
```
|
|
325
|
-
|
|
326
|
-
See [ENHANCED_FEATURES.md](./ENHANCED_FEATURES.md) for comprehensive documentation.
|
|
327
|
-
See [examples/enhanced-kernel-example.ts](./examples/enhanced-kernel-example.ts) for a complete example.
|
|
328
|
-
|
|
329
|
-
## Environment Support
|
|
330
|
-
|
|
331
|
-
### Node.js Features (via Pino)
|
|
332
|
-
- High-performance structured logging
|
|
333
|
-
- Automatic file logging with rotation
|
|
334
|
-
- JSON format for log aggregation tools (Elasticsearch, Splunk, etc.)
|
|
335
|
-
- Pretty printing for development (via pino-pretty)
|
|
336
|
-
- Child loggers with inherited context
|
|
337
|
-
- Minimal performance overhead
|
|
338
|
-
|
|
339
|
-
### Browser Features
|
|
340
|
-
- Pretty console output with colors
|
|
341
|
-
- DevTools integration
|
|
342
|
-
- Lightweight implementation
|
|
343
|
-
- No external dependencies
|
|
344
|
-
|
|
345
|
-
## Security
|
|
346
|
-
|
|
347
|
-
Automatic sensitive data redaction:
|
|
348
|
-
- Default keys: `password`, `token`, `secret`, `key`
|
|
349
|
-
- Configurable via `redact` option
|
|
350
|
-
- Recursive through nested objects
|
|
351
|
-
|
|
352
|
-
## API Reference
|
|
353
|
-
|
|
354
|
-
### LiteKernel (Minimal)
|
|
355
|
-
- `LiteKernel` - Lightweight microkernel for serverless/test
|
|
356
|
-
- `createLogger(config)` - Create standalone logger
|
|
357
|
-
- `Plugin` - Plugin interface
|
|
358
|
-
- `PluginContext` - Runtime context for plugins
|
|
359
|
-
- `Logger` - Logger interface
|
|
360
|
-
|
|
361
|
-
### ObjectKernel (Production)
|
|
362
|
-
- `ObjectKernel` - Full-featured enterprise microkernel
|
|
363
|
-
- `PluginLoader` - Plugin loading and validation
|
|
364
|
-
- `ServiceLifecycle` - Service lifecycle management (SINGLETON, TRANSIENT, SCOPED)
|
|
365
|
-
- `PluginMetadata` - Extended plugin interface with metadata
|
|
366
|
-
- `PluginHealthStatus` - Health check result interface
|
|
367
|
-
|
|
368
|
-
See [TypeScript definitions](./src/types.ts) for complete API.
|
|
369
|
-
|
|
370
|
-
## Documentation
|
|
371
|
-
|
|
372
|
-
- [ADVANCED_FEATURES.md](./ADVANCED_FEATURES.md) - Comprehensive guide to kernel features
|
|
373
|
-
- [examples/kernel-features-example.ts](./examples/kernel-features-example.ts) - Complete working example
|
|
374
|
-
|
|
375
|
-
## License
|
|
376
|
-
|
|
377
|
-
Apache-2.0
|
|
@@ -5,7 +5,9 @@ import { ApiRegistry } from './api-registry';
|
|
|
5
5
|
describe('API Registry Plugin', () => {
|
|
6
6
|
let kernel;
|
|
7
7
|
beforeEach(() => {
|
|
8
|
-
kernel = new ObjectKernel(
|
|
8
|
+
kernel = new ObjectKernel({
|
|
9
|
+
skipSystemValidation: true
|
|
10
|
+
});
|
|
9
11
|
});
|
|
10
12
|
describe('Plugin Registration', () => {
|
|
11
13
|
it('should register API Registry as a service', async () => {
|
|
@@ -580,8 +580,8 @@ describe('ApiRegistry', () => {
|
|
|
580
580
|
endpoints: [],
|
|
581
581
|
});
|
|
582
582
|
const snapshot = registry.getRegistry();
|
|
583
|
-
expect(snapshot.byType?.rest
|
|
584
|
-
expect(snapshot.byType?.graphql
|
|
583
|
+
expect(snapshot.byType?.rest?.length).toBe(2);
|
|
584
|
+
expect(snapshot.byType?.graphql?.length).toBe(1);
|
|
585
585
|
});
|
|
586
586
|
});
|
|
587
587
|
describe('clear', () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SemanticVersion, VersionConstraint, CompatibilityLevel, DependencyConflict } from '@objectstack/spec/
|
|
1
|
+
import type { SemanticVersion, VersionConstraint, CompatibilityLevel, DependencyConflict } from '@objectstack/spec/kernel';
|
|
2
2
|
import type { ObjectLogger } from './logger.js';
|
|
3
3
|
/**
|
|
4
4
|
* Semantic Version Parser and Comparator
|
package/dist/health-monitor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginHealthStatus, PluginHealthCheck, PluginHealthReport } from '@objectstack/spec/
|
|
1
|
+
import type { PluginHealthStatus, PluginHealthCheck, PluginHealthReport } from '@objectstack/spec/kernel';
|
|
2
2
|
import type { ObjectLogger } from './logger.js';
|
|
3
3
|
import type { Plugin } from './types.js';
|
|
4
4
|
/**
|
package/dist/hot-reload.d.ts
CHANGED
package/dist/kernel.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface ObjectKernelConfig {
|
|
|
14
14
|
shutdownTimeout?: number;
|
|
15
15
|
/** Whether to rollback on startup failure */
|
|
16
16
|
rollbackOnFailure?: boolean;
|
|
17
|
+
/** Whether to skip strict system requirement validation (Critical for testing) */
|
|
18
|
+
skipSystemValidation?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Enhanced ObjectKernel with Advanced Plugin Management
|
|
@@ -49,10 +51,18 @@ export declare class ObjectKernel {
|
|
|
49
51
|
* Register a plugin with enhanced validation
|
|
50
52
|
*/
|
|
51
53
|
use(plugin: Plugin): Promise<this>;
|
|
54
|
+
/**
|
|
55
|
+
* Register a service instance directly
|
|
56
|
+
*/
|
|
57
|
+
registerService<T>(name: string, service: T): this;
|
|
52
58
|
/**
|
|
53
59
|
* Register a service factory with lifecycle management
|
|
54
60
|
*/
|
|
55
61
|
registerServiceFactory<T>(name: string, factory: ServiceFactory<T>, lifecycle?: ServiceLifecycle, dependencies?: string[]): this;
|
|
62
|
+
/**
|
|
63
|
+
* Validate Critical System Requirements
|
|
64
|
+
*/
|
|
65
|
+
private validateSystemRequirements;
|
|
56
66
|
/**
|
|
57
67
|
* Bootstrap the kernel with enhanced features
|
|
58
68
|
*/
|
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,EAAiB,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
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;AAE7D,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;IAE5B,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAClC;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;IAoF3C;;OAEG;IACG,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBxC;;OAEG;IACH,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAUlD;;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;IACH,OAAO,CAAC,0BAA0B;IAwClC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDhC;;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"}
|
package/dist/kernel.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createLogger } from './logger.js';
|
|
2
|
+
import { ServiceRequirementDef } from '@objectstack/spec/system';
|
|
2
3
|
import { PluginLoader, ServiceLifecycle } from './plugin-loader.js';
|
|
3
4
|
/**
|
|
4
5
|
* Enhanced ObjectKernel with Advanced Plugin Management
|
|
@@ -38,12 +39,7 @@ export class ObjectKernel {
|
|
|
38
39
|
// Initialize context
|
|
39
40
|
this.context = {
|
|
40
41
|
registerService: (name, service) => {
|
|
41
|
-
|
|
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 });
|
|
42
|
+
this.registerService(name, service);
|
|
47
43
|
},
|
|
48
44
|
getService: (name) => {
|
|
49
45
|
// 1. Try direct service map first (synchronous cache)
|
|
@@ -125,6 +121,18 @@ export class ObjectKernel {
|
|
|
125
121
|
});
|
|
126
122
|
return this;
|
|
127
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Register a service instance directly
|
|
126
|
+
*/
|
|
127
|
+
registerService(name, service) {
|
|
128
|
+
if (this.services.has(name)) {
|
|
129
|
+
throw new Error(`[Kernel] Service '${name}' already registered`);
|
|
130
|
+
}
|
|
131
|
+
this.services.set(name, service);
|
|
132
|
+
this.pluginLoader.registerService(name, service);
|
|
133
|
+
this.logger.info(`Service '${name}' registered`, { service: name });
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
128
136
|
/**
|
|
129
137
|
* Register a service factory with lifecycle management
|
|
130
138
|
*/
|
|
@@ -137,6 +145,44 @@ export class ObjectKernel {
|
|
|
137
145
|
});
|
|
138
146
|
return this;
|
|
139
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate Critical System Requirements
|
|
150
|
+
*/
|
|
151
|
+
validateSystemRequirements() {
|
|
152
|
+
if (this.config.skipSystemValidation) {
|
|
153
|
+
this.logger.debug('System requirement validation skipped');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this.logger.debug('Validating system service requirements...');
|
|
157
|
+
const missingServices = [];
|
|
158
|
+
const missingCoreServices = [];
|
|
159
|
+
// Iterate through all defined requirements
|
|
160
|
+
for (const [serviceName, criticality] of Object.entries(ServiceRequirementDef)) {
|
|
161
|
+
const hasService = this.services.has(serviceName) || this.pluginLoader.hasService(serviceName);
|
|
162
|
+
if (!hasService) {
|
|
163
|
+
if (criticality === 'required') {
|
|
164
|
+
this.logger.error(`CRITICAL: Required service missing: ${serviceName}`);
|
|
165
|
+
missingServices.push(serviceName);
|
|
166
|
+
}
|
|
167
|
+
else if (criticality === 'core') {
|
|
168
|
+
this.logger.warn(`CORE: Core service missing, functionality may be degraded: ${serviceName}`);
|
|
169
|
+
missingCoreServices.push(serviceName);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
this.logger.info(`Info: Optional service not present: ${serviceName}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (missingServices.length > 0) {
|
|
177
|
+
const errorMsg = `System failed to start. Missing critical services: ${missingServices.join(', ')}`;
|
|
178
|
+
this.logger.error(errorMsg);
|
|
179
|
+
throw new Error(errorMsg);
|
|
180
|
+
}
|
|
181
|
+
if (missingCoreServices.length > 0) {
|
|
182
|
+
this.logger.warn(`System started with degraded capabilities. Missing core services: ${missingCoreServices.join(', ')}`);
|
|
183
|
+
}
|
|
184
|
+
this.logger.info('System requirement check passed');
|
|
185
|
+
}
|
|
140
186
|
/**
|
|
141
187
|
* Bootstrap the kernel with enhanced features
|
|
142
188
|
*/
|
|
@@ -174,6 +220,7 @@ export class ObjectKernel {
|
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
// Phase 3: Trigger kernel:ready hook
|
|
223
|
+
this.validateSystemRequirements(); // Final check before ready
|
|
177
224
|
this.logger.debug('Triggering kernel:ready hook');
|
|
178
225
|
await this.context.trigger('kernel:ready');
|
|
179
226
|
this.logger.info('✅ Bootstrap complete');
|
package/dist/kernel.test.js
CHANGED
|
@@ -7,6 +7,7 @@ describe('ObjectKernel', () => {
|
|
|
7
7
|
kernel = new ObjectKernel({
|
|
8
8
|
logger: { level: 'error' }, // Suppress logs in tests
|
|
9
9
|
gracefulShutdown: false, // Disable for tests
|
|
10
|
+
skipSystemValidation: true,
|
|
10
11
|
});
|
|
11
12
|
});
|
|
12
13
|
describe('Plugin Registration and Loading', () => {
|
|
@@ -166,6 +167,7 @@ describe('ObjectKernel', () => {
|
|
|
166
167
|
logger: { level: 'error' },
|
|
167
168
|
rollbackOnFailure: false,
|
|
168
169
|
gracefulShutdown: false,
|
|
170
|
+
skipSystemValidation: true,
|
|
169
171
|
});
|
|
170
172
|
let plugin1Destroyed = false;
|
|
171
173
|
const plugin1 = {
|
package/dist/plugin-loader.d.ts
CHANGED
|
@@ -128,6 +128,10 @@ export declare class PluginLoader {
|
|
|
128
128
|
* Register a static service instance (legacy support)
|
|
129
129
|
*/
|
|
130
130
|
registerService(name: string, service: any): void;
|
|
131
|
+
/**
|
|
132
|
+
* Check if a service is registered (either as instance or factory)
|
|
133
|
+
*/
|
|
134
|
+
hasService(name: string): boolean;
|
|
131
135
|
/**
|
|
132
136
|
* Detect circular dependencies in service factories
|
|
133
137
|
* Note: This only detects cycles in service dependencies, not plugin dependencies.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin-loader.js
CHANGED
|
@@ -127,6 +127,12 @@ export class PluginLoader {
|
|
|
127
127
|
}
|
|
128
128
|
this.serviceInstances.set(name, service);
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if a service is registered (either as instance or factory)
|
|
132
|
+
*/
|
|
133
|
+
hasService(name) {
|
|
134
|
+
return this.serviceInstances.has(name) || this.serviceFactories.has(name);
|
|
135
|
+
}
|
|
130
136
|
/**
|
|
131
137
|
* Detect circular dependencies in service factories
|
|
132
138
|
* Note: This only detects cycles in service dependencies, not plugin dependencies.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Permission, PermissionSet, PermissionAction, ResourceType } from '@objectstack/spec/
|
|
1
|
+
import type { Permission, PermissionSet, PermissionAction, ResourceType } from '@objectstack/spec/kernel';
|
|
2
2
|
import type { ObjectLogger } from '../logger.js';
|
|
3
3
|
/**
|
|
4
4
|
* Permission Grant
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Logger } from '@objectstack/spec/contracts';
|
|
2
|
-
import type { PluginCapability } from '@objectstack/spec/
|
|
2
|
+
import type { PluginCapability } from '@objectstack/spec/kernel';
|
|
3
3
|
import type { PluginContext } from '../types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Plugin Permissions
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"license": "Apache-2.0",
|
|
4
5
|
"description": "Microkernel Core for ObjectStack",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "dist/index.js",
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
"pino": "^8.17.0",
|
|
15
16
|
"pino-pretty": "^10.3.0",
|
|
16
17
|
"zod": "^4.3.6",
|
|
17
|
-
"@objectstack/spec": "0.
|
|
18
|
+
"@objectstack/spec": "1.0.1"
|
|
18
19
|
},
|
|
19
20
|
"peerDependencies": {
|
|
20
21
|
"pino": "^8.0.0"
|
package/src/api-registry.test.ts
CHANGED
|
@@ -657,8 +657,8 @@ describe('ApiRegistry', () => {
|
|
|
657
657
|
});
|
|
658
658
|
|
|
659
659
|
const snapshot = registry.getRegistry();
|
|
660
|
-
expect(snapshot.byType?.rest
|
|
661
|
-
expect(snapshot.byType?.graphql
|
|
660
|
+
expect(snapshot.byType?.rest?.length).toBe(2);
|
|
661
|
+
expect(snapshot.byType?.graphql?.length).toBe(1);
|
|
662
662
|
});
|
|
663
663
|
});
|
|
664
664
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { PluginHealthMonitor } from './health-monitor.js';
|
|
3
3
|
import { createLogger } from './logger.js';
|
|
4
|
-
import type { PluginHealthCheck } from '@objectstack/spec/
|
|
4
|
+
import type { PluginHealthCheck } from '@objectstack/spec/kernel';
|
|
5
5
|
|
|
6
6
|
describe('PluginHealthMonitor', () => {
|
|
7
7
|
let monitor: PluginHealthMonitor;
|
package/src/health-monitor.ts
CHANGED
package/src/hot-reload.ts
CHANGED
package/src/kernel.test.ts
CHANGED
|
@@ -10,6 +10,7 @@ describe('ObjectKernel', () => {
|
|
|
10
10
|
kernel = new ObjectKernel({
|
|
11
11
|
logger: { level: 'error' }, // Suppress logs in tests
|
|
12
12
|
gracefulShutdown: false, // Disable for tests
|
|
13
|
+
skipSystemValidation: true,
|
|
13
14
|
});
|
|
14
15
|
});
|
|
15
16
|
|
|
@@ -226,6 +227,7 @@ describe('ObjectKernel', () => {
|
|
|
226
227
|
logger: { level: 'error' },
|
|
227
228
|
rollbackOnFailure: false,
|
|
228
229
|
gracefulShutdown: false,
|
|
230
|
+
skipSystemValidation: true,
|
|
229
231
|
});
|
|
230
232
|
|
|
231
233
|
let plugin1Destroyed = false;
|
package/src/kernel.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Plugin, PluginContext } from './types.js';
|
|
2
2
|
import { createLogger, ObjectLogger } from './logger.js';
|
|
3
3
|
import type { LoggerConfig } from '@objectstack/spec/system';
|
|
4
|
+
import { ServiceRequirementDef } from '@objectstack/spec/system';
|
|
4
5
|
import { PluginLoader, PluginMetadata, ServiceLifecycle, ServiceFactory, PluginStartupResult } from './plugin-loader.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -20,6 +21,9 @@ export interface ObjectKernelConfig {
|
|
|
20
21
|
|
|
21
22
|
/** Whether to rollback on startup failure */
|
|
22
23
|
rollbackOnFailure?: boolean;
|
|
24
|
+
|
|
25
|
+
/** Whether to skip strict system requirement validation (Critical for testing) */
|
|
26
|
+
skipSystemValidation?: boolean;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
/**
|
|
@@ -67,12 +71,7 @@ export class ObjectKernel {
|
|
|
67
71
|
// Initialize context
|
|
68
72
|
this.context = {
|
|
69
73
|
registerService: (name, service) => {
|
|
70
|
-
|
|
71
|
-
throw new Error(`[Kernel] Service '${name}' already registered`);
|
|
72
|
-
}
|
|
73
|
-
this.services.set(name, service);
|
|
74
|
-
this.pluginLoader.registerService(name, service);
|
|
75
|
-
this.logger.info(`Service '${name}' registered`, { service: name });
|
|
74
|
+
this.registerService(name, service);
|
|
76
75
|
},
|
|
77
76
|
getService: <T>(name: string) => {
|
|
78
77
|
// 1. Try direct service map first (synchronous cache)
|
|
@@ -167,6 +166,19 @@ export class ObjectKernel {
|
|
|
167
166
|
return this;
|
|
168
167
|
}
|
|
169
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Register a service instance directly
|
|
171
|
+
*/
|
|
172
|
+
registerService<T>(name: string, service: T): this {
|
|
173
|
+
if (this.services.has(name)) {
|
|
174
|
+
throw new Error(`[Kernel] Service '${name}' already registered`);
|
|
175
|
+
}
|
|
176
|
+
this.services.set(name, service);
|
|
177
|
+
this.pluginLoader.registerService(name, service);
|
|
178
|
+
this.logger.info(`Service '${name}' registered`, { service: name });
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
|
|
170
182
|
/**
|
|
171
183
|
* Register a service factory with lifecycle management
|
|
172
184
|
*/
|
|
@@ -185,6 +197,49 @@ export class ObjectKernel {
|
|
|
185
197
|
return this;
|
|
186
198
|
}
|
|
187
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Validate Critical System Requirements
|
|
202
|
+
*/
|
|
203
|
+
private validateSystemRequirements() {
|
|
204
|
+
if (this.config.skipSystemValidation) {
|
|
205
|
+
this.logger.debug('System requirement validation skipped');
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.logger.debug('Validating system service requirements...');
|
|
210
|
+
const missingServices: string[] = [];
|
|
211
|
+
const missingCoreServices: string[] = [];
|
|
212
|
+
|
|
213
|
+
// Iterate through all defined requirements
|
|
214
|
+
for (const [serviceName, criticality] of Object.entries(ServiceRequirementDef)) {
|
|
215
|
+
const hasService = this.services.has(serviceName) || this.pluginLoader.hasService(serviceName);
|
|
216
|
+
|
|
217
|
+
if (!hasService) {
|
|
218
|
+
if (criticality === 'required') {
|
|
219
|
+
this.logger.error(`CRITICAL: Required service missing: ${serviceName}`);
|
|
220
|
+
missingServices.push(serviceName);
|
|
221
|
+
} else if (criticality === 'core') {
|
|
222
|
+
this.logger.warn(`CORE: Core service missing, functionality may be degraded: ${serviceName}`);
|
|
223
|
+
missingCoreServices.push(serviceName);
|
|
224
|
+
} else {
|
|
225
|
+
this.logger.info(`Info: Optional service not present: ${serviceName}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (missingServices.length > 0) {
|
|
231
|
+
const errorMsg = `System failed to start. Missing critical services: ${missingServices.join(', ')}`;
|
|
232
|
+
this.logger.error(errorMsg);
|
|
233
|
+
throw new Error(errorMsg);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (missingCoreServices.length > 0) {
|
|
237
|
+
this.logger.warn(`System started with degraded capabilities. Missing core services: ${missingCoreServices.join(', ')}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.logger.info('System requirement check passed');
|
|
241
|
+
}
|
|
242
|
+
|
|
188
243
|
/**
|
|
189
244
|
* Bootstrap the kernel with enhanced features
|
|
190
245
|
*/
|
|
@@ -231,6 +286,7 @@ export class ObjectKernel {
|
|
|
231
286
|
}
|
|
232
287
|
|
|
233
288
|
// Phase 3: Trigger kernel:ready hook
|
|
289
|
+
this.validateSystemRequirements(); // Final check before ready
|
|
234
290
|
this.logger.debug('Triggering kernel:ready hook');
|
|
235
291
|
await this.context.trigger('kernel:ready');
|
|
236
292
|
|
package/src/plugin-loader.ts
CHANGED
|
@@ -246,6 +246,13 @@ export class PluginLoader {
|
|
|
246
246
|
this.serviceInstances.set(name, service);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Check if a service is registered (either as instance or factory)
|
|
251
|
+
*/
|
|
252
|
+
hasService(name: string): boolean {
|
|
253
|
+
return this.serviceInstances.has(name) || this.serviceFactories.has(name);
|
|
254
|
+
}
|
|
255
|
+
|
|
249
256
|
/**
|
|
250
257
|
* Detect circular dependencies in service factories
|
|
251
258
|
* Note: This only detects cycles in service dependencies, not plugin dependencies.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { PluginPermissionManager } from './permission-manager.js';
|
|
3
3
|
import { createLogger } from '../logger.js';
|
|
4
|
-
import type { PermissionSet } from '@objectstack/spec/
|
|
4
|
+
import type { PermissionSet } from '@objectstack/spec/kernel';
|
|
5
5
|
|
|
6
6
|
describe('PluginPermissionManager', () => {
|
|
7
7
|
let manager: PluginPermissionManager;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
2
|
import { PluginPermissionEnforcer, SecurePluginContext } from './plugin-permission-enforcer.js';
|
|
3
3
|
import { createLogger } from '../logger.js';
|
|
4
|
-
import type { PluginCapability } from '@objectstack/spec/
|
|
4
|
+
import type { PluginCapability } from '@objectstack/spec/kernel';
|
|
5
5
|
import type { PluginContext } from '../types.js';
|
|
6
6
|
|
|
7
7
|
describe('PluginPermissionEnforcer', () => {
|