@objectstack/runtime 0.6.0 → 0.7.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,25 @@
1
1
  # @objectstack/runtime
2
2
 
3
+ ## 0.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Patch release for maintenance and stability improvements
8
+ - Updated dependencies
9
+ - @objectstack/spec@0.7.1
10
+ - @objectstack/types@0.7.1
11
+ - @objectstack/core@0.7.1
12
+
13
+ ## 0.6.1
14
+
15
+ ### Patch Changes
16
+
17
+ - Patch release for maintenance and stability improvements
18
+ - Updated dependencies
19
+ - @objectstack/spec@0.6.1
20
+ - @objectstack/types@0.6.1
21
+ - @objectstack/core@0.6.1
22
+
3
23
  ## 0.6.0
4
24
 
5
25
  ### 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,80 @@
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.info('Registering App Service', {
23
+ appId,
24
+ pluginName: this.name,
25
+ version: this.version
26
+ });
27
+ // Register the app manifest as a service
28
+ // ObjectQLPlugin will discover this and call ql.registerApp()
29
+ const serviceName = `app.${appId}`;
30
+ // Merge manifest with the bundle to ensure objects/apps are accessible at root
31
+ // This supports both Legacy Manifests and new Stack Definitions
32
+ const servicePayload = this.bundle.manifest
33
+ ? { ...this.bundle.manifest, ...this.bundle }
34
+ : this.bundle;
35
+ ctx.registerService(serviceName, servicePayload);
36
+ }
37
+ async start(ctx) {
38
+ const sys = this.bundle.manifest || this.bundle;
39
+ const appId = sys.id || sys.name;
40
+ // Execute Runtime Step
41
+ // Retrieve ObjectQL engine from services
42
+ // We cast to any/ObjectQL because ctx.getService returns unknown
43
+ const ql = ctx.getService('objectql');
44
+ if (!ql) {
45
+ ctx.logger.warn('ObjectQL engine service not found', {
46
+ appName: this.name,
47
+ appId
48
+ });
49
+ return;
50
+ }
51
+ ctx.logger.debug('Retrieved ObjectQL engine service', { appId });
52
+ const runtime = this.bundle.default || this.bundle;
53
+ if (runtime && typeof runtime.onEnable === 'function') {
54
+ ctx.logger.info('Executing runtime.onEnable', {
55
+ appName: this.name,
56
+ appId
57
+ });
58
+ // Construct the Host Context (mirroring old ObjectQL.use logic)
59
+ const hostContext = {
60
+ ...ctx,
61
+ ql,
62
+ logger: ctx.logger,
63
+ drivers: {
64
+ register: (driver) => {
65
+ ctx.logger.debug('Registering driver via app runtime', {
66
+ driverName: driver.name,
67
+ appId
68
+ });
69
+ ql.registerDriver(driver);
70
+ }
71
+ },
72
+ };
73
+ await runtime.onEnable(hostContext);
74
+ ctx.logger.debug('Runtime.onEnable completed', { appId });
75
+ }
76
+ else {
77
+ ctx.logger.debug('No runtime.onEnable function found', { appId });
78
+ }
79
+ }
80
+ }
@@ -22,10 +22,14 @@ export class DriverPlugin {
22
22
  // Register driver as a service instead of directly to objectql
23
23
  const serviceName = `driver.${this.driver.name || 'unknown'}`;
24
24
  ctx.registerService(serviceName, this.driver);
25
- ctx.logger.log(`[DriverPlugin] Registered driver service: ${serviceName}`);
25
+ ctx.logger.info('Driver service registered', {
26
+ serviceName,
27
+ driverName: this.driver.name,
28
+ driverVersion: this.driver.version
29
+ });
26
30
  }
27
31
  async start(ctx) {
28
32
  // Drivers don't need start phase, initialization happens in init
29
- ctx.logger.log(`[DriverPlugin] Driver ready: ${this.driver.name || 'unknown'}`);
33
+ ctx.logger.debug('Driver plugin started', { driverName: this.driver.name || 'unknown' });
30
34
  }
31
35
  }
