@objectstack/core 0.9.1 → 1.0.0
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/{ENHANCED_FEATURES.md → ADVANCED_FEATURES.md} +13 -13
- package/CHANGELOG.md +21 -0
- package/PHASE2_IMPLEMENTATION.md +388 -0
- package/README.md +12 -341
- package/REFACTORING_SUMMARY.md +40 -0
- package/dist/api-registry-plugin.test.js +23 -21
- package/dist/api-registry.test.js +2 -2
- package/dist/dependency-resolver.d.ts +62 -0
- package/dist/dependency-resolver.d.ts.map +1 -0
- package/dist/dependency-resolver.js +317 -0
- package/dist/dependency-resolver.test.d.ts +2 -0
- package/dist/dependency-resolver.test.d.ts.map +1 -0
- package/dist/dependency-resolver.test.js +241 -0
- package/dist/health-monitor.d.ts +65 -0
- package/dist/health-monitor.d.ts.map +1 -0
- package/dist/health-monitor.js +269 -0
- package/dist/health-monitor.test.d.ts +2 -0
- package/dist/health-monitor.test.d.ts.map +1 -0
- package/dist/health-monitor.test.js +68 -0
- package/dist/hot-reload.d.ts +79 -0
- package/dist/hot-reload.d.ts.map +1 -0
- package/dist/hot-reload.js +313 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/kernel-base.d.ts +2 -2
- package/dist/kernel-base.js +2 -2
- package/dist/kernel.d.ts +89 -31
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +430 -73
- package/dist/kernel.test.js +375 -122
- package/dist/lite-kernel.d.ts +55 -0
- package/dist/lite-kernel.d.ts.map +1 -0
- package/dist/lite-kernel.js +112 -0
- package/dist/lite-kernel.test.d.ts +2 -0
- package/dist/lite-kernel.test.d.ts.map +1 -0
- package/dist/lite-kernel.test.js +161 -0
- package/dist/logger.d.ts +2 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +26 -7
- package/dist/plugin-loader.d.ts +15 -0
- package/dist/plugin-loader.d.ts.map +1 -1
- package/dist/plugin-loader.js +40 -10
- package/dist/plugin-loader.test.js +9 -0
- package/dist/security/index.d.ts +3 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +4 -0
- package/dist/security/permission-manager.d.ts +96 -0
- package/dist/security/permission-manager.d.ts.map +1 -0
- package/dist/security/permission-manager.js +235 -0
- package/dist/security/permission-manager.test.d.ts +2 -0
- package/dist/security/permission-manager.test.d.ts.map +1 -0
- package/dist/security/permission-manager.test.js +220 -0
- package/dist/security/plugin-permission-enforcer.d.ts +1 -1
- package/dist/security/sandbox-runtime.d.ts +115 -0
- package/dist/security/sandbox-runtime.d.ts.map +1 -0
- package/dist/security/sandbox-runtime.js +310 -0
- package/dist/security/security-scanner.d.ts +92 -0
- package/dist/security/security-scanner.d.ts.map +1 -0
- package/dist/security/security-scanner.js +273 -0
- package/examples/{enhanced-kernel-example.ts → kernel-features-example.ts} +6 -6
- package/examples/phase2-integration.ts +355 -0
- package/package.json +3 -2
- package/src/api-registry-plugin.test.ts +23 -21
- package/src/api-registry.test.ts +2 -2
- package/src/dependency-resolver.test.ts +287 -0
- package/src/dependency-resolver.ts +388 -0
- package/src/health-monitor.test.ts +81 -0
- package/src/health-monitor.ts +316 -0
- package/src/hot-reload.ts +388 -0
- package/src/index.ts +6 -1
- package/src/kernel-base.ts +2 -2
- package/src/kernel.test.ts +471 -134
- package/src/kernel.ts +518 -76
- package/src/lite-kernel.test.ts +200 -0
- package/src/lite-kernel.ts +135 -0
- package/src/logger.ts +28 -7
- package/src/plugin-loader.test.ts +10 -1
- package/src/plugin-loader.ts +49 -13
- package/src/security/index.ts +19 -0
- package/src/security/permission-manager.test.ts +256 -0
- package/src/security/permission-manager.ts +336 -0
- 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 +432 -0
- package/src/security/security-scanner.ts +365 -0
- package/dist/enhanced-kernel.d.ts +0 -103
- package/dist/enhanced-kernel.d.ts.map +0 -1
- package/dist/enhanced-kernel.js +0 -403
- package/dist/enhanced-kernel.test.d.ts +0 -2
- package/dist/enhanced-kernel.test.d.ts.map +0 -1
- package/dist/enhanced-kernel.test.js +0 -412
- package/src/enhanced-kernel.test.ts +0 -535
- package/src/enhanced-kernel.ts +0 -496
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ObjectKernel Features Example
|
|
3
3
|
*
|
|
4
4
|
* Demonstrates advanced plugin features:
|
|
5
5
|
* - Version compatibility
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
|
|
15
|
+
ObjectKernel,
|
|
16
16
|
PluginMetadata,
|
|
17
17
|
ServiceLifecycle,
|
|
18
18
|
PluginContext
|
|
@@ -156,7 +156,7 @@ const cachePlugin: PluginMetadata = {
|
|
|
156
156
|
// Example 4: Using Service Factories
|
|
157
157
|
// ============================================================================
|
|
158
158
|
|
|
159
|
-
async function setupServiceFactories(kernel:
|
|
159
|
+
async function setupServiceFactories(kernel: ObjectKernel) {
|
|
160
160
|
// Singleton: Created once, shared across all requests
|
|
161
161
|
kernel.registerServiceFactory(
|
|
162
162
|
'logger-service',
|
|
@@ -197,10 +197,10 @@ async function setupServiceFactories(kernel: EnhancedObjectKernel) {
|
|
|
197
197
|
// ============================================================================
|
|
198
198
|
|
|
199
199
|
async function main() {
|
|
200
|
-
console.log('🚀 Starting
|
|
200
|
+
console.log('🚀 Starting ObjectKernel Advanced Features Example\n');
|
|
201
201
|
|
|
202
|
-
// Create
|
|
203
|
-
const kernel = new
|
|
202
|
+
// Create object kernel with configuration
|
|
203
|
+
const kernel = new ObjectKernel({
|
|
204
204
|
logger: {
|
|
205
205
|
level: 'info',
|
|
206
206
|
format: 'pretty'
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 Integration Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to use all Phase 2 components together
|
|
5
|
+
* in a real-world scenario.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
ObjectKernel,
|
|
10
|
+
PluginHealthMonitor,
|
|
11
|
+
HotReloadManager,
|
|
12
|
+
DependencyResolver,
|
|
13
|
+
PluginPermissionManager,
|
|
14
|
+
PluginSandboxRuntime,
|
|
15
|
+
PluginSecurityScanner
|
|
16
|
+
} from '@objectstack/core';
|
|
17
|
+
|
|
18
|
+
import type { Plugin } from '@objectstack/core';
|
|
19
|
+
import type {
|
|
20
|
+
PluginHealthCheck,
|
|
21
|
+
HotReloadConfig,
|
|
22
|
+
PermissionSet,
|
|
23
|
+
SandboxConfig
|
|
24
|
+
} from '@objectstack/spec/system';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Example: Enterprise Plugin Platform with Phase 2 Features
|
|
28
|
+
*/
|
|
29
|
+
export class EnterprisePluginPlatform {
|
|
30
|
+
private kernel: ObjectKernel;
|
|
31
|
+
private healthMonitor: PluginHealthMonitor;
|
|
32
|
+
private hotReload: HotReloadManager;
|
|
33
|
+
private depResolver: DependencyResolver;
|
|
34
|
+
private permManager: PluginPermissionManager;
|
|
35
|
+
private sandbox: PluginSandboxRuntime;
|
|
36
|
+
private scanner: PluginSecurityScanner;
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
// Initialize kernel
|
|
40
|
+
this.kernel = new ObjectKernel({
|
|
41
|
+
logger: {
|
|
42
|
+
level: 'info',
|
|
43
|
+
name: 'EnterprisePluginPlatform',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Initialize Phase 2 components
|
|
48
|
+
this.healthMonitor = new PluginHealthMonitor(this.kernel.logger);
|
|
49
|
+
this.hotReload = new HotReloadManager(this.kernel.logger);
|
|
50
|
+
this.depResolver = new DependencyResolver(this.kernel.logger);
|
|
51
|
+
this.permManager = new PluginPermissionManager(this.kernel.logger);
|
|
52
|
+
this.sandbox = new PluginSandboxRuntime(this.kernel.logger);
|
|
53
|
+
this.scanner = new PluginSecurityScanner(this.kernel.logger);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Install and configure a plugin with full Phase 2 features
|
|
58
|
+
*/
|
|
59
|
+
async installPlugin(
|
|
60
|
+
plugin: Plugin,
|
|
61
|
+
config: {
|
|
62
|
+
health?: PluginHealthCheck;
|
|
63
|
+
hotReload?: HotReloadConfig;
|
|
64
|
+
permissions?: PermissionSet;
|
|
65
|
+
sandbox?: SandboxConfig;
|
|
66
|
+
securityScan?: boolean;
|
|
67
|
+
}
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
const pluginName = plugin.name;
|
|
70
|
+
const pluginVersion = plugin.version || '1.0.0';
|
|
71
|
+
|
|
72
|
+
this.kernel.logger.info(`Installing plugin: ${pluginName} v${pluginVersion}`);
|
|
73
|
+
|
|
74
|
+
// Step 1: Security Scan
|
|
75
|
+
if (config.securityScan !== false) {
|
|
76
|
+
this.kernel.logger.info('Running security scan...');
|
|
77
|
+
|
|
78
|
+
const scanResult = await this.scanner.scan({
|
|
79
|
+
pluginId: pluginName,
|
|
80
|
+
version: pluginVersion,
|
|
81
|
+
// In real implementation, would provide actual files and dependencies
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (!scanResult.passed) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Security scan failed: Score ${scanResult.score}/100, ` +
|
|
87
|
+
`Critical: ${scanResult.summary.critical}, ` +
|
|
88
|
+
`High: ${scanResult.summary.high}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.kernel.logger.info(
|
|
93
|
+
`Security scan passed: ${scanResult.score}/100`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Step 2: Register Permissions
|
|
98
|
+
if (config.permissions) {
|
|
99
|
+
this.permManager.registerPermissions(pluginName, config.permissions);
|
|
100
|
+
|
|
101
|
+
// Auto-grant all permissions (in production, would prompt user)
|
|
102
|
+
this.permManager.grantAllPermissions(pluginName, 'system');
|
|
103
|
+
|
|
104
|
+
this.kernel.logger.info(
|
|
105
|
+
`Permissions registered: ${config.permissions.permissions.length} permissions`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Step 3: Create Sandbox
|
|
110
|
+
if (config.sandbox) {
|
|
111
|
+
this.sandbox.createSandbox(pluginName, config.sandbox);
|
|
112
|
+
this.kernel.logger.info(`Sandbox created: ${config.sandbox.level} level`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Step 4: Register for Health Monitoring
|
|
116
|
+
if (config.health) {
|
|
117
|
+
this.healthMonitor.registerPlugin(pluginName, config.health);
|
|
118
|
+
this.kernel.logger.info(
|
|
119
|
+
`Health monitoring configured: ${config.health.interval}ms interval`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Step 5: Register for Hot Reload
|
|
124
|
+
if (config.hotReload) {
|
|
125
|
+
this.hotReload.registerPlugin(pluginName, config.hotReload);
|
|
126
|
+
this.kernel.logger.info(
|
|
127
|
+
`Hot reload enabled: ${config.hotReload.stateStrategy} state strategy`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Step 6: Register with Kernel
|
|
132
|
+
this.kernel.use(plugin);
|
|
133
|
+
|
|
134
|
+
this.kernel.logger.info(`Plugin ${pluginName} installed successfully`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Bootstrap the platform
|
|
139
|
+
*/
|
|
140
|
+
async start(): Promise<void> {
|
|
141
|
+
// Bootstrap kernel (will init and start all plugins)
|
|
142
|
+
await this.kernel.bootstrap();
|
|
143
|
+
|
|
144
|
+
// Start health monitoring for all registered plugins
|
|
145
|
+
for (const [pluginName, plugin] of this.kernel['plugins']) {
|
|
146
|
+
if (this.healthMonitor['healthChecks'].has(pluginName)) {
|
|
147
|
+
this.healthMonitor.startMonitoring(pluginName, plugin);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.kernel.logger.info('Platform started successfully');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Shutdown the platform
|
|
156
|
+
*/
|
|
157
|
+
async shutdown(): Promise<void> {
|
|
158
|
+
this.kernel.logger.info('Shutting down platform...');
|
|
159
|
+
|
|
160
|
+
// Stop health monitoring
|
|
161
|
+
this.healthMonitor.shutdown();
|
|
162
|
+
|
|
163
|
+
// Shutdown sandbox
|
|
164
|
+
this.sandbox.shutdown();
|
|
165
|
+
|
|
166
|
+
// Shutdown kernel
|
|
167
|
+
await this.kernel.shutdown();
|
|
168
|
+
|
|
169
|
+
this.kernel.logger.info('Platform shutdown complete');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get platform health status
|
|
174
|
+
*/
|
|
175
|
+
getHealthStatus(): Record<string, any> {
|
|
176
|
+
const statuses = this.healthMonitor.getAllHealthStatuses();
|
|
177
|
+
const summary: Record<string, any> = {
|
|
178
|
+
totalPlugins: statuses.size,
|
|
179
|
+
healthy: 0,
|
|
180
|
+
degraded: 0,
|
|
181
|
+
unhealthy: 0,
|
|
182
|
+
failed: 0,
|
|
183
|
+
plugins: {},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
for (const [pluginName, status] of statuses) {
|
|
187
|
+
summary[status]++;
|
|
188
|
+
summary.plugins[pluginName] = {
|
|
189
|
+
status,
|
|
190
|
+
report: this.healthMonitor.getHealthReport(pluginName),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return summary;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Perform hot reload of a plugin
|
|
199
|
+
*/
|
|
200
|
+
async reloadPlugin(pluginName: string): Promise<void> {
|
|
201
|
+
this.kernel.logger.info(`Hot reloading plugin: ${pluginName}`);
|
|
202
|
+
|
|
203
|
+
const plugin = this.kernel['plugins'].get(pluginName);
|
|
204
|
+
if (!plugin) {
|
|
205
|
+
throw new Error(`Plugin not found: ${pluginName}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Get current state (simplified - would need plugin cooperation)
|
|
209
|
+
const getState = () => ({
|
|
210
|
+
timestamp: Date.now(),
|
|
211
|
+
// ... plugin state
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Restore state (simplified - would need plugin cooperation)
|
|
215
|
+
const restoreState = (state: Record<string, any>) => {
|
|
216
|
+
this.kernel.logger.info(`Restoring state from ${new Date(state.timestamp)}`);
|
|
217
|
+
// ... restore plugin state
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
await this.hotReload.reloadPlugin(
|
|
221
|
+
pluginName,
|
|
222
|
+
plugin,
|
|
223
|
+
plugin.version || '1.0.0',
|
|
224
|
+
getState,
|
|
225
|
+
restoreState
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
this.kernel.logger.info(`Plugin ${pluginName} reloaded successfully`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Example Usage
|
|
234
|
+
*/
|
|
235
|
+
async function example() {
|
|
236
|
+
const platform = new EnterprisePluginPlatform();
|
|
237
|
+
|
|
238
|
+
// Define a sample plugin
|
|
239
|
+
const myPlugin: Plugin = {
|
|
240
|
+
name: 'com.example.my-plugin',
|
|
241
|
+
version: '1.0.0',
|
|
242
|
+
dependencies: ['com.objectstack.engine.objectql'],
|
|
243
|
+
|
|
244
|
+
async init(ctx) {
|
|
245
|
+
ctx.logger.info('MyPlugin initializing...');
|
|
246
|
+
// Initialize plugin
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
async start(ctx) {
|
|
250
|
+
ctx.logger.info('MyPlugin starting...');
|
|
251
|
+
// Start plugin services
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
async destroy() {
|
|
255
|
+
console.log('MyPlugin destroying...');
|
|
256
|
+
// Cleanup
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Install plugin with full Phase 2 features
|
|
261
|
+
await platform.installPlugin(myPlugin, {
|
|
262
|
+
// Health monitoring
|
|
263
|
+
health: {
|
|
264
|
+
interval: 30000, // Check every 30 seconds
|
|
265
|
+
timeout: 5000,
|
|
266
|
+
failureThreshold: 3,
|
|
267
|
+
successThreshold: 1,
|
|
268
|
+
autoRestart: true,
|
|
269
|
+
maxRestartAttempts: 3,
|
|
270
|
+
restartBackoff: 'exponential',
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
// Hot reload
|
|
274
|
+
hotReload: {
|
|
275
|
+
enabled: true,
|
|
276
|
+
watchPatterns: ['plugins/my-plugin/**/*.ts'],
|
|
277
|
+
debounceDelay: 1000,
|
|
278
|
+
preserveState: true,
|
|
279
|
+
stateStrategy: 'memory',
|
|
280
|
+
shutdownTimeout: 30000,
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
// Permissions
|
|
284
|
+
permissions: {
|
|
285
|
+
permissions: [
|
|
286
|
+
{
|
|
287
|
+
id: 'read-data',
|
|
288
|
+
resource: 'data.object',
|
|
289
|
+
actions: ['read'],
|
|
290
|
+
scope: 'plugin',
|
|
291
|
+
description: 'Read object data',
|
|
292
|
+
required: true,
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: 'write-data',
|
|
296
|
+
resource: 'data.object',
|
|
297
|
+
actions: ['create', 'update'],
|
|
298
|
+
scope: 'plugin',
|
|
299
|
+
description: 'Write object data',
|
|
300
|
+
required: false,
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
defaultGrant: 'prompt',
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
// Sandbox
|
|
307
|
+
sandbox: {
|
|
308
|
+
enabled: true,
|
|
309
|
+
level: 'standard',
|
|
310
|
+
filesystem: {
|
|
311
|
+
mode: 'restricted',
|
|
312
|
+
allowedPaths: ['/app/plugins/my-plugin'],
|
|
313
|
+
deniedPaths: ['/etc', '/root'],
|
|
314
|
+
},
|
|
315
|
+
network: {
|
|
316
|
+
mode: 'restricted',
|
|
317
|
+
allowedHosts: ['api.example.com'],
|
|
318
|
+
maxConnections: 10,
|
|
319
|
+
},
|
|
320
|
+
process: {
|
|
321
|
+
allowSpawn: false,
|
|
322
|
+
},
|
|
323
|
+
memory: {
|
|
324
|
+
maxHeap: 100 * 1024 * 1024, // 100 MB
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
// Security scanning
|
|
329
|
+
securityScan: true,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Start platform
|
|
333
|
+
await platform.start();
|
|
334
|
+
|
|
335
|
+
// Get health status
|
|
336
|
+
const health = platform.getHealthStatus();
|
|
337
|
+
console.log('Platform Health:', health);
|
|
338
|
+
|
|
339
|
+
// Simulate hot reload after some time
|
|
340
|
+
setTimeout(async () => {
|
|
341
|
+
await platform.reloadPlugin('com.example.my-plugin');
|
|
342
|
+
}, 60000);
|
|
343
|
+
|
|
344
|
+
// Shutdown on SIGINT
|
|
345
|
+
process.on('SIGINT', async () => {
|
|
346
|
+
await platform.shutdown();
|
|
347
|
+
process.exit(0);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Run example if this file is executed directly (ES Module compatible)
|
|
352
|
+
// Note: In ES modules, use import.meta.url instead of require.main
|
|
353
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
354
|
+
example().catch(console.error);
|
|
355
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
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.0"
|
|
18
19
|
},
|
|
19
20
|
"peerDependencies": {
|
|
20
21
|
"pino": "^8.0.0"
|
|
@@ -9,12 +9,14 @@ describe('API Registry Plugin', () => {
|
|
|
9
9
|
let kernel: ObjectKernel;
|
|
10
10
|
|
|
11
11
|
beforeEach(() => {
|
|
12
|
-
kernel = new ObjectKernel(
|
|
12
|
+
kernel = new ObjectKernel({
|
|
13
|
+
skipSystemValidation: true
|
|
14
|
+
});
|
|
13
15
|
});
|
|
14
16
|
|
|
15
17
|
describe('Plugin Registration', () => {
|
|
16
18
|
it('should register API Registry as a service', async () => {
|
|
17
|
-
kernel.use(createApiRegistryPlugin());
|
|
19
|
+
await kernel.use(createApiRegistryPlugin());
|
|
18
20
|
await kernel.bootstrap();
|
|
19
21
|
|
|
20
22
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -25,7 +27,7 @@ describe('API Registry Plugin', () => {
|
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
it('should register with custom conflict resolution', async () => {
|
|
28
|
-
kernel.use(createApiRegistryPlugin({
|
|
30
|
+
await kernel.use(createApiRegistryPlugin({
|
|
29
31
|
conflictResolution: 'priority',
|
|
30
32
|
version: '2.0.0',
|
|
31
33
|
}));
|
|
@@ -42,7 +44,7 @@ describe('API Registry Plugin', () => {
|
|
|
42
44
|
|
|
43
45
|
describe('Integration with Plugins', () => {
|
|
44
46
|
it('should allow plugins to register APIs', async () => {
|
|
45
|
-
kernel.use(createApiRegistryPlugin());
|
|
47
|
+
await kernel.use(createApiRegistryPlugin());
|
|
46
48
|
|
|
47
49
|
const testPlugin: Plugin = {
|
|
48
50
|
name: 'test-plugin',
|
|
@@ -75,7 +77,7 @@ describe('API Registry Plugin', () => {
|
|
|
75
77
|
},
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
kernel.use(testPlugin);
|
|
80
|
+
await kernel.use(testPlugin);
|
|
79
81
|
await kernel.bootstrap();
|
|
80
82
|
|
|
81
83
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -88,7 +90,7 @@ describe('API Registry Plugin', () => {
|
|
|
88
90
|
});
|
|
89
91
|
|
|
90
92
|
it('should allow multiple plugins to register APIs', async () => {
|
|
91
|
-
kernel.use(createApiRegistryPlugin());
|
|
93
|
+
await kernel.use(createApiRegistryPlugin());
|
|
92
94
|
|
|
93
95
|
const plugin1: Plugin = {
|
|
94
96
|
name: 'plugin-1',
|
|
@@ -133,8 +135,8 @@ describe('API Registry Plugin', () => {
|
|
|
133
135
|
},
|
|
134
136
|
};
|
|
135
137
|
|
|
136
|
-
kernel.use(plugin1);
|
|
137
|
-
kernel.use(plugin2);
|
|
138
|
+
await kernel.use(plugin1);
|
|
139
|
+
await kernel.use(plugin2);
|
|
138
140
|
await kernel.bootstrap();
|
|
139
141
|
|
|
140
142
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -147,7 +149,7 @@ describe('API Registry Plugin', () => {
|
|
|
147
149
|
});
|
|
148
150
|
|
|
149
151
|
it('should support API discovery across plugins', async () => {
|
|
150
|
-
kernel.use(createApiRegistryPlugin());
|
|
152
|
+
await kernel.use(createApiRegistryPlugin());
|
|
151
153
|
|
|
152
154
|
const dataPlugin: Plugin = {
|
|
153
155
|
name: 'data-plugin',
|
|
@@ -200,8 +202,8 @@ describe('API Registry Plugin', () => {
|
|
|
200
202
|
},
|
|
201
203
|
};
|
|
202
204
|
|
|
203
|
-
kernel.use(dataPlugin);
|
|
204
|
-
kernel.use(analyticsPlugin);
|
|
205
|
+
await kernel.use(dataPlugin);
|
|
206
|
+
await kernel.use(analyticsPlugin);
|
|
205
207
|
await kernel.bootstrap();
|
|
206
208
|
|
|
207
209
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -223,7 +225,7 @@ describe('API Registry Plugin', () => {
|
|
|
223
225
|
});
|
|
224
226
|
|
|
225
227
|
it('should handle route conflicts based on strategy', async () => {
|
|
226
|
-
kernel.use(createApiRegistryPlugin({
|
|
228
|
+
await kernel.use(createApiRegistryPlugin({
|
|
227
229
|
conflictResolution: 'priority',
|
|
228
230
|
}));
|
|
229
231
|
|
|
@@ -275,8 +277,8 @@ describe('API Registry Plugin', () => {
|
|
|
275
277
|
},
|
|
276
278
|
};
|
|
277
279
|
|
|
278
|
-
kernel.use(corePlugin);
|
|
279
|
-
kernel.use(pluginOverride);
|
|
280
|
+
await kernel.use(corePlugin);
|
|
281
|
+
await kernel.use(pluginOverride);
|
|
280
282
|
await kernel.bootstrap();
|
|
281
283
|
|
|
282
284
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -290,7 +292,7 @@ describe('API Registry Plugin', () => {
|
|
|
290
292
|
});
|
|
291
293
|
|
|
292
294
|
it('should support cleanup on plugin unload', async () => {
|
|
293
|
-
kernel.use(createApiRegistryPlugin());
|
|
295
|
+
await kernel.use(createApiRegistryPlugin());
|
|
294
296
|
|
|
295
297
|
const dynamicPlugin: Plugin = {
|
|
296
298
|
name: 'dynamic-plugin',
|
|
@@ -318,7 +320,7 @@ describe('API Registry Plugin', () => {
|
|
|
318
320
|
},
|
|
319
321
|
};
|
|
320
322
|
|
|
321
|
-
kernel.use(dynamicPlugin);
|
|
323
|
+
await kernel.use(dynamicPlugin);
|
|
322
324
|
await kernel.bootstrap();
|
|
323
325
|
|
|
324
326
|
const registry = kernel.getService<ApiRegistry>('api-registry');
|
|
@@ -334,7 +336,7 @@ describe('API Registry Plugin', () => {
|
|
|
334
336
|
|
|
335
337
|
describe('API Registry Lifecycle', () => {
|
|
336
338
|
it('should be available during plugin start phase', async () => {
|
|
337
|
-
kernel.use(createApiRegistryPlugin());
|
|
339
|
+
await kernel.use(createApiRegistryPlugin());
|
|
338
340
|
|
|
339
341
|
let registryAvailable = false;
|
|
340
342
|
|
|
@@ -350,7 +352,7 @@ describe('API Registry Plugin', () => {
|
|
|
350
352
|
},
|
|
351
353
|
};
|
|
352
354
|
|
|
353
|
-
kernel.use(testPlugin);
|
|
355
|
+
await kernel.use(testPlugin);
|
|
354
356
|
await kernel.bootstrap();
|
|
355
357
|
|
|
356
358
|
expect(registryAvailable).toBe(true);
|
|
@@ -359,7 +361,7 @@ describe('API Registry Plugin', () => {
|
|
|
359
361
|
});
|
|
360
362
|
|
|
361
363
|
it('should provide consistent registry across all plugins', async () => {
|
|
362
|
-
kernel.use(createApiRegistryPlugin());
|
|
364
|
+
await kernel.use(createApiRegistryPlugin());
|
|
363
365
|
|
|
364
366
|
let registry1: ApiRegistry | undefined;
|
|
365
367
|
let registry2: ApiRegistry | undefined;
|
|
@@ -378,8 +380,8 @@ describe('API Registry Plugin', () => {
|
|
|
378
380
|
},
|
|
379
381
|
};
|
|
380
382
|
|
|
381
|
-
kernel.use(plugin1);
|
|
382
|
-
kernel.use(plugin2);
|
|
383
|
+
await kernel.use(plugin1);
|
|
384
|
+
await kernel.use(plugin2);
|
|
383
385
|
await kernel.bootstrap();
|
|
384
386
|
|
|
385
387
|
// Same registry instance should be shared
|
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
|
|