@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.
Files changed (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +169 -507
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +24 -223
  5. package/dist/index.d.ts +24 -223
  6. package/dist/index.js +175 -505
  7. package/dist/index.js.map +1 -1
  8. package/dist/logger.cjs +177 -0
  9. package/dist/logger.cjs.map +1 -0
  10. package/dist/logger.d.cts +26 -0
  11. package/dist/logger.d.ts +26 -0
  12. package/dist/logger.js +158 -0
  13. package/dist/logger.js.map +1 -0
  14. package/package.json +36 -15
  15. package/.turbo/turbo-build.log +0 -22
  16. package/ADVANCED_FEATURES.md +0 -380
  17. package/API_REGISTRY.md +0 -392
  18. package/CHANGELOG.md +0 -472
  19. package/PHASE2_IMPLEMENTATION.md +0 -388
  20. package/REFACTORING_SUMMARY.md +0 -40
  21. package/examples/api-registry-example.ts +0 -559
  22. package/examples/kernel-features-example.ts +0 -311
  23. package/examples/phase2-integration.ts +0 -357
  24. package/src/api-registry-plugin.test.ts +0 -393
  25. package/src/api-registry-plugin.ts +0 -89
  26. package/src/api-registry.test.ts +0 -1089
  27. package/src/api-registry.ts +0 -739
  28. package/src/contracts/data-engine.ts +0 -57
  29. package/src/contracts/http-server.ts +0 -151
  30. package/src/contracts/logger.ts +0 -72
  31. package/src/dependency-resolver.test.ts +0 -287
  32. package/src/dependency-resolver.ts +0 -390
  33. package/src/fallbacks/fallbacks.test.ts +0 -281
  34. package/src/fallbacks/index.ts +0 -26
  35. package/src/fallbacks/memory-cache.ts +0 -34
  36. package/src/fallbacks/memory-i18n.ts +0 -112
  37. package/src/fallbacks/memory-job.ts +0 -23
  38. package/src/fallbacks/memory-metadata.ts +0 -50
  39. package/src/fallbacks/memory-queue.ts +0 -28
  40. package/src/health-monitor.test.ts +0 -81
  41. package/src/health-monitor.ts +0 -318
  42. package/src/hot-reload.ts +0 -382
  43. package/src/index.ts +0 -50
  44. package/src/kernel-base.ts +0 -273
  45. package/src/kernel.test.ts +0 -624
  46. package/src/kernel.ts +0 -631
  47. package/src/lite-kernel.test.ts +0 -248
  48. package/src/lite-kernel.ts +0 -137
  49. package/src/logger.test.ts +0 -116
  50. package/src/logger.ts +0 -355
  51. package/src/namespace-resolver.test.ts +0 -130
  52. package/src/namespace-resolver.ts +0 -188
  53. package/src/package-manager.test.ts +0 -225
  54. package/src/package-manager.ts +0 -428
  55. package/src/plugin-loader.test.ts +0 -421
  56. package/src/plugin-loader.ts +0 -484
  57. package/src/qa/adapter.ts +0 -16
  58. package/src/qa/http-adapter.ts +0 -116
  59. package/src/qa/index.ts +0 -5
  60. package/src/qa/runner.ts +0 -189
  61. package/src/security/index.ts +0 -50
  62. package/src/security/permission-manager.test.ts +0 -256
  63. package/src/security/permission-manager.ts +0 -338
  64. package/src/security/plugin-config-validator.test.ts +0 -276
  65. package/src/security/plugin-config-validator.ts +0 -193
  66. package/src/security/plugin-permission-enforcer.test.ts +0 -251
  67. package/src/security/plugin-permission-enforcer.ts +0 -436
  68. package/src/security/plugin-signature-verifier.ts +0 -403
  69. package/src/security/sandbox-runtime.ts +0 -462
  70. package/src/security/security-scanner.ts +0 -367
  71. package/src/types.ts +0 -120
  72. package/src/utils/env.test.ts +0 -62
  73. package/src/utils/env.ts +0 -53
  74. package/tsconfig.json +0 -10
  75. package/vitest.config.ts +0 -10
@@ -1,311 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * ObjectKernel Features Example
5
- *
6
- * Demonstrates advanced plugin features:
7
- * - Version compatibility
8
- * - Service factories with lifecycle management
9
- * - Plugin timeout control
10
- * - Startup failure rollback
11
- * - Health checks
12
- * - Performance metrics
13
- * - Graceful shutdown
14
- */
15
-
16
- import {
17
- ObjectKernel,
18
- PluginMetadata,
19
- ServiceLifecycle,
20
- PluginContext
21
- } from '../index.js';
22
-
23
- // ============================================================================
24
- // Example 1: Database Plugin with Health Checks
25
- // ============================================================================
26
-
27
- const databasePlugin: PluginMetadata = {
28
- name: 'database',
29
- version: '1.0.0',
30
- startupTimeout: 10000, // 10 second timeout
31
-
32
- async init(ctx: PluginContext) {
33
- ctx.logger.info('Initializing database plugin');
34
-
35
- // Register database service using factory
36
- // This creates a singleton that's initialized once
37
- const db = {
38
- connected: false,
39
- async connect() {
40
- ctx.logger.info('Connecting to database...');
41
- await new Promise(resolve => setTimeout(resolve, 100)); // Simulate connection
42
- this.connected = true;
43
- ctx.logger.info('Database connected');
44
- },
45
- async disconnect() {
46
- ctx.logger.info('Disconnecting from database...');
47
- this.connected = false;
48
- },
49
- async query(sql: string) {
50
- if (!this.connected) {
51
- throw new Error('Database not connected');
52
- }
53
- return { rows: [] };
54
- }
55
- };
56
-
57
- ctx.registerService('db', db);
58
- },
59
-
60
- async start(ctx: PluginContext) {
61
- const db = ctx.getService<any>('db');
62
- await db.connect();
63
- },
64
-
65
- async destroy() {
66
- // Cleanup on shutdown
67
- console.log('Cleaning up database connection');
68
- },
69
-
70
- async healthCheck() {
71
- // Health check returns status
72
- return {
73
- healthy: true,
74
- message: 'Database is operational',
75
- details: {
76
- connections: 5,
77
- responseTime: 45
78
- }
79
- };
80
- }
81
- };
82
-
83
- // ============================================================================
84
- // Example 2: API Plugin with Dependencies
85
- // ============================================================================
86
-
87
- const apiPlugin: PluginMetadata = {
88
- name: 'api',
89
- version: '2.1.0',
90
- dependencies: ['database'], // Requires database plugin to be loaded first
91
-
92
- async init(ctx: PluginContext) {
93
- ctx.logger.info('Initializing API plugin');
94
-
95
- // Access database service (guaranteed to exist due to dependencies)
96
- const db = ctx.getService<any>('db');
97
-
98
- const api = {
99
- async getUsers() {
100
- return await db.query('SELECT * FROM users');
101
- },
102
- async createUser(data: any) {
103
- return await db.query('INSERT INTO users VALUES ...', data);
104
- }
105
- };
106
-
107
- ctx.registerService('api', api);
108
- },
109
-
110
- async healthCheck() {
111
- return {
112
- healthy: true,
113
- message: 'API is ready',
114
- details: {
115
- routes: 15,
116
- activeRequests: 3
117
- }
118
- };
119
- }
120
- };
121
-
122
- // ============================================================================
123
- // Example 3: Cache Plugin with Scoped Services
124
- // ============================================================================
125
-
126
- const cachePlugin: PluginMetadata = {
127
- name: 'cache',
128
- version: '1.2.3',
129
-
130
- async init(ctx: PluginContext) {
131
- ctx.logger.info('Initializing cache plugin');
132
-
133
- // Simple in-memory cache
134
- const cache = new Map<string, any>();
135
-
136
- ctx.registerService('cache', {
137
- get(key: string) {
138
- return cache.get(key);
139
- },
140
- set(key: string, value: any) {
141
- cache.set(key, value);
142
- },
143
- clear() {
144
- cache.clear();
145
- }
146
- });
147
- },
148
-
149
- async healthCheck() {
150
- return {
151
- healthy: true,
152
- message: 'Cache is operational'
153
- };
154
- }
155
- };
156
-
157
- // ============================================================================
158
- // Example 4: Using Service Factories
159
- // ============================================================================
160
-
161
- async function setupServiceFactories(kernel: ObjectKernel) {
162
- // Singleton: Created once, shared across all requests
163
- kernel.registerServiceFactory(
164
- 'logger-service',
165
- (ctx) => {
166
- return {
167
- log: (message: string) => {
168
- ctx.logger.info(message);
169
- }
170
- };
171
- },
172
- ServiceLifecycle.SINGLETON
173
- );
174
-
175
- // Transient: New instance on every request
176
- kernel.registerServiceFactory(
177
- 'request-id',
178
- () => {
179
- return `req-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
180
- },
181
- ServiceLifecycle.TRANSIENT
182
- );
183
-
184
- // Scoped: One instance per scope (e.g., per HTTP request)
185
- kernel.registerServiceFactory(
186
- 'user-session',
187
- () => {
188
- return {
189
- id: Math.random().toString(36),
190
- data: new Map<string, any>()
191
- };
192
- },
193
- ServiceLifecycle.SCOPED
194
- );
195
- }
196
-
197
- // ============================================================================
198
- // Main Application
199
- // ============================================================================
200
-
201
- async function main() {
202
- console.log('🚀 Starting ObjectKernel Advanced Features Example\n');
203
-
204
- // Create object kernel with configuration
205
- const kernel = new ObjectKernel({
206
- logger: {
207
- level: 'info',
208
- format: 'pretty'
209
- },
210
- defaultStartupTimeout: 30000, // 30 seconds
211
- gracefulShutdown: true,
212
- shutdownTimeout: 60000, // 60 seconds
213
- rollbackOnFailure: true, // Rollback on failure
214
- });
215
-
216
- // Setup service factories
217
- await setupServiceFactories(kernel);
218
-
219
- // Register plugins
220
- await kernel.use(databasePlugin);
221
- await kernel.use(cachePlugin);
222
- await kernel.use(apiPlugin);
223
-
224
- console.log('📦 Plugins registered\n');
225
-
226
- // Bootstrap kernel
227
- console.log('⚡ Bootstrapping kernel...\n');
228
- await kernel.bootstrap();
229
-
230
- console.log('\n✅ Kernel started successfully!\n');
231
-
232
- // Show plugin metrics
233
- console.log('📊 Plugin Startup Metrics:');
234
- const metrics = kernel.getPluginMetrics();
235
- for (const [name, time] of metrics) {
236
- console.log(` ${name}: ${time}ms`);
237
- }
238
- console.log('');
239
-
240
- // Check plugin health
241
- console.log('🏥 Plugin Health Status:');
242
- const healthStatuses = await kernel.checkAllPluginsHealth();
243
- for (const [name, health] of healthStatuses) {
244
- const status = health.healthy ? '✅' : '❌';
245
- console.log(` ${status} ${name}: ${health.message}`);
246
- if (health.details) {
247
- console.log(` Details:`, health.details);
248
- }
249
- }
250
- console.log('');
251
-
252
- // Use services
253
- console.log('🔧 Using services:');
254
- const db = kernel.getService<any>('db');
255
- console.log(' Database connected:', db.connected);
256
-
257
- const cache = kernel.getService<any>('cache');
258
- cache.set('user:1', { name: 'John Doe' });
259
- console.log(' Cached user:', cache.get('user:1'));
260
-
261
- const api = kernel.getService<any>('api');
262
- console.log(' API ready:', !!api);
263
- console.log('');
264
-
265
- // Test service factories
266
- console.log('🏭 Testing Service Factories:');
267
-
268
- // Singleton - same instance
269
- const logger1 = await kernel.getServiceAsync('logger-service');
270
- const logger2 = await kernel.getServiceAsync('logger-service');
271
- console.log(' Singleton test:', logger1 === logger2 ? 'PASS ✅' : 'FAIL ❌');
272
-
273
- // Transient - different instances
274
- const id1 = await kernel.getServiceAsync('request-id');
275
- const id2 = await kernel.getServiceAsync('request-id');
276
- console.log(' Transient test:', id1 !== id2 ? 'PASS ✅' : 'FAIL ❌');
277
- console.log(' Generated IDs:', id1, 'and', id2);
278
-
279
- // Scoped - same within scope, different across scopes
280
- const session1a = await kernel.getServiceAsync('user-session', 'request-1');
281
- const session1b = await kernel.getServiceAsync('user-session', 'request-1');
282
- const session2 = await kernel.getServiceAsync('user-session', 'request-2');
283
- console.log(' Scoped (same scope):', session1a === session1b ? 'PASS ✅' : 'FAIL ❌');
284
- console.log(' Scoped (diff scope):', session1a !== session2 ? 'PASS ✅' : 'FAIL ❌');
285
- console.log('');
286
-
287
- // Register custom shutdown handler
288
- kernel.onShutdown(async () => {
289
- console.log('🧹 Running custom cleanup...');
290
- });
291
-
292
- // Simulate running for a bit
293
- console.log('⏳ Running for 2 seconds...\n');
294
- await new Promise(resolve => setTimeout(resolve, 2000));
295
-
296
- // Graceful shutdown
297
- console.log('🛑 Initiating graceful shutdown...\n');
298
- await kernel.shutdown();
299
-
300
- console.log('\n✅ Shutdown complete!\n');
301
- }
302
-
303
- // Run the example
304
- if (import.meta.url === `file://${process.argv[1]}`) {
305
- main().catch(error => {
306
- console.error('❌ Error:', error);
307
- process.exit(1);
308
- });
309
- }
310
-
311
- export { main };
@@ -1,357 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * Phase 2 Integration Example
5
- *
6
- * This example demonstrates how to use all Phase 2 components together
7
- * in a real-world scenario.
8
- */
9
-
10
- import {
11
- ObjectKernel,
12
- PluginHealthMonitor,
13
- HotReloadManager,
14
- DependencyResolver,
15
- PluginPermissionManager,
16
- PluginSandboxRuntime,
17
- PluginSecurityScanner
18
- } from '@objectstack/core';
19
-
20
- import type { Plugin } from '@objectstack/core';
21
- import type {
22
- PluginHealthCheck,
23
- HotReloadConfig,
24
- PermissionSet,
25
- SandboxConfig
26
- } from '@objectstack/spec/system';
27
-
28
- /**
29
- * Example: Enterprise Plugin Platform with Phase 2 Features
30
- */
31
- export class EnterprisePluginPlatform {
32
- private kernel: ObjectKernel;
33
- private healthMonitor: PluginHealthMonitor;
34
- private hotReload: HotReloadManager;
35
- private depResolver: DependencyResolver;
36
- private permManager: PluginPermissionManager;
37
- private sandbox: PluginSandboxRuntime;
38
- private scanner: PluginSecurityScanner;
39
-
40
- constructor() {
41
- // Initialize kernel
42
- this.kernel = new ObjectKernel({
43
- logger: {
44
- level: 'info',
45
- name: 'EnterprisePluginPlatform',
46
- },
47
- });
48
-
49
- // Initialize Phase 2 components
50
- this.healthMonitor = new PluginHealthMonitor(this.kernel.logger);
51
- this.hotReload = new HotReloadManager(this.kernel.logger);
52
- this.depResolver = new DependencyResolver(this.kernel.logger);
53
- this.permManager = new PluginPermissionManager(this.kernel.logger);
54
- this.sandbox = new PluginSandboxRuntime(this.kernel.logger);
55
- this.scanner = new PluginSecurityScanner(this.kernel.logger);
56
- }
57
-
58
- /**
59
- * Install and configure a plugin with full Phase 2 features
60
- */
61
- async installPlugin(
62
- plugin: Plugin,
63
- config: {
64
- health?: PluginHealthCheck;
65
- hotReload?: HotReloadConfig;
66
- permissions?: PermissionSet;
67
- sandbox?: SandboxConfig;
68
- securityScan?: boolean;
69
- }
70
- ): Promise<void> {
71
- const pluginName = plugin.name;
72
- const pluginVersion = plugin.version || '1.0.0';
73
-
74
- this.kernel.logger.info(`Installing plugin: ${pluginName} v${pluginVersion}`);
75
-
76
- // Step 1: Security Scan
77
- if (config.securityScan !== false) {
78
- this.kernel.logger.info('Running security scan...');
79
-
80
- const scanResult = await this.scanner.scan({
81
- pluginId: pluginName,
82
- version: pluginVersion,
83
- // In real implementation, would provide actual files and dependencies
84
- });
85
-
86
- if (!scanResult.passed) {
87
- throw new Error(
88
- `Security scan failed: Score ${scanResult.score}/100, ` +
89
- `Critical: ${scanResult.summary.critical}, ` +
90
- `High: ${scanResult.summary.high}`
91
- );
92
- }
93
-
94
- this.kernel.logger.info(
95
- `Security scan passed: ${scanResult.score}/100`
96
- );
97
- }
98
-
99
- // Step 2: Register Permissions
100
- if (config.permissions) {
101
- this.permManager.registerPermissions(pluginName, config.permissions);
102
-
103
- // Auto-grant all permissions (in production, would prompt user)
104
- this.permManager.grantAllPermissions(pluginName, 'system');
105
-
106
- this.kernel.logger.info(
107
- `Permissions registered: ${config.permissions.permissions.length} permissions`
108
- );
109
- }
110
-
111
- // Step 3: Create Sandbox
112
- if (config.sandbox) {
113
- this.sandbox.createSandbox(pluginName, config.sandbox);
114
- this.kernel.logger.info(`Sandbox created: ${config.sandbox.level} level`);
115
- }
116
-
117
- // Step 4: Register for Health Monitoring
118
- if (config.health) {
119
- this.healthMonitor.registerPlugin(pluginName, config.health);
120
- this.kernel.logger.info(
121
- `Health monitoring configured: ${config.health.interval}ms interval`
122
- );
123
- }
124
-
125
- // Step 5: Register for Hot Reload
126
- if (config.hotReload) {
127
- this.hotReload.registerPlugin(pluginName, config.hotReload);
128
- this.kernel.logger.info(
129
- `Hot reload enabled: ${config.hotReload.stateStrategy} state strategy`
130
- );
131
- }
132
-
133
- // Step 6: Register with Kernel
134
- this.kernel.use(plugin);
135
-
136
- this.kernel.logger.info(`Plugin ${pluginName} installed successfully`);
137
- }
138
-
139
- /**
140
- * Bootstrap the platform
141
- */
142
- async start(): Promise<void> {
143
- // Bootstrap kernel (will init and start all plugins)
144
- await this.kernel.bootstrap();
145
-
146
- // Start health monitoring for all registered plugins
147
- for (const [pluginName, plugin] of this.kernel['plugins']) {
148
- if (this.healthMonitor['healthChecks'].has(pluginName)) {
149
- this.healthMonitor.startMonitoring(pluginName, plugin);
150
- }
151
- }
152
-
153
- this.kernel.logger.info('Platform started successfully');
154
- }
155
-
156
- /**
157
- * Shutdown the platform
158
- */
159
- async shutdown(): Promise<void> {
160
- this.kernel.logger.info('Shutting down platform...');
161
-
162
- // Stop health monitoring
163
- this.healthMonitor.shutdown();
164
-
165
- // Shutdown sandbox
166
- this.sandbox.shutdown();
167
-
168
- // Shutdown kernel
169
- await this.kernel.shutdown();
170
-
171
- this.kernel.logger.info('Platform shutdown complete');
172
- }
173
-
174
- /**
175
- * Get platform health status
176
- */
177
- getHealthStatus(): Record<string, any> {
178
- const statuses = this.healthMonitor.getAllHealthStatuses();
179
- const summary: Record<string, any> = {
180
- totalPlugins: statuses.size,
181
- healthy: 0,
182
- degraded: 0,
183
- unhealthy: 0,
184
- failed: 0,
185
- plugins: {},
186
- };
187
-
188
- for (const [pluginName, status] of statuses) {
189
- summary[status]++;
190
- summary.plugins[pluginName] = {
191
- status,
192
- report: this.healthMonitor.getHealthReport(pluginName),
193
- };
194
- }
195
-
196
- return summary;
197
- }
198
-
199
- /**
200
- * Perform hot reload of a plugin
201
- */
202
- async reloadPlugin(pluginName: string): Promise<void> {
203
- this.kernel.logger.info(`Hot reloading plugin: ${pluginName}`);
204
-
205
- const plugin = this.kernel['plugins'].get(pluginName);
206
- if (!plugin) {
207
- throw new Error(`Plugin not found: ${pluginName}`);
208
- }
209
-
210
- // Get current state (simplified - would need plugin cooperation)
211
- const getState = () => ({
212
- timestamp: Date.now(),
213
- // ... plugin state
214
- });
215
-
216
- // Restore state (simplified - would need plugin cooperation)
217
- const restoreState = (state: Record<string, any>) => {
218
- this.kernel.logger.info(`Restoring state from ${new Date(state.timestamp)}`);
219
- // ... restore plugin state
220
- };
221
-
222
- await this.hotReload.reloadPlugin(
223
- pluginName,
224
- plugin,
225
- plugin.version || '1.0.0',
226
- getState,
227
- restoreState
228
- );
229
-
230
- this.kernel.logger.info(`Plugin ${pluginName} reloaded successfully`);
231
- }
232
- }
233
-
234
- /**
235
- * Example Usage
236
- */
237
- async function example() {
238
- const platform = new EnterprisePluginPlatform();
239
-
240
- // Define a sample plugin
241
- const myPlugin: Plugin = {
242
- name: 'com.example.my-plugin',
243
- version: '1.0.0',
244
- dependencies: ['com.objectstack.engine.objectql'],
245
-
246
- async init(ctx) {
247
- ctx.logger.info('MyPlugin initializing...');
248
- // Initialize plugin
249
- },
250
-
251
- async start(ctx) {
252
- ctx.logger.info('MyPlugin starting...');
253
- // Start plugin services
254
- },
255
-
256
- async destroy() {
257
- console.log('MyPlugin destroying...');
258
- // Cleanup
259
- },
260
- };
261
-
262
- // Install plugin with full Phase 2 features
263
- await platform.installPlugin(myPlugin, {
264
- // Health monitoring
265
- health: {
266
- interval: 30000, // Check every 30 seconds
267
- timeout: 5000,
268
- failureThreshold: 3,
269
- successThreshold: 1,
270
- autoRestart: true,
271
- maxRestartAttempts: 3,
272
- restartBackoff: 'exponential',
273
- },
274
-
275
- // Hot reload
276
- hotReload: {
277
- enabled: true,
278
- watchPatterns: ['plugins/my-plugin/**/*.ts'],
279
- debounceDelay: 1000,
280
- preserveState: true,
281
- stateStrategy: 'memory',
282
- shutdownTimeout: 30000,
283
- },
284
-
285
- // Permissions
286
- permissions: {
287
- permissions: [
288
- {
289
- id: 'read-data',
290
- resource: 'data.object',
291
- actions: ['read'],
292
- scope: 'plugin',
293
- description: 'Read object data',
294
- required: true,
295
- },
296
- {
297
- id: 'write-data',
298
- resource: 'data.object',
299
- actions: ['create', 'update'],
300
- scope: 'plugin',
301
- description: 'Write object data',
302
- required: false,
303
- },
304
- ],
305
- defaultGrant: 'prompt',
306
- },
307
-
308
- // Sandbox
309
- sandbox: {
310
- enabled: true,
311
- level: 'standard',
312
- filesystem: {
313
- mode: 'restricted',
314
- allowedPaths: ['/app/plugins/my-plugin'],
315
- deniedPaths: ['/etc', '/root'],
316
- },
317
- network: {
318
- mode: 'restricted',
319
- allowedHosts: ['api.example.com'],
320
- maxConnections: 10,
321
- },
322
- process: {
323
- allowSpawn: false,
324
- },
325
- memory: {
326
- maxHeap: 100 * 1024 * 1024, // 100 MB
327
- },
328
- },
329
-
330
- // Security scanning
331
- securityScan: true,
332
- });
333
-
334
- // Start platform
335
- await platform.start();
336
-
337
- // Get health status
338
- const health = platform.getHealthStatus();
339
- console.log('Platform Health:', health);
340
-
341
- // Simulate hot reload after some time
342
- setTimeout(async () => {
343
- await platform.reloadPlugin('com.example.my-plugin');
344
- }, 60000);
345
-
346
- // Shutdown on SIGINT
347
- process.on('SIGINT', async () => {
348
- await platform.shutdown();
349
- process.exit(0);
350
- });
351
- }
352
-
353
- // Run example if this file is executed directly (ES Module compatible)
354
- // Note: In ES modules, use import.meta.url instead of require.main
355
- if (import.meta.url === `file://${process.argv[1]}`) {
356
- example().catch(console.error);
357
- }