@objectstack/core 1.0.4 → 1.0.6

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 (127) hide show
  1. package/.turbo/turbo-build.log +22 -0
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.cjs +4304 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1777 -0
  6. package/dist/index.d.ts +1776 -21
  7. package/dist/index.js +4246 -23
  8. package/dist/index.js.map +1 -0
  9. package/package.json +5 -5
  10. package/src/logger.ts +2 -2
  11. package/src/security/plugin-signature-verifier.ts +12 -11
  12. package/tsconfig.json +1 -3
  13. package/dist/api-registry-plugin.d.ts +0 -54
  14. package/dist/api-registry-plugin.d.ts.map +0 -1
  15. package/dist/api-registry-plugin.js +0 -53
  16. package/dist/api-registry-plugin.test.d.ts +0 -2
  17. package/dist/api-registry-plugin.test.d.ts.map +0 -1
  18. package/dist/api-registry-plugin.test.js +0 -334
  19. package/dist/api-registry.d.ts +0 -259
  20. package/dist/api-registry.d.ts.map +0 -1
  21. package/dist/api-registry.js +0 -600
  22. package/dist/api-registry.test.d.ts +0 -2
  23. package/dist/api-registry.test.d.ts.map +0 -1
  24. package/dist/api-registry.test.js +0 -957
  25. package/dist/contracts/data-engine.d.ts +0 -62
  26. package/dist/contracts/data-engine.d.ts.map +0 -1
  27. package/dist/contracts/data-engine.js +0 -1
  28. package/dist/contracts/http-server.d.ts +0 -119
  29. package/dist/contracts/http-server.d.ts.map +0 -1
  30. package/dist/contracts/http-server.js +0 -11
  31. package/dist/contracts/logger.d.ts +0 -63
  32. package/dist/contracts/logger.d.ts.map +0 -1
  33. package/dist/contracts/logger.js +0 -1
  34. package/dist/dependency-resolver.d.ts +0 -62
  35. package/dist/dependency-resolver.d.ts.map +0 -1
  36. package/dist/dependency-resolver.js +0 -317
  37. package/dist/dependency-resolver.test.d.ts +0 -2
  38. package/dist/dependency-resolver.test.d.ts.map +0 -1
  39. package/dist/dependency-resolver.test.js +0 -241
  40. package/dist/health-monitor.d.ts +0 -65
  41. package/dist/health-monitor.d.ts.map +0 -1
  42. package/dist/health-monitor.js +0 -269
  43. package/dist/health-monitor.test.d.ts +0 -2
  44. package/dist/health-monitor.test.d.ts.map +0 -1
  45. package/dist/health-monitor.test.js +0 -68
  46. package/dist/hot-reload.d.ts +0 -79
  47. package/dist/hot-reload.d.ts.map +0 -1
  48. package/dist/hot-reload.js +0 -313
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/kernel-base.d.ts +0 -84
  51. package/dist/kernel-base.d.ts.map +0 -1
  52. package/dist/kernel-base.js +0 -219
  53. package/dist/kernel.d.ts +0 -113
  54. package/dist/kernel.d.ts.map +0 -1
  55. package/dist/kernel.js +0 -472
  56. package/dist/kernel.test.d.ts +0 -2
  57. package/dist/kernel.test.d.ts.map +0 -1
  58. package/dist/kernel.test.js +0 -414
  59. package/dist/lite-kernel.d.ts +0 -55
  60. package/dist/lite-kernel.d.ts.map +0 -1
  61. package/dist/lite-kernel.js +0 -112
  62. package/dist/lite-kernel.test.d.ts +0 -2
  63. package/dist/lite-kernel.test.d.ts.map +0 -1
  64. package/dist/lite-kernel.test.js +0 -161
  65. package/dist/logger.d.ts +0 -71
  66. package/dist/logger.d.ts.map +0 -1
  67. package/dist/logger.js +0 -312
  68. package/dist/logger.test.d.ts +0 -2
  69. package/dist/logger.test.d.ts.map +0 -1
  70. package/dist/logger.test.js +0 -92
  71. package/dist/plugin-loader.d.ts +0 -164
  72. package/dist/plugin-loader.d.ts.map +0 -1
  73. package/dist/plugin-loader.js +0 -319
  74. package/dist/plugin-loader.test.d.ts +0 -2
  75. package/dist/plugin-loader.test.d.ts.map +0 -1
  76. package/dist/plugin-loader.test.js +0 -348
  77. package/dist/qa/adapter.d.ts +0 -14
  78. package/dist/qa/adapter.d.ts.map +0 -1
  79. package/dist/qa/adapter.js +0 -1
  80. package/dist/qa/http-adapter.d.ts +0 -16
  81. package/dist/qa/http-adapter.d.ts.map +0 -1
  82. package/dist/qa/http-adapter.js +0 -107
  83. package/dist/qa/index.d.ts +0 -4
  84. package/dist/qa/index.d.ts.map +0 -1
  85. package/dist/qa/index.js +0 -3
  86. package/dist/qa/runner.d.ts +0 -27
  87. package/dist/qa/runner.d.ts.map +0 -1
  88. package/dist/qa/runner.js +0 -157
  89. package/dist/security/index.d.ts +0 -17
  90. package/dist/security/index.d.ts.map +0 -1
  91. package/dist/security/index.js +0 -17
  92. package/dist/security/permission-manager.d.ts +0 -96
  93. package/dist/security/permission-manager.d.ts.map +0 -1
  94. package/dist/security/permission-manager.js +0 -235
  95. package/dist/security/permission-manager.test.d.ts +0 -2
  96. package/dist/security/permission-manager.test.d.ts.map +0 -1
  97. package/dist/security/permission-manager.test.js +0 -220
  98. package/dist/security/plugin-config-validator.d.ts +0 -79
  99. package/dist/security/plugin-config-validator.d.ts.map +0 -1
  100. package/dist/security/plugin-config-validator.js +0 -166
  101. package/dist/security/plugin-config-validator.test.d.ts +0 -2
  102. package/dist/security/plugin-config-validator.test.d.ts.map +0 -1
  103. package/dist/security/plugin-config-validator.test.js +0 -223
  104. package/dist/security/plugin-permission-enforcer.d.ts +0 -154
  105. package/dist/security/plugin-permission-enforcer.d.ts.map +0 -1
  106. package/dist/security/plugin-permission-enforcer.js +0 -323
  107. package/dist/security/plugin-permission-enforcer.test.d.ts +0 -2
  108. package/dist/security/plugin-permission-enforcer.test.d.ts.map +0 -1
  109. package/dist/security/plugin-permission-enforcer.test.js +0 -205
  110. package/dist/security/plugin-signature-verifier.d.ts +0 -96
  111. package/dist/security/plugin-signature-verifier.d.ts.map +0 -1
  112. package/dist/security/plugin-signature-verifier.js +0 -250
  113. package/dist/security/sandbox-runtime.d.ts +0 -115
  114. package/dist/security/sandbox-runtime.d.ts.map +0 -1
  115. package/dist/security/sandbox-runtime.js +0 -311
  116. package/dist/security/security-scanner.d.ts +0 -92
  117. package/dist/security/security-scanner.d.ts.map +0 -1
  118. package/dist/security/security-scanner.js +0 -273
  119. package/dist/types.d.ts +0 -89
  120. package/dist/types.d.ts.map +0 -1
  121. package/dist/types.js +0 -1
  122. package/dist/utils/env.d.ts +0 -20
  123. package/dist/utils/env.d.ts.map +0 -1
  124. package/dist/utils/env.js +0 -46
  125. package/dist/utils/env.test.d.ts +0 -2
  126. package/dist/utils/env.test.d.ts.map +0 -1
  127. package/dist/utils/env.test.js +0 -52
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/core",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Microkernel Core for ObjectStack",
6
6
  "type": "module",
