@objectstack/runtime 0.6.0 → 0.6.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.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Patch release for maintenance and stability improvements
8
+ - Updated dependencies
9
+ - @objectstack/spec@0.6.1
10
+ - @objectstack/types@0.6.1
11
+ - @objectstack/core@0.6.1
12
+
3
13
  ## 0.6.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -8,7 +8,7 @@ The runtime package provides the **Standard Library** for the ObjectStack Operat
8
8
 
9
9
  ### Architecture Highlights
10
10
 
11
- - **Standard Library**: Contains essential plugins (`AppManifestPlugin`, `DriverPlugin`)
11
+ - **Standard Library**: Contains essential plugins (`AppPlugin`, `DriverPlugin`)
12
12
  - **Core Integration**: Re-exports `ObjectKernel` for convenience
13
13
  - **Capability Contracts**: Abstract interfaces for HTTP server and data persistence
14
14
 
@@ -24,7 +24,8 @@ npm install @objectstack/runtime
24
24
 
25
25
  ```typescript
26
26
  import { ObjectKernel } from '@objectstack/core';
27
- import { ObjectQLPlugin, DriverPlugin, AppManifestPlugin } from '@objectstack/runtime';
27
+ import { DriverPlugin, AppPlugin } from '@objectstack/runtime';
28
+ import { ObjectQLPlugin } from '@objectstack/objectql';
28
29
  import { InMemoryDriver } from '@objectstack/driver-memory';
29
30
 
30
31
  const kernel = new ObjectKernel();
@@ -37,7 +38,7 @@ kernel
37
38
  .use(new DriverPlugin(new InMemoryDriver(), 'memory'))
38
39
 
39
40
  // Add your app configurations
40
- // .use(new AppManifestPlugin(appConfig));
41
+ // .use(new AppPlugin(appConfig));
41
42
 
42
43
  await kernel.bootstrap();
43
44
  ```
@@ -47,7 +48,8 @@ await kernel.bootstrap();
47
48
  If you have a separate ObjectQL implementation or need custom configuration:
48
49
 
49
50
  ```typescript
50
- import { ObjectKernel, ObjectQLPlugin, DriverPlugin, ObjectQL } from '@objectstack/runtime';
51
+ import { ObjectKernel, DriverPlugin } from '@objectstack/runtime';
52
+ import { ObjectQLPlugin, ObjectQL } from '@objectstack/objectql';
51
53
 
52
54
  // Create custom ObjectQL instance
53
55
  const customQL = new ObjectQL({
@@ -107,14 +109,14 @@ new DriverPlugin(driver, 'driver-name')
107
109
 
108
110
  **Dependencies**: `['com.objectstack.engine.objectql']`
109
111
 
110
- #### AppManifestPlugin
112
+ #### AppPlugin
111
113
  Wraps ObjectStack app manifests (objectstack.config.ts) as plugins.
112
114
 
113
115
  ```typescript
114
- new AppManifestPlugin(appConfig)
116
+ new AppPlugin(appConfig)
115
117
  ```
116
118
 
117
- **Dependencies**: `['com.objectstack.engine.objectql']`
119
+ **Services**: `'app.{id}'`
118
120
 
119
121
  ## API Reference
120
122
 
@@ -246,7 +248,7 @@ See the `examples/` directory for complete examples:
246
248
  - `examples/host/` - Full server setup with Hono
247
249
  - `examples/msw-react-crud/` - Browser-based setup with MSW
248
250
  - `test-mini-kernel.ts` - Comprehensive kernel test suite
249
- - `packages/runtime/src/test-interfaces.ts` - Capability contract interface examples
251
+ - `packages/runtime/src/
250
252
 
251
253
  ## Benefits of MiniKernel
252
254
 
