@objectstack/core 4.0.4 → 4.1.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.
Files changed (75) hide show
  1. package/README.md +95 -10
  2. package/dist/index.cjs +172 -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 +178 -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,393 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { ObjectKernel } from './kernel';
3
- import { createApiRegistryPlugin } from './api-registry-plugin';
4
- import { ApiRegistry } from './api-registry';
5
- import type { Plugin } from './types';
6
- import type { ApiRegistryEntryInput } from '@objectstack/spec/api';
7
-
8
- describe('API Registry Plugin', () => {
9
- let kernel: ObjectKernel;
10
-
11
- beforeEach(() => {
12
- kernel = new ObjectKernel({
13
- skipSystemValidation: true
14
- });
15
- });
16
-
17
- describe('Plugin Registration', () => {
18
- it('should register API Registry as a service', async () => {
19
- await kernel.use(createApiRegistryPlugin());
20
- await kernel.bootstrap();
21
-
22
- const registry = kernel.getService<ApiRegistry>('api-registry');
23
- expect(registry).toBeDefined();
24
- expect(registry).toBeInstanceOf(ApiRegistry);
25
-
26
- await kernel.shutdown();
27
- });
28
-
29
- it('should register with custom conflict resolution', async () => {
30
- await kernel.use(createApiRegistryPlugin({
31
- conflictResolution: 'priority',
32
- version: '2.0.0',
33
- }));
34
- await kernel.bootstrap();
35
-
36
- const registry = kernel.getService<ApiRegistry>('api-registry');
37
- const snapshot = registry.getRegistry();
38
- expect(snapshot.conflictResolution).toBe('priority');
39
- expect(snapshot.version).toBe('2.0.0');
40
-
41
- await kernel.shutdown();
42
- });
43
- });
44
-
45
- describe('Integration with Plugins', () => {
46
- it('should allow plugins to register APIs', async () => {
47
- await kernel.use(createApiRegistryPlugin());
48
-
49
- const testPlugin: Plugin = {
50
- name: 'test-plugin',
51
- init: async (ctx) => {
52
- const registry = ctx.getService<ApiRegistry>('api-registry');
53
-
54
- const api: ApiRegistryEntryInput = {
55
- id: 'test_api',
56
- name: 'Test API',
57
- type: 'rest',
58
- version: 'v1',
59
- basePath: '/api/test',
60
- endpoints: [
61
- {
62
- id: 'get_test',
63
- method: 'GET',
64
- path: '/api/test/hello',
65
- summary: 'Test endpoint',
66
- responses: [
67
- {
68
- statusCode: 200,
69
- description: 'Success',
70
- },
71
- ],
72
- },
73
- ],
74
- };
75
-
76
- registry.registerApi(api);
77
- },
78
- };
79
-
80
- await kernel.use(testPlugin);
81
- await kernel.bootstrap();
82
-
83
- const registry = kernel.getService<ApiRegistry>('api-registry');
84
- const api = registry.getApi('test_api');
85
- expect(api).toBeDefined();
86
- expect(api?.name).toBe('Test API');
87
- expect(api?.endpoints.length).toBe(1);
88
-
89
- await kernel.shutdown();
90
- });
91
-
92
- it('should allow multiple plugins to register APIs', async () => {
93
- await kernel.use(createApiRegistryPlugin());
94
-
95
- const plugin1: Plugin = {
96
- name: 'plugin-1',
97
- init: async (ctx) => {
98
- const registry = ctx.getService<ApiRegistry>('api-registry');
99
- registry.registerApi({
100
- id: 'api1',
101
- name: 'API 1',
102
- type: 'rest',
103
- version: 'v1',
104
- basePath: '/api/plugin1',
105
- endpoints: [
106
- {
107
- id: 'endpoint1',
108
- method: 'GET',
109
- path: '/api/plugin1/data',
110
- responses: [],
111
- },
112
- ],
113
- });
114
- },
115
- };
116
-
117
- const plugin2: Plugin = {
118
- name: 'plugin-2',
119
- init: async (ctx) => {
120
- const registry = ctx.getService<ApiRegistry>('api-registry');
121
- registry.registerApi({
122
- id: 'api2',
123
- name: 'API 2',
124
- type: 'graphql',
125
- version: 'v1',
126
- basePath: '/graphql',
127
- endpoints: [
128
- {
129
- id: 'query',
130
- path: '/graphql',
131
- responses: [],
132
- },
133
- ],
134
- });
135
- },
136
- };
137
-
138
- await kernel.use(plugin1);
139
- await kernel.use(plugin2);
140
- await kernel.bootstrap();
141
-
142
- const registry = kernel.getService<ApiRegistry>('api-registry');
143
- const stats = registry.getStats();
144
- expect(stats.totalApis).toBe(2);
145
- expect(stats.apisByType.rest).toBe(1);
146
- expect(stats.apisByType.graphql).toBe(1);
147
-
148
- await kernel.shutdown();
149
- });
150
-
151
- it('should support API discovery across plugins', async () => {
152
- await kernel.use(createApiRegistryPlugin());
153
-
154
- const dataPlugin: Plugin = {
155
- name: 'data-plugin',
156
- init: async (ctx) => {
157
- const registry = ctx.getService<ApiRegistry>('api-registry');
158
- registry.registerApi({
159
- id: 'customer_api',
160
- name: 'Customer API',
161
- type: 'rest',
162
- version: 'v1',
163
- basePath: '/api/v1/customers',
164
- endpoints: [],
165
- metadata: {
166
- status: 'active',
167
- tags: ['crm', 'data'],
168
- },
169
- });
170
-
171
- registry.registerApi({
172
- id: 'product_api',
173
- name: 'Product API',
174
- type: 'rest',
175
- version: 'v1',
176
- basePath: '/api/v1/products',
177
- endpoints: [],
178
- metadata: {
179
- status: 'active',
180
- tags: ['inventory', 'data'],
181
- },
182
- });
183
- },
184
- };
185
-
186
- const analyticsPlugin: Plugin = {
187
- name: 'analytics-plugin',
188
- init: async (ctx) => {
189
- const registry = ctx.getService<ApiRegistry>('api-registry');
190
- registry.registerApi({
191
- id: 'analytics_api',
192
- name: 'Analytics API',
193
- type: 'rest',
194
- version: 'v1',
195
- basePath: '/api/v1/analytics',
196
- endpoints: [],
197
- metadata: {
198
- status: 'beta',
199
- tags: ['analytics', 'reporting'],
200
- },
201
- });
202
- },
203
- };
204
-
205
- await kernel.use(dataPlugin);
206
- await kernel.use(analyticsPlugin);
207
- await kernel.bootstrap();
208
-
209
- const registry = kernel.getService<ApiRegistry>('api-registry');
210
-
211
- // Find all data APIs
212
- const dataApis = registry.findApis({ tags: ['data'] });
213
- expect(dataApis.total).toBe(2);
214
-
215
- // Find active APIs
216
- const activeApis = registry.findApis({ status: 'active' });
217
- expect(activeApis.total).toBe(2);
218
-
219
- // Find CRM APIs
220
- const crmApis = registry.findApis({ tags: ['crm'] });
221
- expect(crmApis.total).toBe(1);
222
- expect(crmApis.apis[0].id).toBe('customer_api');
223
-
224
- await kernel.shutdown();
225
- });
226
-
227
- it('should handle route conflicts based on strategy', async () => {
228
- await kernel.use(createApiRegistryPlugin({
229
- conflictResolution: 'priority',
230
- }));
231
-
232
- const corePlugin: Plugin = {
233
- name: 'core-plugin',
234
- init: async (ctx) => {
235
- const registry = ctx.getService<ApiRegistry>('api-registry');
236
- registry.registerApi({
237
- id: 'core_api',
238
- name: 'Core API',
239
- type: 'rest',
240
- version: 'v1',
241
- basePath: '/api',
242
- endpoints: [
243
- {
244
- id: 'core_endpoint',
245
- method: 'GET',
246
- path: '/api/data/:object',
247
- priority: 900, // High priority
248
- summary: 'Core data endpoint',
249
- responses: [],
250
- },
251
- ],
252
- });
253
- },
254
- };
255
-
256
- const pluginOverride: Plugin = {
257
- name: 'plugin-override',
258
- init: async (ctx) => {
259
- const registry = ctx.getService<ApiRegistry>('api-registry');
260
- registry.registerApi({
261
- id: 'plugin_api',
262
- name: 'Plugin API',
263
- type: 'rest',
264
- version: 'v1',
265
- basePath: '/api',
266
- endpoints: [
267
- {
268
- id: 'plugin_endpoint',
269
- method: 'GET',
270
- path: '/api/data/:object',
271
- priority: 300, // Lower priority
272
- summary: 'Plugin data endpoint',
273
- responses: [],
274
- },
275
- ],
276
- });
277
- },
278
- };
279
-
280
- await kernel.use(corePlugin);
281
- await kernel.use(pluginOverride);
282
- await kernel.bootstrap();
283
-
284
- const registry = kernel.getService<ApiRegistry>('api-registry');
285
- const result = registry.findEndpointByRoute('GET', '/api/data/:object');
286
-
287
- // Core API should win due to higher priority
288
- expect(result?.api.id).toBe('core_api');
289
- expect(result?.endpoint.id).toBe('core_endpoint');
290
-
291
- await kernel.shutdown();
292
- });
293
-
294
- it('should support cleanup on plugin unload', async () => {
295
- await kernel.use(createApiRegistryPlugin());
296
-
297
- const dynamicPlugin: Plugin = {
298
- name: 'dynamic-plugin',
299
- init: async (ctx) => {
300
- const registry = ctx.getService<ApiRegistry>('api-registry');
301
- registry.registerApi({
302
- id: 'dynamic_api',
303
- name: 'Dynamic API',
304
- type: 'rest',
305
- version: 'v1',
306
- basePath: '/api/dynamic',
307
- endpoints: [
308
- {
309
- id: 'test',
310
- method: 'GET',
311
- path: '/api/dynamic/test',
312
- responses: [],
313
- },
314
- ],
315
- });
316
- },
317
- destroy: async () => {
318
- // In a real scenario, this would use ctx to access registry
319
- // For now, we'll test the registry's unregister capability
320
- },
321
- };
322
-
323
- await kernel.use(dynamicPlugin);
324
- await kernel.bootstrap();
325
-
326
- const registry = kernel.getService<ApiRegistry>('api-registry');
327
- expect(registry.getApi('dynamic_api')).toBeDefined();
328
-
329
- // Unregister the API
330
- registry.unregisterApi('dynamic_api');
331
- expect(registry.getApi('dynamic_api')).toBeUndefined();
332
-
333
- await kernel.shutdown();
334
- });
335
- });
336
-
337
- describe('API Registry Lifecycle', () => {
338
- it('should be available during plugin start phase', async () => {
339
- await kernel.use(createApiRegistryPlugin());
340
-
341
- let registryAvailable = false;
342
-
343
- const testPlugin: Plugin = {
344
- name: 'test-plugin',
345
- init: async () => {
346
- // Init phase
347
- },
348
- start: async (ctx) => {
349
- // Start phase - registry should be available
350
- const registry = ctx.getService<ApiRegistry>('api-registry');
351
- registryAvailable = registry !== undefined;
352
- },
353
- };
354
-
355
- await kernel.use(testPlugin);
356
- await kernel.bootstrap();
357
-
358
- expect(registryAvailable).toBe(true);
359
-
360
- await kernel.shutdown();
361
- });
362
-
363
- it('should provide consistent registry across all plugins', async () => {
364
- await kernel.use(createApiRegistryPlugin());
365
-
366
- let registry1: ApiRegistry | undefined;
367
- let registry2: ApiRegistry | undefined;
368
-
369
- const plugin1: Plugin = {
370
- name: 'plugin-1',
371
- init: async (ctx) => {
372
- registry1 = ctx.getService<ApiRegistry>('api-registry');
373
- },
374
- };
375
-
376
- const plugin2: Plugin = {
377
- name: 'plugin-2',
378
- init: async (ctx) => {
379
- registry2 = ctx.getService<ApiRegistry>('api-registry');
380
- },
381
- };
382
-
383
- await kernel.use(plugin1);
384
- await kernel.use(plugin2);
385
- await kernel.bootstrap();
386
-
387
- // Same registry instance should be shared
388
- expect(registry1).toBe(registry2);
389
-
390
- await kernel.shutdown();
391
- });
392
- });
393
- });
@@ -1,89 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { Plugin, PluginContext } from './types.js';
4
- import { ApiRegistry } from './api-registry.js';
5
- import type { ConflictResolutionStrategy } from '@objectstack/spec/api';
6
-
7
- /**
8
- * API Registry Plugin Configuration
9
- */
10
- export interface ApiRegistryPluginConfig {
11
- /**
12
- * Conflict resolution strategy for route conflicts
13
- * @default 'error'
14
- */
15
- conflictResolution?: ConflictResolutionStrategy;
16
-
17
- /**
18
- * Registry version
19
- * @default '1.0.0'
20
- */
21
- version?: string;
22
- }
23
-
24
- /**
25
- * API Registry Plugin
26
- *
27
- * Registers the API Registry service in the kernel, making it available
28
- * to all plugins for endpoint registration and discovery.
29
- *
30
- * **Usage:**
31
- * ```typescript
32
- * const kernel = new ObjectKernel();
33
- *
34
- * // Register API Registry Plugin
35
- * kernel.use(createApiRegistryPlugin({ conflictResolution: 'priority' }));
36
- *
37
- * // In other plugins, access the API Registry
38
- * const plugin: Plugin = {
39
- * name: 'my-plugin',
40
- * init: async (ctx) => {
41
- * const registry = ctx.getService<ApiRegistry>('api-registry');
42
- *
43
- * // Register plugin APIs
44
- * registry.registerApi({
45
- * id: 'my_plugin_api',
46
- * name: 'My Plugin API',
47
- * type: 'rest',
48
- * version: 'v1',
49
- * basePath: '/api/v1/my-plugin',
50
- * endpoints: [...]
51
- * });
52
- * }
53
- * };
54
- * ```
55
- *
56
- * @param config - Plugin configuration
57
- * @returns Plugin instance
58
- */
59
- export function createApiRegistryPlugin(
60
- config: ApiRegistryPluginConfig = {}
61
- ): Plugin {
62
- const {
63
- conflictResolution = 'error',
64
- version = '1.0.0',
65
- } = config;
66
-
67
- return {
68
- name: 'com.objectstack.core.api-registry',
69
- type: 'standard',
70
- version: '1.0.0',
71
-
72
- init: async (ctx: PluginContext) => {
73
- // Create API Registry instance
74
- const registry = new ApiRegistry(
75
- ctx.logger,
76
- conflictResolution,
77
- version
78
- );
79
-
80
- // Register as a service
81
- ctx.registerService('api-registry', registry);
82
-
83
- ctx.logger.info('API Registry plugin initialized', {
84
- conflictResolution,
85
- version,
86
- });
87
- },
88
- };
89
- }