@@ -0,0 +1,84 @@
1
+ import { IHttpServer, RouteHandler, Middleware } from '@objectstack/core';
2
+ /**
3
+ * HttpServer - Unified HTTP Server Abstraction
4
+ *
5
+ * Provides a framework-agnostic HTTP server interface that wraps
6
+ * underlying server implementations (Hono, Express, Fastify, etc.)
7
+ *
8
+ * This class serves as an adapter between the IHttpServer interface
9
+ * and concrete server implementations, allowing plugins to register
10
+ * routes and middleware without depending on specific frameworks.
11
+ *
12
+ * Features:
13
+ * - Unified route registration API
14
+ * - Middleware management with ordering
15
+ * - Request/response lifecycle hooks
16
+ * - Framework-agnostic abstractions
17
+ */
18
+ export declare class HttpServer implements IHttpServer {
19
+ protected server: IHttpServer;
20
+ protected routes: Map<string, RouteHandler>;
21
+ protected middlewares: Middleware[];
22
+ /**
23
+ * Create an HTTP server wrapper
24
+ * @param server - The underlying server implementation (Hono, Express, etc.)
25
+ */
26
+ constructor(server: IHttpServer);
27
+ /**
28
+ * Register a GET route handler
29
+ * @param path - Route path (e.g., '/api/users/:id')
30
+ * @param handler - Route handler function
31
+ */
32
+ get(path: string, handler: RouteHandler): void;
33
+ /**
34
+ * Register a POST route handler
35
+ * @param path - Route path
36
+ * @param handler - Route handler function
37
+ */
38
+ post(path: string, handler: RouteHandler): void;
39
+ /**
40
+ * Register a PUT route handler
41
+ * @param path - Route path
42
+ * @param handler - Route handler function
43
+ */
44
+ put(path: string, handler: RouteHandler): void;
45
+ /**
46
+ * Register a DELETE route handler
47
+ * @param path - Route path
48
+ * @param handler - Route handler function
49
+ */
50
+ delete(path: string, handler: RouteHandler): void;
51
+ /**
52
+ * Register a PATCH route handler
53
+ * @param path - Route path
54
+ * @param handler - Route handler function
55
+ */
56
+ patch(path: string, handler: RouteHandler): void;
57
+ /**
58
+ * Register middleware
59
+ * @param path - Optional path to apply middleware to (if omitted, applies globally)
60
+ * @param handler - Middleware function
61
+ */
62
+ use(path: string | Middleware, handler?: Middleware): void;
63
+ /**
64
+ * Start the HTTP server
65
+ * @param port - Port number to listen on
66
+ * @returns Promise that resolves when server is ready
67
+ */
68
+ listen(port: number): Promise<void>;
69
+ /**
70
+ * Stop the HTTP server
71
+ * @returns Promise that resolves when server is stopped
72
+ */
73
+ close(): Promise<void>;
74
+ /**
75
+ * Get registered routes
76
+ * @returns Map of route keys to handlers
77
+ */
78
+ getRoutes(): Map<string, RouteHandler>;
79
+ /**
80
+ * Get registered middlewares
81
+ * @returns Array of middleware functions
82
+ */
83
+ getMiddlewares(): Middleware[];
84
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * HttpServer - Unified HTTP Server Abstraction
3
+ *
4
+ * Provides a framework-agnostic HTTP server interface that wraps
5
+ * underlying server implementations (Hono, Express, Fastify, etc.)
6
+ *
7
+ * This class serves as an adapter between the IHttpServer interface
8
+ * and concrete server implementations, allowing plugins to register
9
+ * routes and middleware without depending on specific frameworks.
10
+ *
11
+ * Features:
12
+ * - Unified route registration API
13
+ * - Middleware management with ordering
14
+ * - Request/response lifecycle hooks
15
+ * - Framework-agnostic abstractions
16
+ */
17
+ export class HttpServer {
18
+ /**
19
+ * Create an HTTP server wrapper
20
+ * @param server - The underlying server implementation (Hono, Express, etc.)
21
+ */
22
+ constructor(server) {
23
+ this.server = server;
24
+ this.routes = new Map();
25
+ this.middlewares = [];
26
+ }
27
+ /**
28
+ * Register a GET route handler
29
+ * @param path - Route path (e.g., '/api/users/:id')
30
+ * @param handler - Route handler function
31
+ */
32
+ get(path, handler) {
33
+ const key = `GET:${path}`;
34
+ this.routes.set(key, handler);
35
+ this.server.get(path, handler);
36
+ }
37
+ /**
38
+ * Register a POST route handler
39
+ * @param path - Route path
40
+ * @param handler - Route handler function
41
+ */
42
+ post(path, handler) {
43
+ const key = `POST:${path}`;
44
+ this.routes.set(key, handler);
45
+ this.server.post(path, handler);
46
+ }
47
+ /**
48
+ * Register a PUT route handler
49
+ * @param path - Route path
50
+ * @param handler - Route handler function
51
+ */
52
+ put(path, handler) {
53
+ const key = `PUT:${path}`;
54
+ this.routes.set(key, handler);
55
+ this.server.put(path, handler);
56
+ }
57
+ /**
58
+ * Register a DELETE route handler
59
+ * @param path - Route path
60
+ * @param handler - Route handler function
61
+ */
62
+ delete(path, handler) {
63
+ const key = `DELETE:${path}`;
64
+ this.routes.set(key, handler);
65
+ this.server.delete(path, handler);
66
+ }
67
+ /**
68
+ * Register a PATCH route handler
69
+ * @param path - Route path
70
+ * @param handler - Route handler function
71
+ */
72
+ patch(path, handler) {
73
+ const key = `PATCH:${path}`;
74
+ this.routes.set(key, handler);
75
+ this.server.patch(path, handler);
76
+ }
77
+ /**
78
+ * Register middleware
79
+ * @param path - Optional path to apply middleware to (if omitted, applies globally)
80
+ * @param handler - Middleware function
81
+ */
82
+ use(path, handler) {
83
+ if (typeof path === 'function') {
84
+ // Global middleware
85
+ this.middlewares.push(path);
86
+ this.server.use(path);
87
+ }
88
+ else if (handler) {
89
+ // Path-specific middleware
90
+ this.middlewares.push(handler);
91
+ this.server.use(path, handler);
92
+ }
93
+ }
94
+ /**
95
+ * Start the HTTP server
96
+ * @param port - Port number to listen on
97
+ * @returns Promise that resolves when server is ready
98
+ */
99
+ async listen(port) {
100
+ await this.server.listen(port);
101
+ }
102
+ /**
103
+ * Stop the HTTP server
104
+ * @returns Promise that resolves when server is stopped
105
+ */
106
+ async close() {
107
+ if (this.server.close) {
108
+ await this.server.close();
109
+ }
110
+ }
111
+ /**
112
+ * Get registered routes
113
+ * @returns Map of route keys to handlers
114
+ */
115
+ getRoutes() {
116
+ return new Map(this.routes);
117
+ }
118
+ /**
119
+ * Get registered middlewares
120
+ * @returns Array of middleware functions
121
+ */
122
+ getMiddlewares() {
123
+ return [...this.middlewares];
124
+ }
125
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- export { ObjectQL, SchemaRegistry, ObjectStackProtocolImplementation } from '@objectstack/objectql';
2
1
  export { ObjectKernel } from '@objectstack/core';
3
- export { ObjectQLPlugin } from '@objectstack/objectql';
4
- export { DriverPlugin } from './driver-plugin';
5
- export { AppManifestPlugin } from './app-manifest-plugin';
2
+ export { DriverPlugin } from './driver-plugin.js';
3
+ export { AppPlugin } from './app-plugin.js';
4
+ export { HttpServer } from './http-server.js';
5
+ export { RestServer } from './rest-server.js';
6
+ export { RouteManager, RouteGroupBuilder } from './route-manager.js';
7
+ export { MiddlewareManager } from './middleware.js';
6
8
  export * from '@objectstack/core';
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
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
- export { DriverPlugin } from './driver-plugin';
8
- export { AppManifestPlugin } from './app-manifest-plugin';
4
+ export { DriverPlugin } from './driver-plugin.js';
5
+ export { AppPlugin } from './app-plugin.js';
6
+ // Export HTTP Server Components
7
+ export { HttpServer } from './http-server.js';
8
+ export { RestServer } from './rest-server.js';
9
+ export { RouteManager, RouteGroupBuilder } from './route-manager.js';
10
+ export { MiddlewareManager } from './middleware.js';
9
11
  // Export Types
10
12
  export * from '@objectstack/core';
@@ -0,0 +1,111 @@
1
+ import { Middleware } from '@objectstack/core';
2
+ import { MiddlewareConfig, MiddlewareType } from '@objectstack/spec/system';
3
+ /**
4
+ * Middleware Entry
5
+ * Internal representation of registered middleware
6
+ */
7
+ interface MiddlewareEntry {
8
+ name: string;
9
+ type: MiddlewareType;
10
+ middleware: Middleware;
11
+ order: number;
12
+ enabled: boolean;
13
+ paths?: {
14
+ include?: string[];
15
+ exclude?: string[];
16
+ };
17
+ }
18
+ /**
19
+ * MiddlewareManager
20
+ *
21
+ * Manages middleware registration, ordering, and execution.
22
+ * Provides fine-grained control over middleware chains with:
23
+ * - Execution order management
24
+ * - Path-based filtering
25
+ * - Enable/disable individual middleware
26
+ * - Middleware categorization by type
27
+ *
28
+ * @example
29
+ * const manager = new MiddlewareManager();
30
+ *
31
+ * // Register middleware with configuration
32
+ * manager.register({
33
+ * name: 'auth',
34
+ * type: 'authentication',
35
+ * order: 10,
36
+ * paths: { exclude: ['/health', '/metrics'] }
37
+ * }, authMiddleware);
38
+ *
39
+ * // Get sorted middleware chain
40
+ * const chain = manager.getMiddlewareChain();
41
+ * chain.forEach(mw => server.use(mw));
42
+ */
43
+ export declare class MiddlewareManager {
44
+ private middlewares;
45
+ constructor();
46
+ /**
47
+ * Register middleware with configuration
48
+ * @param config - Middleware configuration
49
+ * @param middleware - Middleware function
50
+ */
51
+ register(config: MiddlewareConfig, middleware: Middleware): void;
52
+ /**
53
+ * Unregister middleware by name
54
+ * @param name - Middleware name
55
+ */
56
+ unregister(name: string): void;
57
+ /**
58
+ * Enable middleware by name
59
+ * @param name - Middleware name
60
+ */
61
+ enable(name: string): void;
62
+ /**
63
+ * Disable middleware by name
64
+ * @param name - Middleware name
65
+ */
66
+ disable(name: string): void;
67
+ /**
68
+ * Get middleware entry by name
69
+ * @param name - Middleware name
70
+ */
71
+ get(name: string): MiddlewareEntry | undefined;
72
+ /**
73
+ * Get all middleware entries
74
+ */
75
+ getAll(): MiddlewareEntry[];
76
+ /**
77
+ * Get middleware by type
78
+ * @param type - Middleware type
79
+ */
80
+ getByType(type: MiddlewareType): MiddlewareEntry[];
81
+ /**
82
+ * Get middleware chain sorted by order
83
+ * Returns only enabled middleware
84
+ */
85
+ getMiddlewareChain(): Middleware[];
86
+ /**
87
+ * Get middleware chain with path filtering
88
+ * @param path - Request path to match against
89
+ */
90
+ getMiddlewareChainForPath(path: string): Middleware[];
91
+ /**
92
+ * Match path against pattern (simple glob matching)
93
+ * @param path - Request path
94
+ * @param pattern - Pattern to match (supports * wildcard)
95
+ */
96
+ private matchPath;
97
+ /**
98
+ * Clear all middleware
99
+ */
100
+ clear(): void;
101
+ /**
102
+ * Get middleware count
103
+ */
104
+ count(): number;
105
+ /**
106
+ * Create a composite middleware from the chain
107
+ * This can be used to apply all middleware at once
108
+ */
109
+ createCompositeMiddleware(): Middleware;
110
+ }
111
+ export {};