@objectstack/runtime 0.4.2 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @objectstack/runtime
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b2df5f7: Unified version bump to 0.5.0
8
+
9
+ - Standardized all package versions to 0.5.0 across the monorepo
10
+ - Fixed driver-memory package.json paths for proper module resolution
11
+ - Ensured all packages are in sync for the 0.5.0 release
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [b2df5f7]
16
+ - @objectstack/spec@0.6.0
17
+ - @objectstack/objectql@0.6.0
18
+ - @objectstack/types@0.6.0
19
+ - @objectstack/core@0.6.0
20
+
3
21
  ## 0.4.2
4
22
 
5
23
  ### Patch Changes
package/README.md CHANGED
@@ -1,10 +1,16 @@
1
1
  # @objectstack/runtime
2
2
 
3
- ObjectStack Core Runtime & Query Engine
3
+ ObjectStack Standard System Library
4
4
 
5
5
  ## Overview
6
6
 
7
- The runtime package provides the `ObjectStackKernel` - the central orchestrator for ObjectStack applications. It manages the application lifecycle, plugins, and the ObjectQL data engine.
7
+ The runtime package provides the **Standard Library** for the ObjectStack Operating System. It bridges the pure **ObjectKernel** (from `@objectstack/core`) with the **Data Engine** (`@objectstack/objectql`) and provides essential infrastructure adapters.
8
+
9
+ ### Architecture Highlights
10
+
11
+ - **Standard Library**: Contains essential plugins (`AppManifestPlugin`, `DriverPlugin`)
12
+ - **Core Integration**: Re-exports `ObjectKernel` for convenience
13
+ - **Capability Contracts**: Abstract interfaces for HTTP server and data persistence
8
14
 
9
15
  ## Installation
10
16
 
@@ -12,26 +18,28 @@ The runtime package provides the `ObjectStackKernel` - the central orchestrator
12
18
  npm install @objectstack/runtime
13
19
  ```
14
20
 
15
- ## Usage
21
+ ## Quick Start
16
22
 
17
- ### Basic Setup
23
+ ### Basic Setup (Recommended)
18
24
 
19
25
  ```typescript
20
- import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime';
26
+ import { ObjectKernel } from '@objectstack/core';
27
+ import { ObjectQLPlugin, DriverPlugin, AppManifestPlugin } from '@objectstack/runtime';
21
28
  import { InMemoryDriver } from '@objectstack/driver-memory';
22
29
 
23
- const kernel = new ObjectStackKernel([
30
+ const kernel = new ObjectKernel();
31
+
32
+ kernel
24
33
  // Register ObjectQL engine
25
- new ObjectQLPlugin(),
34
+ .use(new ObjectQLPlugin())
26
35
 
27
36
  // Add database driver
28
- new InMemoryDriver(),
37
+ .use(new DriverPlugin(new InMemoryDriver(), 'memory'))
29
38
 
30
39
  // Add your app configurations
31
- // appConfig,
32
- ]);
40
+ // .use(new AppManifestPlugin(appConfig));
33
41
 
34
- await kernel.start();
42
+ await kernel.bootstrap();
35
43
  ```
36
44
 
37
45
  ### Custom ObjectQL Instance
@@ -39,7 +47,7 @@ await kernel.start();
39
47
  If you have a separate ObjectQL implementation or need custom configuration:
40
48
 
41
49
  ```typescript
42
- import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime';
50
+ import { ObjectKernel, ObjectQLPlugin, DriverPlugin, ObjectQL } from '@objectstack/runtime';
43
51
 
44
52
  // Create custom ObjectQL instance
