@objectstack/runtime 0.9.0 → 0.9.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @objectstack/runtime
2
2
 
3
+ ## 0.9.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Patch release for maintenance and stability improvements. All packages updated with unified versioning.
8
+ - Updated dependencies
9
+ - @objectstack/spec@0.9.1
10
+ - @objectstack/core@0.9.1
11
+ - @objectstack/types@0.9.1
12
+
3
13
  ## 0.8.2
4
14
 
5
15
  ### Patch Changes
package/README.md CHANGED
@@ -268,6 +268,302 @@ See the `examples/` directory for complete examples:
268
268
  4. **Use hooks**: Decouple plugins with event system
269
269
  5. **Handle errors**: Implement proper error handling in lifecycle methods
270
270
 
271
+ ## Common Plugin Patterns
272
+
273
+ ### Service Provider Pattern
274
+
275
+ ```typescript
276
+ import { Plugin, PluginContext } from '@objectstack/core';
277
+
278
+ export class DatabasePlugin implements Plugin {
279
+ name = 'database';
280
+ private connection: any;
281
+
282
+ async init(ctx: PluginContext) {
283
+ // Initialize connection
284
+ this.connection = await createConnection({
285
+ host: 'localhost',
286
+ database: 'myapp'
287
+ });
288
+
289
+ // Register as service
290
+ ctx.registerService('database', this.connection);
291
+
292
+ ctx.logger.info('Database connected');
293
+ }
294
+
295
+ async destroy() {
296
+ // Cleanup
297
+ await this.connection.close();
298
+ }
299
+ }
300
+ ```
301
+
302
+ ### Service Consumer Pattern
303
+
304
+ ```typescript
305
+ import { Plugin, PluginContext } from '@objectstack/core';
306
+
307
+ export class RepositoryPlugin implements Plugin {
308
+ name = 'repository';
309
+ dependencies = ['database']; // Ensure database loads first
310
+
311
+ async init(ctx: PluginContext) {
312
+ // Get dependency
313
+ const db = ctx.getService('database');
314
+
315
+ // Create and register repository
316
+ const repo = new UserRepository(db);
317
+ ctx.registerService('user-repository', repo);
318
+ }
319
+ }
320
+ ```
321
+
322
+ ### Event-Driven Pattern
323
+
324
+ ```typescript
325
+ import { Plugin, PluginContext } from '@objectstack/core';
326
+
327
+ // Publisher
328
+ export class DataPlugin implements Plugin {
329
+ name = 'data';
330
+
331
+ async init(ctx: PluginContext) {
332
+ const service = {
333
+ async create(entity: string, data: any) {
334
+ const result = await db.insert(entity, data);
335
+
336
+ // Trigger event
337
+ await ctx.trigger('data:created', { entity, data: result });
338
+
339
+ return result;
340
+ }
341
+ };
342
+
343
+ ctx.registerService('data', service);
344
+ }
345
+ }
346
+
347
+ // Subscriber
348
+ export class AuditPlugin implements Plugin {
349
+ name = 'audit';
350
+ dependencies = ['data'];
351
+
352
+ async init(ctx: PluginContext) {
353
+ // Listen to events
354
+ ctx.hook('data:created', async ({ entity, data }) => {
355
+ ctx.logger.info(`Audit: ${entity} created`, { id: data.id });
356
+
357
+ await auditLog.write({
358
+ action: 'create',
359
+ entity,
360
+ entityId: data.id,
361
+ timestamp: new Date()
362
+ });
363
+ });
364
+ }
365
+ }
366
+ ```
367
+
368
+ ### Configuration Pattern
369
+
370
+ ```typescript
371
+ import { Plugin, PluginContext } from '@objectstack/core';
372
+ import { z } from 'zod';
373
+
374
+ const ConfigSchema = z.object({
375
+ apiKey: z.string(),
376
+ endpoint: z.string().url(),
377
+ timeout: z.number().default(5000)
378
+ });
379
+
380
+ export class ApiPlugin implements Plugin {
381
+ name = 'api-client';
382
+
383
+ constructor(private config: z.infer<typeof ConfigSchema>) {
384
+ // Validate config
385
+ ConfigSchema.parse(config);
386
+ }
387
+
388
+ async init(ctx: PluginContext) {
389
+ const client = new ApiClient({
390
+ apiKey: this.config.apiKey,
391
+ endpoint: this.config.endpoint,
392
+ timeout: this.config.timeout
393
+ });
394
+
395
+ ctx.registerService('api-client', client);
396
+ }
397
+ }
398
+
399
+ // Usage
400
+ kernel.use(new ApiPlugin({
401
+ apiKey: process.env.API_KEY,
402
+ endpoint: 'https://api.example.com',
403
+ timeout: 10000
404
+ }));
405
+ ```
406
+
407
+ ### Factory Pattern
408
+
409
+ ```typescript
410
+ import { Plugin, PluginContext } from '@objectstack/core';
411
+
412
+ export class ConnectionPoolPlugin implements Plugin {
413
+ name = 'connection-pool';
414
+ private pool: any;
415
+
416
+ async init(ctx: PluginContext) {
417
+ this.pool = {
418
+ connections: new Map(),
419
+
420
+ getConnection(name: string) {
421
+ if (!this.connections.has(name)) {
422
+ this.connections.set(name, createConnection(name));
423
+ }
424
+ return this.connections.get(name);
425
+ },
426
+
427
+ closeAll() {
428
+ for (const conn of this.connections.values()) {
429
+ conn.close();
430
+ }
431
+ this.connections.clear();
432
+ }
433
+ };
434
+
435
+ ctx.registerService('connection-pool', this.pool);
436
+ }
437
+
438
+ async destroy() {
439
+ // Use stored reference from init phase
440
+ if (this.pool) {
441
+ this.pool.closeAll();
442
+ }
443
+ }
444
+ }
445
+ ```
446
+
447
+ ### Middleware Pattern
448
+
449
+ ```typescript
450
+ import { Plugin, PluginContext } from '@objectstack/core';
451
+
452
+ export class LoggingMiddleware implements Plugin {
453
+ name = 'logging-middleware';
454
+ dependencies = ['http-server'];
455
+
456
+ async start(ctx: PluginContext) {
457
+ const server = ctx.getService('http-server');
458
+
459
+ // Register middleware
460
+ server.use(async (req, res, next) => {
461
+ const start = Date.now();
462
+
463
+ ctx.logger.info('Request', {
464
+ method: req.method,
465
+ path: req.path
466
+ });
467
+
468
+ await next();
469
+
470
+ const duration = Date.now() - start;
471
+ ctx.logger.info('Response', {
472
+ method: req.method,
473
+ path: req.path,
474
+ status: res.statusCode,
475
+ duration
476
+ });
477
+ });
478
+ }
479
+ }
480
+ ```
481
+
482
+ ### Lazy Loading Pattern
483
+
484
+ ```typescript
485
+ import { Plugin, PluginContext } from '@objectstack/core';
486
+
487
+ export class HeavyServicePlugin implements Plugin {
488
+ name = 'heavy-service';
489
+ private instance: any = null;
490
+
491
+ async init(ctx: PluginContext) {
492
+ // Register factory instead of instance
493
+ const factory = {
494
+ async getInstance() {
495
+ if (!this.instance) {
496
+ ctx.logger.info('Lazy loading heavy service...');
497
+ this.instance = await loadHeavyService();
498
+ }
499
+ return this.instance;
500
+ }
501
+ };
502
+
503
+ ctx.registerService('heavy-service', factory);
504
+ }
505
+ }
506
+
507
+ // Usage
508
+ const factory = kernel.getService('heavy-service');
509
+ const service = await factory.getInstance(); // Loaded only when needed
510
+ ```
511
+
512
+ ### Health Check Pattern
513
+
514
+ ```typescript
515
+ import { Plugin, PluginContext } from '@objectstack/core';
516
+
517
+ export class HealthCheckPlugin implements Plugin {
518
+ name = 'health-check';
519
+ dependencies = ['http-server', 'database', 'cache'];
520
+
521
+ async start(ctx: PluginContext) {
522
+ const server = ctx.getService('http-server');
523
+
524
+ server.get('/health', async (req, res) => {
525
+ const checks = await Promise.all([
526
+ this.checkDatabase(ctx),
527
+ this.checkCache(ctx),
528
+ this.checkDiskSpace()
529
+ ]);
530
+
531
+ const healthy = checks.every(c => c.healthy);
532
+
533
+ res.status(healthy ? 200 : 503).json({
534
+ status: healthy ? 'healthy' : 'unhealthy',
535
+ checks
536
+ });
537
+ });
538
+ }
539
+
540
+ private async checkDatabase(ctx: PluginContext) {
541
+ try {
542
+ const db = ctx.getService('database');
543
+ await db.ping();
544
+ return { name: 'database', healthy: true };
545
+ } catch (error) {
546
+ return { name: 'database', healthy: false, error: error.message };
547
+ }
548
+ }
549
+
550
+ private async checkCache(ctx: PluginContext) {
551
+ try {
552
+ const cache = ctx.getService('cache');
553
+ await cache.ping();
554
+ return { name: 'cache', healthy: true };
555
+ } catch (error) {
556
+ return { name: 'cache', healthy: false, error: error.message };
557
+ }
558
+ }
559
+
560
+ private async checkDiskSpace() {
561
+ // Implementation
562
+ return { name: 'disk', healthy: true };
563
+ }
564
+ }
565
+ ```
566
+
271
567
  ## Documentation
