@objectstack/core 4.0.3 → 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 -465
  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,559 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- /**
4
- * API Registry Example
5
- *
6
- * Demonstrates how to use the API Registry in the ObjectStack kernel
7
- * to register and discover API endpoints across plugins.
8
- */
9
-
10
- import { ObjectKernel, createApiRegistryPlugin, ApiRegistry } from '@objectstack/core';
11
- import type { Plugin } from '@objectstack/core';
12
- import type { ApiRegistryEntry } from '@objectstack/spec/api';
13
-
14
- // Example 1: Basic API Registration
15
- async function example1_BasicApiRegistration() {
16
- console.log('\n=== Example 1: Basic API Registration ===\n');
17
-
18
- const kernel = new ObjectKernel();
19
-
20
- // Register API Registry plugin with default settings
21
- kernel.use(createApiRegistryPlugin());
22
-
23
- // Create a plugin that registers a simple REST API
24
- const customerPlugin: Plugin = {
25
- name: 'customer-plugin',
26
- version: '1.0.0',
27
- init: async (ctx) => {
28
- const registry = ctx.getService<ApiRegistry>('api-registry');
29
-
30
- const customerApi: ApiRegistryEntry = {
31
- id: 'customer_api',
32
- name: 'Customer Management API',
33
- type: 'rest',
34
- version: 'v1',
35
- basePath: '/api/v1/customers',
36
- description: 'CRUD operations for customer records',
37
- endpoints: [
38
- {
39
- id: 'list_customers',
40
- method: 'GET',
41
- path: '/api/v1/customers',
42
- summary: 'List all customers',
43
- parameters: [
44
- {
45
- name: 'limit',
46
- in: 'query',
47
- schema: { type: 'number' },
48
- description: 'Maximum number of results',
49
- },
50
- {
51
- name: 'offset',
52
- in: 'query',
53
- schema: { type: 'number' },
54
- description: 'Offset for pagination',
55
- },
56
- ],
57
- responses: [
58
- {
59
- statusCode: 200,
60
- description: 'Customers retrieved successfully',
61
- schema: {
62
- type: 'array',
63
- items: {
64
- type: 'object',
65
- properties: {
66
- id: { type: 'string' },
67
- name: { type: 'string' },
68
- email: { type: 'string' },
69
- },
70
- },
71
- },
72
- },
73
- ],
74
- },
75
- {
76
- id: 'get_customer',
77
- method: 'GET',
78
- path: '/api/v1/customers/:id',
79
- summary: 'Get customer by ID',
80
- requiredPermissions: ['customer.read'], // RBAC integration
81
- parameters: [
82
- {
83
- name: 'id',
84
- in: 'path',
85
- required: true,
86
- schema: { type: 'string', format: 'uuid' },
87
- },
88
- ],
89
- responses: [
90
- {
91
- statusCode: 200,
92
- description: 'Customer found',
93
- },
94
- {
95
- statusCode: 404,
96
- description: 'Customer not found',
97
- },
98
- ],
99
- },
100
- {
101
- id: 'create_customer',
102
- method: 'POST',
103
- path: '/api/v1/customers',
104
- summary: 'Create new customer',
105
- requiredPermissions: ['customer.create'],
106
- requestBody: {
107
- required: true,
108
- contentType: 'application/json',
109
- schema: {
110
- type: 'object',
111
- properties: {
112
- name: { type: 'string' },
113
- email: { type: 'string', format: 'email' },
114
- },
115
- },
116
- },
117
- responses: [
118
- {
119
- statusCode: 201,
120
- description: 'Customer created',
121
- },
122
- ],
123
- },
124
- ],
125
- metadata: {
126
- status: 'active',
127
- tags: ['customer', 'crm', 'data'],
128
- owner: 'sales_team',
129
- },
130
- };
131
-
132
- registry.registerApi(customerApi);
133
- ctx.logger.info('Customer API registered', {
134
- endpointCount: customerApi.endpoints.length,
135
- });
136
- },
137
- };
138
-
139
- kernel.use(customerPlugin);
140
- await kernel.bootstrap();
141
-
142
- // Access the registry
143
- const registry = kernel.getService<ApiRegistry>('api-registry');
144
- const snapshot = registry.getRegistry();
145
-
146
- console.log(`Total APIs: ${snapshot.totalApis}`);
147
- console.log(`Total Endpoints: ${snapshot.totalEndpoints}`);
148
- console.log('\nRegistered APIs:');
149
- snapshot.apis.forEach((api) => {
150
- console.log(` - ${api.name} (${api.type}) - ${api.endpoints.length} endpoints`);
151
- });
152
-
153
- await kernel.shutdown();
154
- }
155
-
156
- // Example 2: Multi-Plugin API Discovery
157
- async function example2_MultiPluginDiscovery() {
158
- console.log('\n=== Example 2: Multi-Plugin API Discovery ===\n');
159
-
160
- const kernel = new ObjectKernel();
161
- kernel.use(createApiRegistryPlugin());
162
-
163
- // Data Plugin - REST APIs
164
- const dataPlugin: Plugin = {
165
- name: 'data-plugin',
166
- init: async (ctx) => {
167
- const registry = ctx.getService<ApiRegistry>('api-registry');
168
-
169
- registry.registerApi({
170
- id: 'customer_api',
171
- name: 'Customer API',
172
- type: 'rest',
173
- version: 'v1',
174
- basePath: '/api/v1/customers',
175
- endpoints: [
176
- {
177
- id: 'get_customers',
178
- method: 'GET',
179
- path: '/api/v1/customers',
180
- responses: [],
181
- },
182
- ],
183
- metadata: {
184
- status: 'active',
185
- tags: ['data', 'crm'],
186
- },
187
- });
188
-
189
- registry.registerApi({
190
- id: 'product_api',
191
- name: 'Product API',
192
- type: 'rest',
193
- version: 'v1',
194
- basePath: '/api/v1/products',
195
- endpoints: [
196
- {
197
- id: 'get_products',
198
- method: 'GET',
199
- path: '/api/v1/products',
200
- responses: [],
201
- },
202
- ],
203
- metadata: {
204
- status: 'active',
205
- tags: ['data', 'inventory'],
206
- },
207
- });
208
- },
209
- };
210
-
211
- // GraphQL Plugin
212
- const graphqlPlugin: Plugin = {
213
- name: 'graphql-plugin',
214
- init: async (ctx) => {
215
- const registry = ctx.getService<ApiRegistry>('api-registry');
216
-
217
- registry.registerApi({
218
- id: 'graphql_api',
219
- name: 'GraphQL API',
220
- type: 'graphql',
221
- version: 'v1',
222
- basePath: '/graphql',
223
- endpoints: [
224
- {
225
- id: 'query',
226
- path: '/graphql',
227
- summary: 'GraphQL Query Endpoint',
228
- responses: [],
229
- },
230
- ],
231
- metadata: {
232
- status: 'active',
233
- tags: ['query', 'flexible'],
234
- },
235
- });
236
- },
237
- };
238
-
239
- // Analytics Plugin - Beta API
240
- const analyticsPlugin: Plugin = {
241
- name: 'analytics-plugin',
242
- init: async (ctx) => {
243
- const registry = ctx.getService<ApiRegistry>('api-registry');
244
-
245
- registry.registerApi({
246
- id: 'analytics_api',
247
- name: 'Analytics API',
248
- type: 'rest',
249
- version: 'v1',
250
- basePath: '/api/v1/analytics',
251
- endpoints: [
252
- {
253
- id: 'get_reports',
254
- method: 'GET',
255
- path: '/api/v1/analytics/reports',
256
- responses: [],
257
- },
258
- ],
259
- metadata: {
260
- status: 'beta',
261
- tags: ['analytics', 'reporting'],
262
- },
263
- });
264
- },
265
- };
266
-
267
- kernel.use(dataPlugin);
268
- kernel.use(graphqlPlugin);
269
- kernel.use(analyticsPlugin);
270
- await kernel.bootstrap();
271
-
272
- const registry = kernel.getService<ApiRegistry>('api-registry');
273
-
274
- // Discovery 1: Find all REST APIs
275
- console.log('All REST APIs:');
276
- const restApis = registry.findApis({ type: 'rest' });
277
- restApis.apis.forEach((api) => console.log(` - ${api.name}`));
278
-
279
- // Discovery 2: Find active APIs
280
- console.log('\nActive APIs:');
281
- const activeApis = registry.findApis({ status: 'active' });
282
- console.log(` Total: ${activeApis.total}`);
283
-
284
- // Discovery 3: Find data-related APIs
285
- console.log('\nData-related APIs:');
286
- const dataApis = registry.findApis({ tags: ['data'] });
287
- dataApis.apis.forEach((api) => console.log(` - ${api.name}`));
288
-
289
- // Discovery 4: Search by name
290
- console.log('\nSearch for "analytics":');
291
- const analyticsApis = registry.findApis({ search: 'analytics' });
292
- analyticsApis.apis.forEach((api) => console.log(` - ${api.name} (${api.metadata?.status})`));
293
-
294
- await kernel.shutdown();
295
- }
296
-
297
- // Example 3: Route Conflict Resolution
298
- async function example3_ConflictResolution() {
299
- console.log('\n=== Example 3: Route Conflict Resolution ===\n');
300
-
301
- const kernel = new ObjectKernel();
302
-
303
- // Use priority-based conflict resolution
304
- kernel.use(
305
- createApiRegistryPlugin({
306
- conflictResolution: 'priority',
307
- })
308
- );
309
-
310
- // Core Plugin - High priority
311
- const corePlugin: Plugin = {
312
- name: 'core-plugin',
313
- init: async (ctx) => {
314
- const registry = ctx.getService<ApiRegistry>('api-registry');
315
-
316
- registry.registerApi({
317
- id: 'core_data_api',
318
- name: 'Core Data API',
319
- type: 'rest',
320
- version: 'v1',
321
- basePath: '/api',
322
- endpoints: [
323
- {
324
- id: 'core_data',
325
- method: 'GET',
326
- path: '/api/data/:object',
327
- priority: 900, // High priority
328
- summary: 'Core data endpoint (generic)',
329
- responses: [],
330
- },
331
- ],
332
- });
333
-
334
- ctx.logger.info('Core API registered with priority 900');
335
- },
336
- };
337
-
338
- // Custom Plugin - Medium priority
339
- const customPlugin: Plugin = {
340
- name: 'custom-plugin',
341
- init: async (ctx) => {
342
- const registry = ctx.getService<ApiRegistry>('api-registry');
343
-
344
- registry.registerApi({
345
- id: 'custom_data_api',
346
- name: 'Custom Data API',
347
- type: 'rest',
348
- version: 'v1',
349
- basePath: '/api',
350
- endpoints: [
351
- {
352
- id: 'custom_data',
353
- method: 'GET',
354
- path: '/api/data/:object',
355
- priority: 300, // Lower priority
356
- summary: 'Custom data endpoint (specialized)',
357
- responses: [],
358
- },
359
- ],
360
- });
361
-
362
- ctx.logger.info('Custom API registered with priority 300');
363
- },
364
- };
365
-
366
- kernel.use(corePlugin);
367
- kernel.use(customPlugin);
368
- await kernel.bootstrap();
369
-
370
- const registry = kernel.getService<ApiRegistry>('api-registry');
371
-
372
- // Check which endpoint won
373
- const winner = registry.findEndpointByRoute('GET', '/api/data/:object');
374
- console.log('\nConflict Resolution Result:');
375
- console.log(` Route: GET /api/data/:object`);
376
- console.log(` Winner: ${winner?.api.name}`);
377
- console.log(` Endpoint: ${winner?.endpoint.summary}`);
378
- console.log(` Priority: ${winner?.endpoint.priority}`);
379
-
380
- await kernel.shutdown();
381
- }
382
-
383
- // Example 4: Plugin-specific APIs with Custom Protocol
384
- async function example4_CustomProtocol() {
385
- console.log('\n=== Example 4: Custom Protocol Support ===\n');
386
-
387
- const kernel = new ObjectKernel();
388
- kernel.use(createApiRegistryPlugin());
389
-
390
- const websocketPlugin: Plugin = {
391
- name: 'websocket-plugin',
392
- init: async (ctx) => {
393
- const registry = ctx.getService<ApiRegistry>('api-registry');
394
-
395
- registry.registerApi({
396
- id: 'realtime_api',
397
- name: 'Real-time WebSocket API',
398
- type: 'websocket',
399
- version: 'v1',
400
- basePath: '/ws',
401
- endpoints: [
402
- {
403
- id: 'customer_updates',
404
- path: '/ws/customers',
405
- summary: 'Customer update notifications',
406
- protocolConfig: {
407
- subProtocol: 'websocket',
408
- eventName: 'customer.updated',
409
- direction: 'server-to-client',
410
- },
411
- responses: [],
412
- },
413
- {
414
- id: 'order_updates',
415
- path: '/ws/orders',
416
- summary: 'Order update notifications',
417
- protocolConfig: {
418
- subProtocol: 'websocket',
419
- eventName: 'order.updated',
420
- direction: 'bidirectional',
421
- },
422
- responses: [],
423
- },
424
- ],
425
- metadata: {
426
- status: 'active',
427
- tags: ['realtime', 'websocket'],
428
- pluginSource: 'websocket-plugin',
429
- },
430
- });
431
- },
432
- };
433
-
434
- kernel.use(websocketPlugin);
435
- await kernel.bootstrap();
436
-
437
- const registry = kernel.getService<ApiRegistry>('api-registry');
438
- const wsApis = registry.findApis({ type: 'websocket' });
439
-
440
- console.log('WebSocket APIs:');
441
- wsApis.apis.forEach((api) => {
442
- console.log(`\n${api.name}:`);
443
- api.endpoints.forEach((endpoint) => {
444
- console.log(` - ${endpoint.summary}`);
445
- console.log(` Event: ${endpoint.protocolConfig?.eventName}`);
446
- console.log(` Direction: ${endpoint.protocolConfig?.direction}`);
447
- });
448
- });
449
-
450
- await kernel.shutdown();
451
- }
452
-
453
- // Example 5: Dynamic Schema Linking with ObjectQL
454
- async function example5_DynamicSchemas() {
455
- console.log('\n=== Example 5: Dynamic Schema Linking ===\n');
456
-
457
- const kernel = new ObjectKernel();
458
- kernel.use(createApiRegistryPlugin());
459
-
460
- const dynamicPlugin: Plugin = {
461
- name: 'dynamic-plugin',
462
- init: async (ctx) => {
463
- const registry = ctx.getService<ApiRegistry>('api-registry');
464
-
465
- registry.registerApi({
466
- id: 'dynamic_customer_api',
467
- name: 'Dynamic Customer API',
468
- type: 'rest',
469
- version: 'v1',
470
- basePath: '/api/v1/customers',
471
- endpoints: [
472
- {
473
- id: 'get_customer_dynamic',
474
- method: 'GET',
475
- path: '/api/v1/customers/:id',
476
- summary: 'Get customer (with dynamic schema)',
477
- responses: [
478
- {
479
- statusCode: 200,
480
- description: 'Customer retrieved',
481
- // Dynamic schema linked to ObjectQL
482
- //
483
- // IMPORTANT: The API Registry stores this ObjectQL reference as-is.
484
- // The actual schema resolution (expanding the reference into a full JSON Schema)
485
- // is performed by downstream tools:
486
- // - API Gateway: For runtime request/response validation
487
- // - OpenAPI/Swagger Generator: For API documentation generation
488
- // - GraphQL Schema Builder: For GraphQL type generation
489
- //
490
- // The Registry's responsibility is to STORE the reference metadata,
491
- // not to resolve or transform it.
492
- schema: {
493
- $ref: {
494
- objectId: 'customer', // References ObjectQL object
495
- excludeFields: ['password_hash', 'internal_notes'], // Exclude sensitive fields
496
- includeRelated: ['account', 'primary_contact'], // Include related objects
497
- },
498
- },
499
- },
500
- ],
501
- },
502
- ],
503
- });
504
-
505
- ctx.logger.info('Dynamic Customer API registered with ObjectQL schema references');
506
- },
507
- };
508
-
509
- kernel.use(dynamicPlugin);
510
- await kernel.bootstrap();
511
-
512
- const registry = kernel.getService<ApiRegistry>('api-registry');
513
- const endpoint = registry.getEndpoint('dynamic_customer_api', 'get_customer_dynamic');
514
-
515
- console.log('Dynamic Endpoint:');
516
- console.log(` Path: ${endpoint?.path}`);
517
- console.log(` Summary: ${endpoint?.summary}`);
518
-
519
- if (endpoint?.responses?.[0]?.schema && '$ref' in endpoint.responses[0].schema) {
520
- const ref = endpoint.responses[0].schema.$ref;
521
- console.log('\n Schema Reference (stored as metadata):');
522
- console.log(` Object: ${ref.objectId}`);
523
- console.log(` Excluded Fields: ${ref.excludeFields?.join(', ')}`);
524
- console.log(` Included Related: ${ref.includeRelated?.join(', ')}`);
525
- console.log('\n ℹ️ Note: Schema resolution is handled by gateway/documentation tools,');
526
- console.log(' not by the API Registry itself.');
527
- }
528
-
529
- await kernel.shutdown();
530
- }
531
-
532
- // Run all examples
533
- async function main() {
534
- try {
535
- await example1_BasicApiRegistration();
536
- await example2_MultiPluginDiscovery();
537
- await example3_ConflictResolution();
538
- await example4_CustomProtocol();
539
- await example5_DynamicSchemas();
540
-
541
- console.log('\n=== All examples completed successfully! ===\n');
542
- } catch (error) {
543
- console.error('Example failed:', error);
544
- process.exit(1);
545
- }
546
- }
547
-
548
- // Only run if this file is executed directly
549
- if (import.meta.url === `file://${process.argv[1]}`) {
550
- main();
551
- }
552
-
553
- export {
554
- example1_BasicApiRegistration,
555
- example2_MultiPluginDiscovery,
556
- example3_ConflictResolution,
557
- example4_CustomProtocol,
558
- example5_DynamicSchemas,
559
- };