@@ -12,10 +12,10 @@
12
12
  "@types/node": "^25.1.0"
13
13
  },
14
14
  "dependencies": {
15
- "pino": "^8.17.0",
16
- "pino-pretty": "^10.3.0",
15
+ "pino": "^10.3.0",
16
+ "pino-pretty": "^13.1.3",
17
17
  "zod": "^4.3.6",
18
- "@objectstack/spec": "1.0.4"
18
+ "@objectstack/spec": "1.0.6"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "pino": "^8.0.0"
@@ -26,7 +26,7 @@
26
26
  }
27
27
  },
28
28
  "scripts": {
29
- "build": "tsc",
29
+ "build": "tsup --config ../../tsup.config.ts",
30
30
  "test": "vitest run",
31
31
  "test:watch": "vitest"
32
32
  }
package/src/logger.ts CHANGED
@@ -51,13 +51,13 @@ export class ObjectLogger implements Logger {
51
51
  /**
52
52
  * Initialize Pino logger for Node.js
53
53
  */
54
- private initPinoLogger() {
54
+ private async initPinoLogger() {
55
55
  if (!this.isNode) return;
56
56
 
57
57
  try {
58
58
  // Create require function dynamically for Node.js (avoids bundling issues in browser)
59
59
  // @ts-ignore - dynamic import of Node.js module
60
- const { createRequire } = eval('require("module")');
60
+ const { createRequire } = await import('module');
61
61
  this.require = createRequire(import.meta.url);
62
62
 
63
63
  // Synchronous import for Pino using createRequire (works in ESM)
@@ -3,15 +3,7 @@ import type { PluginMetadata } from '../plugin-loader.js';
3
3
 
4
4
  // Conditionally import crypto for Node.js environments
5
5
  let cryptoModule: typeof import('crypto') | null = null;
6
- if (typeof (globalThis as any).window === 'undefined') {
7
- try {
8
- // Dynamic import for Node.js crypto module (using eval to avoid bundling issues)
9
- // @ts-ignore - dynamic require for Node.js
10
- cryptoModule = eval('require("crypto")');
11
- } catch {
12
- // Crypto module not available (e.g., browser environment)
13
- }
14
- }
6
+
15
7
 
16
8
  /**
17
9
  * Plugin Signature Configuration
@@ -295,11 +287,20 @@ export class PluginSignatureVerifier {
295
287
  return this.verifyCryptoSignatureNode(data, signature, publicKey);
296
288
  }
297
289
 
298
- private verifyCryptoSignatureNode(
290
+ private async verifyCryptoSignatureNode(
299
291
  data: string,
300
292
  signature: string,
301
293
  publicKey: string
302
- ): boolean {
294
+ ): Promise<boolean> {
295
+ if (!cryptoModule) {
296
+ try {
297
+ // @ts-ignore
298
+ cryptoModule = await import('crypto');
299
+ } catch (e) {
300
+ // ignore
301
+ }
302
+ }
303
+
303
304
  if (!cryptoModule) {
304
305
  this.logger.error('Crypto module not available for signature verification');
305
306
  return false;
package/tsconfig.json CHANGED
@@ -2,9 +2,7 @@
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist",
5
- "rootDir": "./src",
6
- "moduleResolution": "bundler",
7
- "module": "esnext"
5
+ "rootDir": "./src"
8
6
  },
9
7
  "include": ["src/**/*"],
10
8
  "exclude": []
@@ -1,54 +0,0 @@
1
- import type { Plugin } from './types.js';
2
- import type { ConflictResolutionStrategy } from '@objectstack/spec/api';
3
- /**
4
- * API Registry Plugin Configuration
5
- */
6
- export interface ApiRegistryPluginConfig {
7
- /**
8
- * Conflict resolution strategy for route conflicts
9
- * @default 'error'
10
- */
11
- conflictResolution?: ConflictResolutionStrategy;
12
- /**
13
- * Registry version
14
- * @default '1.0.0'
15
- */
16
- version?: string;
17
- }
18
- /**
19
- * API Registry Plugin
20
- *
21
- * Registers the API Registry service in the kernel, making it available
22
- * to all plugins for endpoint registration and discovery.
23
- *
24
- * **Usage:**
25
- * ```typescript
26
- * const kernel = new ObjectKernel();
27
- *
28
- * // Register API Registry Plugin
29
- * kernel.use(createApiRegistryPlugin({ conflictResolution: 'priority' }));
30
- *
31
- * // In other plugins, access the API Registry
32
- * const plugin: Plugin = {
33
- * name: 'my-plugin',
34
- * init: async (ctx) => {
35
- * const registry = ctx.getService<ApiRegistry>('api-registry');
36
- *
37
- * // Register plugin APIs
38
- * registry.registerApi({
39
- * id: 'my_plugin_api',
40
- * name: 'My Plugin API',
41
- * type: 'rest',
42
- * version: 'v1',
43
- * basePath: '/api/v1/my-plugin',
44
- * endpoints: [...]
45
- * });
46
- * }
47
- * };
48
- * ```
49
- *
50
- * @param config - Plugin configuration
51
- * @returns Plugin instance
52
- */
53
- export declare function createApiRegistryPlugin(config?: ApiRegistryPluginConfig): Plugin;
54
- //# sourceMappingURL=api-registry-plugin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-registry-plugin.d.ts","sourceRoot":"","sources":["../src/api-registry-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAEhD;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,GAAE,uBAA4B,GACnC,MAAM,CA2BR"}
@@ -1,53 +0,0 @@
1
- import { ApiRegistry } from './api-registry.js';
2
- /**
3
- * API Registry Plugin
4
- *
5
- * Registers the API Registry service in the kernel, making it available
6
- * to all plugins for endpoint registration and discovery.
7
- *
8
- * **Usage:**
9
- * ```typescript
10
- * const kernel = new ObjectKernel();
11
- *
12
- * // Register API Registry Plugin
13
- * kernel.use(createApiRegistryPlugin({ conflictResolution: 'priority' }));
14
- *
15
- * // In other plugins, access the API Registry
16
- * const plugin: Plugin = {
17
- * name: 'my-plugin',
18
- * init: async (ctx) => {
19
- * const registry = ctx.getService<ApiRegistry>('api-registry');
20
- *
21
- * // Register plugin APIs
22
- * registry.registerApi({
23
- * id: 'my_plugin_api',
24
- * name: 'My Plugin API',
25
- * type: 'rest',
26
- * version: 'v1',
27
- * basePath: '/api/v1/my-plugin',
28
- * endpoints: [...]
29
- * });
30
- * }
31
- * };
32
- * ```
33
- *
34
- * @param config - Plugin configuration
35
- * @returns Plugin instance
36
- */
37
- export function createApiRegistryPlugin(config = {}) {
38
- const { conflictResolution = 'error', version = '1.0.0', } = config;
39
- return {
40
- name: 'com.objectstack.core.api-registry',
41
- version: '1.0.0',
42
- init: async (ctx) => {
43
- // Create API Registry instance
44
- const registry = new ApiRegistry(ctx.logger, conflictResolution, version);
45
- // Register as a service
46
- ctx.registerService('api-registry', registry);
47
- ctx.logger.info('API Registry plugin initialized', {
48
- conflictResolution,
49
- version,
50
- });
51
- },
52
- };
53
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=api-registry-plugin.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-registry-plugin.test.d.ts","sourceRoot":"","sources":["../src/api-registry-plugin.test.ts"],"names":[],"mappings":""}
@@ -1,334 +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
- describe('API Registry Plugin', () => {
6
- let kernel;
7
- beforeEach(() => {
8
- kernel = new ObjectKernel({
9
- skipSystemValidation: true
10
- });
11
- });
12
- describe('Plugin Registration', () => {
13
- it('should register API Registry as a service', async () => {
14
- await kernel.use(createApiRegistryPlugin());
15
- await kernel.bootstrap();
16
- const registry = kernel.getService('api-registry');
17
- expect(registry).toBeDefined();
18
- expect(registry).toBeInstanceOf(ApiRegistry);
19
- await kernel.shutdown();
20
- });
21
- it('should register with custom conflict resolution', async () => {
22
- await kernel.use(createApiRegistryPlugin({
23
- conflictResolution: 'priority',
24
- version: '2.0.0',
25
- }));
26
- await kernel.bootstrap();
27
- const registry = kernel.getService('api-registry');
28
- const snapshot = registry.getRegistry();
29
- expect(snapshot.conflictResolution).toBe('priority');
30
- expect(snapshot.version).toBe('2.0.0');
31
- await kernel.shutdown();
32
- });
33
- });
34
- describe('Integration with Plugins', () => {
35
- it('should allow plugins to register APIs', async () => {
36
- await kernel.use(createApiRegistryPlugin());
37
- const testPlugin = {
38
- name: 'test-plugin',
39
- init: async (ctx) => {
40
- const registry = ctx.getService('api-registry');
41
- const api = {
42
- id: 'test_api',
43
- name: 'Test API',
44
- type: 'rest',
45
- version: 'v1',
46
- basePath: '/api/test',
47
- endpoints: [
48
- {
49
- id: 'get_test',
50
- method: 'GET',
51
- path: '/api/test/hello',
52
- summary: 'Test endpoint',
53
- responses: [
54
- {
55
- statusCode: 200,
56
- description: 'Success',
57
- },
58
- ],
59
- },
60
- ],
61
- };
62
- registry.registerApi(api);
63
- },
64
- };
65
- await kernel.use(testPlugin);
66
- await kernel.bootstrap();
67
- const registry = kernel.getService('api-registry');
68
- const api = registry.getApi('test_api');
69
- expect(api).toBeDefined();
70
- expect(api?.name).toBe('Test API');
71
- expect(api?.endpoints.length).toBe(1);
72
- await kernel.shutdown();
73
- });
74
- it('should allow multiple plugins to register APIs', async () => {
75
- await kernel.use(createApiRegistryPlugin());
76
- const plugin1 = {
77
- name: 'plugin-1',
78
- init: async (ctx) => {
79
- const registry = ctx.getService('api-registry');
80
- registry.registerApi({
81
- id: 'api1',
82
- name: 'API 1',
83
- type: 'rest',
84
- version: 'v1',
85
- basePath: '/api/plugin1',
86
- endpoints: [
87
- {
88
- id: 'endpoint1',
89
- method: 'GET',
90
- path: '/api/plugin1/data',
91
- responses: [],
92
- },
93
- ],
94
- });
95
- },
96
- };
97
- const plugin2 = {
98
- name: 'plugin-2',
99
- init: async (ctx) => {
100
- const registry = ctx.getService('api-registry');
101
- registry.registerApi({
102
- id: 'api2',
103
- name: 'API 2',
104
- type: 'graphql',
105
- version: 'v1',
106
- basePath: '/graphql',
107
- endpoints: [
108
- {
109
- id: 'query',
110
- path: '/graphql',
111
- responses: [],
112
- },
113
- ],
114
- });
115
- },
116
- };
117
- await kernel.use(plugin1);
118
- await kernel.use(plugin2);
119
- await kernel.bootstrap();
120
- const registry = kernel.getService('api-registry');
121
- const stats = registry.getStats();
122
- expect(stats.totalApis).toBe(2);
123
- expect(stats.apisByType.rest).toBe(1);
124
- expect(stats.apisByType.graphql).toBe(1);
125
- await kernel.shutdown();
126
- });
127
- it('should support API discovery across plugins', async () => {
128
- await kernel.use(createApiRegistryPlugin());
129
- const dataPlugin = {
130
- name: 'data-plugin',
131
- init: async (ctx) => {
132
- const registry = ctx.getService('api-registry');
133
- registry.registerApi({
134
- id: 'customer_api',
135
- name: 'Customer API',
136
- type: 'rest',
137
- version: 'v1',
138
- basePath: '/api/v1/customers',
139
- endpoints: [],
140
- metadata: {
141
- status: 'active',
142
- tags: ['crm', 'data'],
143
- },
144
- });
145
- registry.registerApi({
146
- id: 'product_api',
147
- name: 'Product API',
148
- type: 'rest',
149
- version: 'v1',
150
- basePath: '/api/v1/products',
151
- endpoints: [],
152
- metadata: {
153
- status: 'active',
154
- tags: ['inventory', 'data'],
155
- },
156
- });
157
- },
158
- };
159
- const analyticsPlugin = {
160
- name: 'analytics-plugin',
161
- init: async (ctx) => {
162
- const registry = ctx.getService('api-registry');
163
- registry.registerApi({
164
- id: 'analytics_api',
165
- name: 'Analytics API',
166
- type: 'rest',
167
- version: 'v1',
168
- basePath: '/api/v1/analytics',
169
- endpoints: [],
170
- metadata: {
171
- status: 'beta',
172
- tags: ['analytics', 'reporting'],
173
- },
174
- });
175
- },
176
- };
177
- await kernel.use(dataPlugin);
178
- await kernel.use(analyticsPlugin);
179
- await kernel.bootstrap();
180
- const registry = kernel.getService('api-registry');
181
- // Find all data APIs
182
- const dataApis = registry.findApis({ tags: ['data'] });
183
- expect(dataApis.total).toBe(2);
184
- // Find active APIs
185
- const activeApis = registry.findApis({ status: 'active' });
186
- expect(activeApis.total).toBe(2);
187
- // Find CRM APIs
188
- const crmApis = registry.findApis({ tags: ['crm'] });
189
- expect(crmApis.total).toBe(1);
190
- expect(crmApis.apis[0].id).toBe('customer_api');
191
- await kernel.shutdown();
192
- });
193
- it('should handle route conflicts based on strategy', async () => {
194
- await kernel.use(createApiRegistryPlugin({
195
- conflictResolution: 'priority',
196
- }));
197
- const corePlugin = {
198
- name: 'core-plugin',
199
- init: async (ctx) => {
200
- const registry = ctx.getService('api-registry');
201
- registry.registerApi({
202
- id: 'core_api',
203
- name: 'Core API',
204
- type: 'rest',
205
- version: 'v1',
206
- basePath: '/api',
207
- endpoints: [
208
- {
209
- id: 'core_endpoint',
210
- method: 'GET',
211
- path: '/api/data/:object',
212
- priority: 900, // High priority
213
- summary: 'Core data endpoint',
214
- responses: [],
215
- },
216
- ],
217
- });
218
- },
219
- };
220
- const pluginOverride = {
221
- name: 'plugin-override',
222
- init: async (ctx) => {
223
- const registry = ctx.getService('api-registry');
224
- registry.registerApi({
225
- id: 'plugin_api',
226
- name: 'Plugin API',
227
- type: 'rest',
228
- version: 'v1',
229
- basePath: '/api',
230
- endpoints: [
231
- {
232
- id: 'plugin_endpoint',
233
- method: 'GET',
234
- path: '/api/data/:object',
235
- priority: 300, // Lower priority
236
- summary: 'Plugin data endpoint',
237
- responses: [],
238
- },
239
- ],
240
- });
241
- },
242
- };
243
- await kernel.use(corePlugin);
244
- await kernel.use(pluginOverride);
245
- await kernel.bootstrap();
246
- const registry = kernel.getService('api-registry');
247
- const result = registry.findEndpointByRoute('GET', '/api/data/:object');
248
- // Core API should win due to higher priority
249
- expect(result?.api.id).toBe('core_api');
250
- expect(result?.endpoint.id).toBe('core_endpoint');
251
- await kernel.shutdown();
252
- });
253
- it('should support cleanup on plugin unload', async () => {
254
- await kernel.use(createApiRegistryPlugin());
255
- const dynamicPlugin = {
256
- name: 'dynamic-plugin',
257
- init: async (ctx) => {
258
- const registry = ctx.getService('api-registry');
259
- registry.registerApi({
260
- id: 'dynamic_api',
261
- name: 'Dynamic API',
262
- type: 'rest',
263
- version: 'v1',
264
- basePath: '/api/dynamic',
265
- endpoints: [
266
- {
267
- id: 'test',
268
- method: 'GET',
269
- path: '/api/dynamic/test',
270
- responses: [],
271
- },
272
- ],
273
- });
274
- },
275
- destroy: async () => {
276
- // In a real scenario, this would use ctx to access registry
277
- // For now, we'll test the registry's unregister capability
278
- },
279
- };
280
- await kernel.use(dynamicPlugin);
281
- await kernel.bootstrap();
282
- const registry = kernel.getService('api-registry');
283
- expect(registry.getApi('dynamic_api')).toBeDefined();
284
- // Unregister the API
285
- registry.unregisterApi('dynamic_api');
286
- expect(registry.getApi('dynamic_api')).toBeUndefined();
287
- await kernel.shutdown();
288
- });
289
- });
290
- describe('API Registry Lifecycle', () => {
291
- it('should be available during plugin start phase', async () => {
292
- await kernel.use(createApiRegistryPlugin());
293
- let registryAvailable = false;
294
- const testPlugin = {
295
- name: 'test-plugin',
296
- init: async () => {
297
- // Init phase
298
- },
299
- start: async (ctx) => {
300
- // Start phase - registry should be available
301
- const registry = ctx.getService('api-registry');
302
- registryAvailable = registry !== undefined;
303
- },
304
- };
305
- await kernel.use(testPlugin);
306
- await kernel.bootstrap();
307
- expect(registryAvailable).toBe(true);
308
- await kernel.shutdown();
309
- });
310
- it('should provide consistent registry across all plugins', async () => {
311
- await kernel.use(createApiRegistryPlugin());
312
- let registry1;
313
- let registry2;
314
- const plugin1 = {
315
- name: 'plugin-1',
316
- init: async (ctx) => {
317
- registry1 = ctx.getService('api-registry');
318
- },
319
- };
320
- const plugin2 = {
321
- name: 'plugin-2',
322
- init: async (ctx) => {
323
- registry2 = ctx.getService('api-registry');
324
- },
325
- };
326
- await kernel.use(plugin1);
327
- await kernel.use(plugin2);
328
- await kernel.bootstrap();
329
- // Same registry instance should be shared
330
- expect(registry1).toBe(registry2);
331
- await kernel.shutdown();
332
- });
333
- });
334
- });