45
53
  const customQL = new ObjectQL({
@@ -52,111 +60,218 @@ customQL.registerHook('beforeInsert', async (ctx) => {
52
60
  console.log(`Inserting into ${ctx.object}`);
53
61
  });
54
62
 
55
- const kernel = new ObjectStackKernel([
63
+ const kernel = new ObjectKernel();
64
+
65
+ kernel
56
66
  // Use your custom ObjectQL instance
57
- new ObjectQLPlugin(customQL),
67
+ .use(new ObjectQLPlugin(customQL))
58
68
 
59
- // ... other plugins
60
- ]);
69
+ // Add driver
70
+ .use(new DriverPlugin(new InMemoryDriver(), 'memory'));
71
+
72
+ await kernel.bootstrap();
61
73
 
62
- await kernel.start();
74
+ // Access ObjectQL via service registry
75
+ const objectql = kernel.getService('objectql');
63
76
  ```
64
77
 
65
- ### Backward Compatibility
78
+ ## Architecture
79
+
80
+ ### ObjectKernel (MiniKernel)
81
+
82
+ The kernel provides:
83
+ - **Plugin Lifecycle Management**: init → start → destroy phases
84
+ - **Service Registry**: Dependency injection container
85
+ - **Event/Hook System**: Inter-plugin communication
86
+ - **Dependency Resolution**: Topological sort for plugin dependencies
87
+
88
+ ### Built-in Plugins
66
89
 
67
- For backward compatibility, the kernel will automatically initialize ObjectQL if no `ObjectQLPlugin` is provided:
90
+ #### ObjectQLPlugin
91
+ Registers the ObjectQL data engine as a service.
68
92
 
69
93
  ```typescript
70
- // This still works, but will show a deprecation warning
71
- const kernel = new ObjectStackKernel([
72
- new InMemoryDriver(),
73
- // ... other plugins
74
- ]);
94
+ new ObjectQLPlugin() // Default instance
95
+ new ObjectQLPlugin(customQL) // Custom instance
96
+ new ObjectQLPlugin(undefined, { env: 'prod' }) // With context
75
97
  ```
76
98
 
77
- ## Architecture
99
+ **Services**: `'objectql'`
78
100
 
79
- ### ObjectStackKernel
101
+ #### DriverPlugin
102
+ Registers a data driver with ObjectQL.
80
103
 
81
- The kernel is responsible for:
82
- - Orchestrating application lifecycle
83
- - Managing plugins
84
- - Coordinating the ObjectQL engine
85
- - Handling data operations
104
+ ```typescript
105
+ new DriverPlugin(driver, 'driver-name')
106
+ ```
86
107
 
87
- ### ObjectQLPlugin
108
+ **Dependencies**: `['com.objectstack.engine.objectql']`
88
109
 
89
- The `ObjectQLPlugin` provides:
90
- - Explicit ObjectQL engine registration
91
- - Support for custom ObjectQL instances
92
- - Clean separation of concerns
93
- - Better testability
110
+ #### AppManifestPlugin
111
+ Wraps ObjectStack app manifests (objectstack.config.ts) as plugins.
112
+
113
+ ```typescript
114
+ new AppManifestPlugin(appConfig)
115
+ ```
116
+
117
+ **Dependencies**: `['com.objectstack.engine.objectql']`
94
118
 
95
119
  ## API Reference
96
120
 
97
- ### ObjectStackKernel
121
+ ### Capability Contract Interfaces
122
+
123
+ #### IHttpServer
124
+
125
+ Abstract interface for HTTP server capabilities. Allows plugins to work with any HTTP framework (Express, Fastify, Hono, etc.) without tight coupling.
98
126
 
99
- #### Constructor
100
127
  ```typescript
101
- constructor(plugins: any[] = [])
128
+ import { IHttpServer, IHttpRequest, IHttpResponse } from '@objectstack/runtime';
129
+
130
+ // In your HTTP server plugin
131
+ class MyHttpServerPlugin implements Plugin {
132
+ name = 'http-server';
133
+
134
+ async init(ctx: PluginContext) {
135
+ const server: IHttpServer = createMyServer(); // Express, Hono, etc.
136
+ ctx.registerService('http-server', server);
137
+ }
138
+ }
139
+
140
+ // In your API plugin
141
+ class MyApiPlugin implements Plugin {
142
+ name = 'api';
143
+ dependencies = ['http-server'];
144
+
145
+ async start(ctx: PluginContext) {
146
+ const server = ctx.getService<IHttpServer>('http-server');
147
+
148
+ // Register routes - works with any HTTP framework
149
+ server.get('/api/users', async (req, res) => {
150
+ res.json({ users: [] });
151
+ });
152
+ }
153
+ }
102
154
  ```
103
155
 
156
+ **Interface Methods:**
157
+ - `get(path, handler)` - Register GET route
158
+ - `post(path, handler)` - Register POST route
159
+ - `put(path, handler)` - Register PUT route
160
+ - `delete(path, handler)` - Register DELETE route
161
+ - `patch(path, handler)` - Register PATCH route
162
+ - `use(path, handler?)` - Register middleware
163
+ - `listen(port)` - Start server
164
+ - `close()` - Stop server (optional)
165
+
166
+ #### IDataEngine
167
+
168
+ Abstract interface for data persistence. Allows plugins to work with any data layer (ObjectQL, Prisma, TypeORM, etc.) without tight coupling.
169
+
170
+ ```typescript
171
+ import { IDataEngine } from '@objectstack/runtime';
172
+
173
+ // In your data plugin
174
+ class MyDataPlugin implements Plugin {
175
+ name = 'data';
176
+
177
+ async init(ctx: PluginContext) {
178
+ const engine: IDataEngine = createMyDataEngine(); // ObjectQL, Prisma, etc.
179
+ ctx.registerService('data-engine', engine);
180
+ }
181
+ }
182
+
183
+ // In your business logic plugin
184
+ class MyBusinessPlugin implements Plugin {
185
+ name = 'business';
186
+ dependencies = ['data'];
187
+
188
+ async start(ctx: PluginContext) {
189
+ const engine = ctx.getService<IDataEngine>('data-engine');
190
+
191
+ // CRUD operations - works with any data layer
192
+ const user = await engine.insert('user', { name: 'John' });
193
+ const users = await engine.find('user', { filter: { active: true } });
194
+ await engine.update('user', user.id, { name: 'Jane' });
195
+ await engine.delete('user', user.id);
196
+ }
197
+ }
198
+ ```
199
+
200
+ **Interface Methods:**
201
+ - `insert(objectName, data)` - Create a record
202
+ - `find(objectName, query?)` - Query records
203
+ - `update(objectName, id, data)` - Update a record
204
+ - `delete(objectName, id)` - Delete a record
205
+
206
+ ### ObjectKernel
207
+
104
208
  #### Methods
105
- - `start()`: Initialize and start the kernel
106
- - `find(objectName, query)`: Query data
107
- - `get(objectName, id)`: Get single record
108
- - `create(objectName, data)`: Create record
109
- - `update(objectName, id, data)`: Update record
110
- - `delete(objectName, id)`: Delete record
111
- - `getMetadata(objectName)`: Get object metadata
112
- - `getView(objectName, viewType)`: Get UI view definition
113
-
114
- ### ObjectQLPlugin
115
-
116
- #### Constructor
209
+ - `use(plugin: Plugin)`: Register a plugin
210
+ - `bootstrap()`: Initialize and start all plugins
211
+ - `shutdown()`: Stop all plugins in reverse order
212
+ - `getService<T>(name: string)`: Get a service from registry
213
+ - `isRunning()`: Check if kernel is running
214
+ - `getState()`: Get current kernel state
215
+
216
+ ### Plugin Interface
217
+
117
218
  ```typescript
118
- constructor(ql?: ObjectQL, hostContext?: Record<string, any>)
219
+ interface Plugin {
220
+ name: string; // Unique identifier
221
+ version?: string; // Plugin version
222
+ dependencies?: string[]; // Required plugin names
223
+
224
+ init(ctx: PluginContext): Promise<void>; // Register services
225
+ start?(ctx: PluginContext): Promise<void>; // Execute business logic
226
+ destroy?(): Promise<void>; // Cleanup
227
+ }
119
228
  ```
120
229
 
121
- #### Parameters
122
- - `ql` (optional): Custom ObjectQL instance
123
- - `hostContext` (optional): Host context configuration
230
+ ### PluginContext
231
+
232
+ ```typescript
233
+ interface PluginContext {
234
+ registerService(name: string, service: any): void;
235
+ getService<T>(name: string): T;
236
+ hook(name: string, handler: Function): void;
237
+ trigger(name: string, ...args: any[]): Promise<void>;
238
+ logger: Console;
239
+ getKernel?(): any;
240
+ }
241
+ ```
124
242
 
125
243
  ## Examples
126
244
 
127
245
  See the `examples/` directory for complete examples:
128
246
  - `examples/host/` - Full server setup with Hono
129
247
  - `examples/msw-react-crud/` - Browser-based setup with MSW
130
- - `examples/custom-objectql-example.ts` - Custom ObjectQL instance
248
+ - `test-mini-kernel.ts` - Comprehensive kernel test suite
249
+ - `packages/runtime/src/test-interfaces.ts` - Capability contract interface examples
131
250
 
132
- ## Migration Guide
251
+ ## Benefits of MiniKernel
133
252
 
134
- ### From Hardcoded ObjectQL to Plugin-Based
253
+ 1. **True Modularity**: Each plugin is independent and reusable
254
+ 2. **Capability Contracts**: Plugins depend on interfaces, not implementations
255
+ 3. **Testability**: Mock services easily in tests
256
+ 4. **Flexibility**: Load plugins conditionally, swap implementations
257
+ 5. **Extensibility**: Add new plugins without modifying kernel
258
+ 6. **Clear Dependencies**: Explicit dependency declarations
259
+ 7. **Better Architecture**: Separation of concerns with Dependency Inversion
135
260
 
136
- **Before:**
137
- ```typescript
138
- const kernel = new ObjectStackKernel([appConfig, driver]);
139
- ```
261
+ ## Best Practices
140
262
 
141
- **After (Recommended):**
142
- ```typescript
143
- const kernel = new ObjectStackKernel([
144
- new ObjectQLPlugin(),
145
- appConfig,
146
- driver
147
- ]);
148
- ```
263
+ 1. **Keep plugins focused**: One responsibility per plugin
264
+ 2. **Use services**: Share functionality via service registry
265
+ 3. **Declare dependencies**: Make plugin requirements explicit
266
+ 4. **Use hooks**: Decouple plugins with event system
267
+ 5. **Handle errors**: Implement proper error handling in lifecycle methods
149
268
 
150
- **After (Custom Instance):**
151
- ```typescript
152
- const customQL = new ObjectQL({ /* config */ });
153
- const kernel = new ObjectStackKernel([
154
- new ObjectQLPlugin(customQL),
155
- appConfig,
156
- driver
157
- ]);
158
- ```
269
+ ## Documentation
270
+
271
+ - [MiniKernel Guide](../../MINI_KERNEL_GUIDE.md) - Complete API documentation and patterns
272
+ - [MiniKernel Architecture](../../MINI_KERNEL_ARCHITECTURE.md) - Architecture diagrams and flows
273
+ - [MiniKernel Implementation](../../MINI_KERNEL_IMPLEMENTATION.md) - Implementation details
159
274
 
160
275
  ## License
161
276
 
162
- MIT
277
+ Apache-2.0
@@ -0,0 +1,19 @@
1
+ import { Plugin, PluginContext } from '@objectstack/core';
2
+ /**
3
+ * AppManifestPlugin
4
+ *
5
+ * Adapts a static Manifest JSON into a dynamic Kernel Service.
6
+ * This allows the ObjectQL Engine to "discover" this app during its start phase.
7
+ *
8
+ * Flow:
9
+ * 1. AppPlugin registers `app.<id>` service (init phase)
10
+ * 2. ObjectQL Engine discovers `app.*` services (start phase)
11
+ */
12
+ export declare class AppManifestPlugin implements Plugin {
13
+ name: string;
14
+ version?: string;
15
+ private manifest;
16
+ constructor(manifest: any);
17
+ init(ctx: PluginContext): Promise<void>;
18
+ start(ctx: PluginContext): Promise<void>;
19
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * AppManifestPlugin
3
+ *
4
+ * Adapts a static Manifest JSON into a dynamic Kernel Service.
5
+ * This allows the ObjectQL Engine to "discover" this app during its start phase.
6
+ *
7
+ * Flow:
8
+ * 1. AppPlugin registers `app.<id>` service (init phase)
9
+ * 2. ObjectQL Engine discovers `app.*` services (start phase)
10
+ */
11
+ export class AppManifestPlugin {
12
+ constructor(manifest) {
13
+ this.manifest = manifest;
14
+ // Support both direct manifest (legacy) and Stack Definition (nested manifest)
15
+ const sys = manifest.manifest || manifest;
16
+ const appId = sys.id || sys.name || 'unnamed-app';
17
+ this.name = `plugin.app.${appId}`; // Unique plugin name
18
+ this.version = sys.version;
19
+ }
20
+ async init(ctx) {
21
+ // Support both direct manifest (legacy) and Stack Definition (nested manifest)
22
+ const sys = this.manifest.manifest || this.manifest;
23
+ const appId = sys.id || sys.name;
24
+ ctx.logger.log(`[AppManifestPlugin] Registering App Service: ${appId}`);
25
+ // Register the app manifest as a service
26
+ const serviceName = `app.${appId}`;
27
+ ctx.registerService(serviceName, this.manifest);
28
+ }
29
+ async start(ctx) {
30
+ // No logic needed here.
31
+ // Logic is inverted: The Engine will pull data from this service.
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ import { Plugin, PluginContext } from '@objectstack/core';
2
+ /**
3
+ * Driver Plugin
4
+ *
5
+ * Generic plugin wrapper for ObjectQL drivers.
6
+ * Registers a driver with the ObjectQL engine.
7
+ *
8
+ * Dependencies: None (Registers service for ObjectQL to discover)
9
+ * Services: driver.{name}
10
+ *
11
+ * @example
12
+ * const memoryDriver = new InMemoryDriver();
13
+ * const driverPlugin = new DriverPlugin(memoryDriver, 'memory');
14
+ * kernel.use(driverPlugin);
15
+ */
16
+ export declare class DriverPlugin implements Plugin {
17
+ name: string;
18
+ version: string;
19
+ private driver;
20
+ constructor(driver: any, driverName?: string);
21
+ init(ctx: PluginContext): Promise<void>;
22
+ start(ctx: PluginContext): Promise<void>;
23
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Driver Plugin
3
+ *
4
+ * Generic plugin wrapper for ObjectQL drivers.
5
+ * Registers a driver with the ObjectQL engine.
6
+ *
7
+ * Dependencies: None (Registers service for ObjectQL to discover)
8
+ * Services: driver.{name}
9
+ *
10
+ * @example
11
+ * const memoryDriver = new InMemoryDriver();
12
+ * const driverPlugin = new DriverPlugin(memoryDriver, 'memory');
13
+ * kernel.use(driverPlugin);
14
+ */
15
+ export class DriverPlugin {
16
+ constructor(driver, driverName) {
17
+ this.version = '1.0.0';
18
+ this.driver = driver;
19
+ this.name = `com.objectstack.driver.${driverName || driver.name || 'unknown'}`;
20
+ }
21
+ async init(ctx) {
22
+ // Register driver as a service instead of directly to objectql
23
+ const serviceName = `driver.${this.driver.name || 'unknown'}`;
24
+ ctx.registerService(serviceName, this.driver);
25
+ ctx.logger.log(`[DriverPlugin] Registered driver service: ${serviceName}`);
26
+ }
27
+ async start(ctx) {
28
+ // Drivers don't need start phase, initialization happens in init
29
+ ctx.logger.log(`[DriverPlugin] Driver ready: ${this.driver.name || 'unknown'}`);
30
+ }
31
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { ObjectQL, SchemaRegistry } from '@objectstack/objectql';
2
- export { ObjectStackKernel } from './kernel';
3
- export { ObjectQLPlugin } from './objectql-plugin';
4
- export { ObjectStackRuntimeProtocol } from './protocol';
5
- export * from './types';
1
+ export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
2
+ export { ObjectKernel } from '@objectstack/core';
3
+ export { ObjectQLPlugin } from '@objectstack/objectql';
4
+ export { DriverPlugin } from './driver-plugin';
5
+ export { AppManifestPlugin } from './app-manifest-plugin';
6
+ export * from '@objectstack/core';
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // Export core engine
2
- export { ObjectQL, SchemaRegistry } from '@objectstack/objectql';
3
- export { ObjectStackKernel } from './kernel';
4
- export { ObjectQLPlugin } from './objectql-plugin';
5
- export { ObjectStackRuntimeProtocol } from './protocol';
6
- export * from './types';
2
+ export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
3
+ // Export Kernels
4
+ export { ObjectKernel } from '@objectstack/core';
5
+ // Export Plugins
6
+ export { ObjectQLPlugin } from '@objectstack/objectql';
7
+ export { DriverPlugin } from './driver-plugin';
8
+ export { AppManifestPlugin } from './app-manifest-plugin';
9
+ // Export Types
10
+ export * from '@objectstack/core';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Test file to verify capability contract interfaces
3
+ *
4
+ * This file demonstrates how plugins can implement the IHttpServer
5
+ * and IDataEngine interfaces without depending on concrete implementations.
6
+ */
7
+ export {};
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Test file to verify capability contract interfaces
3
+ *
4
+ * This file demonstrates how plugins can implement the IHttpServer
5
+ * and IDataEngine interfaces without depending on concrete implementations.
6
+ */
7
+ /**
8
+ * Example: Mock HTTP Server Plugin
9
+ *
10
+ * Shows how a plugin can implement the IHttpServer interface
11
+ * without depending on Express, Fastify, or any specific framework.
12
+ */
13
+ class MockHttpServer {
14
+ constructor() {
15
+ this.routes = new Map();
16
+ }
17
+ get(path, handler) {
18
+ this.routes.set(`GET:${path}`, { method: 'GET', handler });
19
+ console.log(`✅ Registered GET ${path}`);
20
+ }
21
+ post(path, handler) {
22
+ this.routes.set(`POST:${path}`, { method: 'POST', handler });
23
+ console.log(`✅ Registered POST ${path}`);
24
+ }
25
+ put(path, handler) {
26
+ this.routes.set(`PUT:${path}`, { method: 'PUT', handler });
27
+ console.log(`✅ Registered PUT ${path}`);
28
+ }
29
+ delete(path, handler) {
30
+ this.routes.set(`DELETE:${path}`, { method: 'DELETE', handler });
31
+ console.log(`✅ Registered DELETE ${path}`);
32
+ }
33
+ patch(path, handler) {
34
+ this.routes.set(`PATCH:${path}`, { method: 'PATCH', handler });
35
+ console.log(`✅ Registered PATCH ${path}`);
36
+ }
37
+ use(path, handler) {
38
+ console.log(`✅ Registered middleware`);
39
+ }
40
+ async listen(port) {
41
+ console.log(`✅ Mock HTTP server listening on port ${port}`);
42
+ }
43
+ async close() {
44
+ console.log(`✅ Mock HTTP server closed`);
45
+ }
46
+ }
47
+ /**
48
+ * Example: Mock Data Engine Plugin
49
+ *
50
+ * Shows how a plugin can implement the IDataEngine interface
51
+ * without depending on ObjectQL, Prisma, or any specific database.
52
+ */
53
+ class MockDataEngine {
54
+ constructor() {
55
+ this.store = new Map();
56
+ this.idCounter = 0;
57
+ }
58
+ async insert(objectName, data) {
59
+ if (!this.store.has(objectName)) {
60
+ this.store.set(objectName, new Map());
61
+ }
62
+ const id = `${objectName}_${++this.idCounter}`;
63
+ const record = { id, ...data };
64
+ this.store.get(objectName).set(id, record);
65
+ console.log(`✅ Inserted into ${objectName}:`, record);
66
+ return record;
67
+ }
68
+ async find(objectName, query) {
69
+ const objectStore = this.store.get(objectName);
70
+ if (!objectStore) {
71
+ return [];
72
+ }
73
+ const results = Array.from(objectStore.values());
74
+ console.log(`✅ Found ${results.length} records in ${objectName}`);
75
+ return results;
76
+ }
77
+ async update(objectName, id, data) {
78
+ const objectStore = this.store.get(objectName);
79
+ if (!objectStore || !objectStore.has(id)) {
80
+ throw new Error(`Record ${id} not found in ${objectName}`);
81
+ }
82
+ const existing = objectStore.get(id);
83
+ const updated = { ...existing, ...data };
84
+ objectStore.set(id, updated);
85
+ console.log(`✅ Updated ${objectName}/${id}:`, updated);
86
+ return updated;
87
+ }
88
+ async delete(objectName, id) {
89
+ const objectStore = this.store.get(objectName);
90
+ if (!objectStore) {
91
+ return false;
92
+ }
93
+ const deleted = objectStore.delete(id);
94
+ console.log(`✅ Deleted ${objectName}/${id}: ${deleted}`);
95
+ return deleted;
96
+ }
97
+ }
98
+ /**
99
+ * Test the interfaces
100
+ */
101
+ async function testInterfaces() {
102
+ console.log('\n=== Testing IHttpServer Interface ===\n');
103
+ const httpServer = new MockHttpServer();
104
+ // Register routes using the interface
105
+ httpServer.get('/api/users', async (req, res) => {
106
+ res.json({ users: [] });
107
+ });
108
+ httpServer.post('/api/users', async (req, res) => {
109
+ res.status(201).json({ id: 1, ...req.body });
110
+ });
111
+ await httpServer.listen(3000);
112
+ console.log('\n=== Testing IDataEngine Interface ===\n');
113
+ const dataEngine = new MockDataEngine();
114
+ // Use the data engine interface
115
+ const user1 = await dataEngine.insert('user', {
116
+ name: 'John Doe',
117
+ email: 'john@example.com'
118
+ });
119
+ const user2 = await dataEngine.insert('user', {
120
+ name: 'Jane Smith',
121
+ email: 'jane@example.com'
122
+ });
123
+ const users = await dataEngine.find('user');
124
+ console.log(`Found ${users.length} users after inserts`);
125
+ const updatedUser = await dataEngine.update('user', user1.id, {
126
+ name: 'John Updated'
127
+ });
128
+ console.log(`Updated user:`, updatedUser);
129
+ const deleted = await dataEngine.delete('user', user2.id);
130
+ console.log(`Delete result: ${deleted}`);
131
+ console.log('\n✅ All interface tests passed!\n');
132
+ if (httpServer.close) {
133
+ await httpServer.close();
134
+ }
135
+ }
136
+ // Run tests
137
+ testInterfaces().catch(console.error);
138
+ export {};