272
568
 
273
569
  - [MiniKernel Guide](../../MINI_KERNEL_GUIDE.md) - Complete API documentation and patterns
package/dist/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export { AppPlugin } from './app-plugin.js';
4
4
  export { HttpServer } from './http-server.js';
5
5
  export { RestServer } from './rest-server.js';
6
6
  export { RouteManager, RouteGroupBuilder } from './route-manager.js';
7
+ export type { RouteEntry } from './route-manager.js';
7
8
  export { MiddlewareManager } from './middleware.js';
8
9
  export * from '@objectstack/core';
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@objectstack/runtime",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "ObjectStack Core Runtime & Query Engine",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "dependencies": {
9
- "@objectstack/core": "0.9.0",
10
- "@objectstack/types": "0.9.0",
11
- "@objectstack/spec": "0.9.0"
9
+ "@objectstack/core": "0.9.1",
10
+ "@objectstack/types": "0.9.1",
11
+ "@objectstack/spec": "0.9.1"
12
12
  },
13
13
  "devDependencies": {
14
14
  "typescript": "^5.0.0"
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export { AppPlugin } from './app-plugin.js';
9
9
  export { HttpServer } from './http-server.js';
10
10
  export { RestServer } from './rest-server.js';
11
11
  export { RouteManager, RouteGroupBuilder } from './route-manager.js';
12
+ export type { RouteEntry } from './route-manager.js';
12
13
  export { MiddlewareManager } from './middleware.js';
13
14
 
14
15
  // Export Types