@@ -0,0 +1,18 @@
1
+ import { Plugin, PluginContext } from '@objectstack/core';
2
+ /**
3
+ * AppPlugin
4
+ *
5
+ * Adapts a generic App Bundle (Manifest + Runtime Code) into a Kernel Plugin.
6
+ *
7
+ * Responsibilities:
8
+ * 1. Register App Manifest as a service (for ObjectQL discovery)
9
+ * 2. Execute Runtime `onEnable` hook (for code logic)
10
+ */
11
+ export declare class AppPlugin implements Plugin {
12
+ name: string;
13
+ version?: string;
14
+ private bundle;
15
+ constructor(bundle: any);
16
+ init(ctx: PluginContext): Promise<void>;
17
+ start(ctx: PluginContext): Promise<void>;
18
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * AppPlugin
3
+ *
4
+ * Adapts a generic App Bundle (Manifest + Runtime Code) into a Kernel Plugin.
5
+ *
6
+ * Responsibilities:
7
+ * 1. Register App Manifest as a service (for ObjectQL discovery)
8
+ * 2. Execute Runtime `onEnable` hook (for code logic)
9
+ */
10
+ export class AppPlugin {
11
+ constructor(bundle) {
12
+ this.bundle = bundle;
13
+ // Support both direct manifest (legacy) and Stack Definition (nested manifest)
14
+ const sys = bundle.manifest || bundle;
15
+ const appId = sys.id || sys.name || 'unnamed-app';
16
+ this.name = `plugin.app.${appId}`;
17
+ this.version = sys.version;
18
+ }
19
+ async init(ctx) {
20
+ const sys = this.bundle.manifest || this.bundle;
21
+ const appId = sys.id || sys.name;
22
+ ctx.logger?.log(`[AppPlugin] Registering App Service: ${appId}`);
23
+ // Register the app manifest as a service
24
+ // ObjectQLPlugin will discover this and call ql.registerApp()
25
+ const serviceName = `app.${appId}`;
26
+ ctx.registerService(serviceName, this.bundle.manifest || this.bundle);
27
+ }
28
+ async start(ctx) {
29
+ // Execute Runtime Step
30
+ // Retrieve ObjectQL engine from services
31
+ // We cast to any/ObjectQL because ctx.getService returns unknown
32
+ const ql = ctx.getService('objectql');
33
+ if (!ql) {
34
+ ctx.logger?.warn(`[AppPlugin] ObjectQL engine service not found for app: ${this.name}`);
35
+ return;
36
+ }
37
+ const runtime = this.bundle.default || this.bundle;
38
+ if (runtime && typeof runtime.onEnable === 'function') {
39
+ ctx.logger?.log(`[AppPlugin] Executing runtime.onEnable for: ${this.name}`);
40
+ // Construct the Host Context (mirroring old ObjectQL.use logic)
41
+ const hostContext = {
42
+ ...ctx,
43
+ ql,
44
+ logger: ctx.logger || console,
45
+ drivers: {
46
+ register: (driver) => ql.registerDriver(driver)
47
+ },
48
+ };
49
+ await runtime.onEnable(hostContext);
50
+ }
51
+ }
52
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
2
1
  export { ObjectKernel } from '@objectstack/core';
3
- export { ObjectQLPlugin } from '@objectstack/objectql';
4
2
  export { DriverPlugin } from './driver-plugin';
5
- export { AppManifestPlugin } from './app-manifest-plugin';
3
+ export { AppPlugin } from './app-plugin';
6
4
  export * from '@objectstack/core';
package/dist/index.js CHANGED
@@ -1,10 +1,7 @@
1
- // Export core engine
2
- export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
3
1
  // Export Kernels
4
2
  export { ObjectKernel } from '@objectstack/core';
5
3
  // Export Plugins
6
- export { ObjectQLPlugin } from '@objectstack/objectql';
7
4
  export { DriverPlugin } from './driver-plugin';
8
- export { AppManifestPlugin } from './app-manifest-plugin';
5
+ export { AppPlugin } from './app-plugin';
9
6
  // Export Types
10
7
  export * from '@objectstack/core';
package/package.json CHANGED
@@ -1,15 +1,14 @@
1
1
  {
2
2
  "name": "@objectstack/runtime",
3
- "version": "0.6.0",
3
+ "version": "0.6.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.6.0",
10
- "@objectstack/objectql": "0.6.0",
11
- "@objectstack/types": "0.6.0",
12
- "@objectstack/spec": "0.6.0"
9
+ "@objectstack/core": "0.6.1",
10
+ "@objectstack/types": "0.6.1",
11
+ "@objectstack/spec": "0.6.1"
13
12
  },
14
13
  "devDependencies": {
15
14
  "typescript": "^5.0.0"
@@ -0,0 +1,69 @@
1
+ import { Plugin, PluginContext } from '@objectstack/core';
2
+
3
+ /**
4
+ * AppPlugin
5
+ *
6
+ * Adapts a generic App Bundle (Manifest + Runtime Code) into a Kernel Plugin.
7
+ *
8
+ * Responsibilities:
9
+ * 1. Register App Manifest as a service (for ObjectQL discovery)
10
+ * 2. Execute Runtime `onEnable` hook (for code logic)
11
+ */
12
+ export class AppPlugin implements Plugin {
13
+ name: string;
14
+ version?: string;
15
+
16
+ private bundle: any;
17
+
18
+ constructor(bundle: any) {
19
+ this.bundle = bundle;
20
+ // Support both direct manifest (legacy) and Stack Definition (nested manifest)
21
+ const sys = bundle.manifest || bundle;
22
+ const appId = sys.id || sys.name || 'unnamed-app';
23
+
24
+ this.name = `plugin.app.${appId}`;
25
+ this.version = sys.version;
26
+ }
27
+
28
+ async init(ctx: PluginContext) {
29
+ const sys = this.bundle.manifest || this.bundle;
30
+ const appId = sys.id || sys.name;
31
+
32
+ ctx.logger?.log(`[AppPlugin] Registering App Service: ${appId}`);
33
+
34
+ // Register the app manifest as a service
35
+ // ObjectQLPlugin will discover this and call ql.registerApp()
36
+ const serviceName = `app.${appId}`;
37
+ ctx.registerService(serviceName, this.bundle.manifest || this.bundle);
38
+ }
39
+
40
+ async start(ctx: PluginContext) {
41
+ // Execute Runtime Step
42
+ // Retrieve ObjectQL engine from services
43
+ // We cast to any/ObjectQL because ctx.getService returns unknown
44
+ const ql = ctx.getService('objectql') as any;
45
+
46
+ if (!ql) {
47
+ ctx.logger?.warn(`[AppPlugin] ObjectQL engine service not found for app: ${this.name}`);
48
+ return;
49
+ }
50
+
51
+ const runtime = this.bundle.default || this.bundle;
52
+
53
+ if (runtime && typeof runtime.onEnable === 'function') {
54
+ ctx.logger?.log(`[AppPlugin] Executing runtime.onEnable for: ${this.name}`);
55
+
56
+ // Construct the Host Context (mirroring old ObjectQL.use logic)
57
+ const hostContext = {
58
+ ...ctx,
59
+ ql,
60
+ logger: ctx.logger || console,
61
+ drivers: {
62
+ register: (driver: any) => ql.registerDriver(driver)
63
+ },
64
+ };
65
+
66
+ await runtime.onEnable(hostContext);
67
+ }
68
+ }
69
+ }
package/src/index.ts CHANGED
@@ -1,13 +1,9 @@
1
- // Export core engine
2
- export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
3
-
4
1
  // Export Kernels
5
2
  export { ObjectKernel } from '@objectstack/core';
6
3
 
7
4
  // Export Plugins
8
- export { ObjectQLPlugin } from '@objectstack/objectql';
9
5
  export { DriverPlugin } from './driver-plugin';
10
- export { AppManifestPlugin } from './app-manifest-plugin';
6
+ export { AppPlugin } from './app-plugin';
11
7
 
12
8
  // Export Types
13
9
  export * from '@objectstack/core';
@@ -1,19 +0,0 @@
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
- }
@@ -1,33 +0,0 @@
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
- }
@@ -1,7 +0,0 @@
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 {};
@@ -1,138 +0,0 @@
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 {};
@@ -1,48 +0,0 @@
1
- import { Plugin, PluginContext } from '@objectstack/core';
2
-
3
- /**
4
- * AppManifestPlugin
5
- *
6
- * Adapts a static Manifest JSON into a dynamic Kernel Service.
7
- * This allows the ObjectQL Engine to "discover" this app during its start phase.
8
- *
9
- * Flow:
10
- * 1. AppPlugin registers `app.<id>` service (init phase)
11
- * 2. ObjectQL Engine discovers `app.*` services (start phase)
12
- */
13
- export class AppManifestPlugin implements Plugin {
14
- name: string;
15
- version?: string;
16
-
17
- // Dependencies removed: This plugin produces data. It doesn't need to consume the engine to register itself.
18
- // Making it dependency-free allows it to initialize BEFORE the engine if needed.
19
-
20
- private manifest: any;
21
-
22
- constructor(manifest: any) {
23
- this.manifest = manifest;
24
- // Support both direct manifest (legacy) and Stack Definition (nested manifest)
25
- const sys = manifest.manifest || manifest;
26
- const appId = sys.id || sys.name || 'unnamed-app';
27
-
28
- this.name = `plugin.app.${appId}`; // Unique plugin name
29
- this.version = sys.version;
30
- }
31
-
32
- async init(ctx: PluginContext) {
33
- // Support both direct manifest (legacy) and Stack Definition (nested manifest)
34
- const sys = this.manifest.manifest || this.manifest;
35
- const appId = sys.id || sys.name;
36
-
37
- ctx.logger.log(`[AppManifestPlugin] Registering App Service: ${appId}`);
38
-
39
- // Register the app manifest as a service
40
- const serviceName = `app.${appId}`;
41
- ctx.registerService(serviceName, this.manifest);
42
- }
43
-
44
- async start(ctx: PluginContext) {
45
- // No logic needed here.
46
- // Logic is inverted: The Engine will pull data from this service.
47
- }
48
- }
@@ -1,170 +0,0 @@
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
- import { IHttpServer, IDataEngine, RouteHandler, IHttpRequest, IHttpResponse, Middleware, DataEngineQueryOptions } from './index.js';
9
-
10
- /**
11
- * Example: Mock HTTP Server Plugin
12
- *
13
- * Shows how a plugin can implement the IHttpServer interface
14
- * without depending on Express, Fastify, or any specific framework.
15
- */
16
- class MockHttpServer implements IHttpServer {
17
- private routes: Map<string, { method: string; handler: RouteHandler }> = new Map();
18
-
19
- get(path: string, handler: RouteHandler): void {
20
- this.routes.set(`GET:${path}`, { method: 'GET', handler });
21
- console.log(`✅ Registered GET ${path}`);
22
- }
23
-
24
- post(path: string, handler: RouteHandler): void {
25
- this.routes.set(`POST:${path}`, { method: 'POST', handler });
26
- console.log(`✅ Registered POST ${path}`);
27
- }
28
-
29
- put(path: string, handler: RouteHandler): void {
30
- this.routes.set(`PUT:${path}`, { method: 'PUT', handler });
31
- console.log(`✅ Registered PUT ${path}`);
32
- }
33
-
34
- delete(path: string, handler: RouteHandler): void {
35
- this.routes.set(`DELETE:${path}`, { method: 'DELETE', handler });
36
- console.log(`✅ Registered DELETE ${path}`);
37
- }
38
-
39
- patch(path: string, handler: RouteHandler): void {
40
- this.routes.set(`PATCH:${path}`, { method: 'PATCH', handler });
41
- console.log(`✅ Registered PATCH ${path}`);
42
- }
43
-
44
- use(path: string | Middleware, handler?: Middleware): void {
45
- console.log(`✅ Registered middleware`);
46
- }
47
-
48
- async listen(port: number): Promise<void> {
49
- console.log(`✅ Mock HTTP server listening on port ${port}`);
50
- }
51
-
52
- async close(): Promise<void> {
53
- console.log(`✅ Mock HTTP server closed`);
54
- }
55
- }
56
-
57
- /**
58
- * Example: Mock Data Engine Plugin
59
- *
60
- * Shows how a plugin can implement the IDataEngine interface
61
- * without depending on ObjectQL, Prisma, or any specific database.
62
- */
63
- class MockDataEngine implements IDataEngine {
64
- private store: Map<string, Map<string, any>> = new Map();
65
- private idCounter = 0;
66
-
67
- async insert(objectName: string, data: any): Promise<any> {
68
- if (!this.store.has(objectName)) {
69
- this.store.set(objectName, new Map());
70
- }
71
-
72
- const id = `${objectName}_${++this.idCounter}`;
73
- const record = { id, ...data };
74
- this.store.get(objectName)!.set(id, record);
75
-
76
- console.log(`✅ Inserted into ${objectName}:`, record);
77
- return record;
78
- }
79
-
80
- async find(objectName: string, query?: DataEngineQueryOptions): Promise<any[]> {
81
- const objectStore = this.store.get(objectName);
82
- if (!objectStore) {
83
- return [];
84
- }
85
-
86
- const results = Array.from(objectStore.values());
87
- console.log(`✅ Found ${results.length} records in ${objectName}`);
88
- return results;
89
- }
90
-
91
- async update(objectName: string, id: any, data: any): Promise<any> {
92
- const objectStore = this.store.get(objectName);
93
- if (!objectStore || !objectStore.has(id)) {
94
- throw new Error(`Record ${id} not found in ${objectName}`);
95
- }
96
-
97
- const existing = objectStore.get(id);
98
- const updated = { ...existing, ...data };
99
- objectStore.set(id, updated);
100
-
101
- console.log(`✅ Updated ${objectName}/${id}:`, updated);
102
- return updated;
103
- }
104
-
105
- async delete(objectName: string, id: any): Promise<boolean> {
106
- const objectStore = this.store.get(objectName);
107
- if (!objectStore) {
108
- return false;
109
- }
110
-
111
- const deleted = objectStore.delete(id);
112
- console.log(`✅ Deleted ${objectName}/${id}: ${deleted}`);
113
- return deleted;
114
- }
115
- }
116
-
117
- /**
118
- * Test the interfaces
119
- */
120
- async function testInterfaces() {
121
- console.log('\n=== Testing IHttpServer Interface ===\n');
122
-
123
- const httpServer: IHttpServer = new MockHttpServer();
124
-
125
- // Register routes using the interface
126
- httpServer.get('/api/users', async (req, res) => {
127
- res.json({ users: [] });
128
- });
129
-
130
- httpServer.post('/api/users', async (req, res) => {
131
- res.status(201).json({ id: 1, ...req.body });
132
- });
133
-
134
- await httpServer.listen(3000);
135
-
136
- console.log('\n=== Testing IDataEngine Interface ===\n');
137
-
138
- const dataEngine: IDataEngine = new MockDataEngine();
139
-
140
- // Use the data engine interface
141
- const user1 = await dataEngine.insert('user', {
142
- name: 'John Doe',
143
- email: 'john@example.com'
144
- });
145
-
146
- const user2 = await dataEngine.insert('user', {
147
- name: 'Jane Smith',
148
- email: 'jane@example.com'
149
- });
150
-
151
- const users = await dataEngine.find('user');
152
- console.log(`Found ${users.length} users after inserts`);
153
-
154
- const updatedUser = await dataEngine.update('user', user1.id, {
155
- name: 'John Updated'
156
- });
157
- console.log(`Updated user:`, updatedUser);
158
-
159
- const deleted = await dataEngine.delete('user', user2.id);
160
- console.log(`Delete result: ${deleted}`);
161
-
162
- console.log('\n✅ All interface tests passed!\n');
163
-
164
- if (httpServer.close) {
165
- await httpServer.close();
166
- }
167
- }
168
-
169
- // Run tests
170
- testInterfaces().catch(console.error);