@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 +20 -0
- package/README.md +10 -8
- package/dist/app-plugin.d.ts +18 -0
- package/dist/app-plugin.js +80 -0
- package/dist/driver-plugin.js +6 -2
- package/dist/http-server.d.ts +84 -0
- package/dist/http-server.js +125 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +7 -5
- package/dist/middleware.d.ts +111 -0
- package/dist/middleware.js +176 -0
- package/dist/rest-server.d.ts +74 -0
- package/dist/rest-server.js +490 -0
- package/dist/route-manager.d.ts +153 -0
- package/dist/route-manager.js +251 -0
- package/package.json +4 -5
- package/src/app-plugin.ts +100 -0
- package/src/driver-plugin.ts +6 -2
- package/src/http-server.ts +140 -0
- package/src/index.ts +9 -6
- package/src/middleware.ts +220 -0
- package/src/rest-server.ts +579 -0
- package/src/route-manager.ts +305 -0
- package/dist/app-manifest-plugin.d.ts +0 -19
- package/dist/app-manifest-plugin.js +0 -33
- package/dist/test-interfaces.d.ts +0 -7
- package/dist/test-interfaces.js +0 -138
- package/src/app-manifest-plugin.ts +0 -48
- package/src/test-interfaces.ts +0 -170
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RouteManager
|
|
3
|
+
*
|
|
4
|
+
* Manages route registration and organization for HTTP servers.
|
|
5
|
+
* Provides:
|
|
6
|
+
* - Route registration with metadata
|
|
7
|
+
* - Route lookup and querying
|
|
8
|
+
* - Bulk route registration
|
|
9
|
+
* - Route grouping by prefix
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const manager = new RouteManager(server);
|
|
13
|
+
*
|
|
14
|
+
* // Register individual route
|
|
15
|
+
* manager.register({
|
|
16
|
+
* method: 'GET',
|
|
17
|
+
* path: '/api/users/:id',
|
|
18
|
+
* handler: getUserHandler,
|
|
19
|
+
* metadata: {
|
|
20
|
+
* summary: 'Get user by ID',
|
|
21
|
+
* tags: ['users']
|
|
22
|
+
* }
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Register route group
|
|
26
|
+
* manager.group('/api/users', (group) => {
|
|
27
|
+
* group.get('/', listUsersHandler);
|
|
28
|
+
* group.post('/', createUserHandler);
|
|
29
|
+
* group.get('/:id', getUserHandler);
|
|
30
|
+
* });
|
|
31
|
+
*/
|
|
32
|
+
export class RouteManager {
|
|
33
|
+
constructor(server) {
|
|
34
|
+
this.server = server;
|
|
35
|
+
this.routes = new Map();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register a route
|
|
39
|
+
* @param entry - Route entry with method, path, handler, and metadata
|
|
40
|
+
*/
|
|
41
|
+
register(entry) {
|
|
42
|
+
// Validate handler type - string handlers not yet supported
|
|
43
|
+
if (typeof entry.handler === 'string') {
|
|
44
|
+
throw new Error(`String-based route handlers are not supported yet. ` +
|
|
45
|
+
`Received handler identifier "${entry.handler}". ` +
|
|
46
|
+
`Please provide a RouteHandler function instead.`);
|
|
47
|
+
}
|
|
48
|
+
const handler = entry.handler;
|
|
49
|
+
const routeEntry = {
|
|
50
|
+
method: entry.method,
|
|
51
|
+
path: entry.path,
|
|
52
|
+
handler,
|
|
53
|
+
metadata: entry.metadata,
|
|
54
|
+
security: entry.security,
|
|
55
|
+
};
|
|
56
|
+
const key = this.getRouteKey(entry.method, entry.path);
|
|
57
|
+
this.routes.set(key, routeEntry);
|
|
58
|
+
// Register with underlying server
|
|
59
|
+
this.registerWithServer(routeEntry);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Register multiple routes
|
|
63
|
+
* @param entries - Array of route entries
|
|
64
|
+
*/
|
|
65
|
+
registerMany(entries) {
|
|
66
|
+
entries.forEach(entry => this.register(entry));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Unregister a route
|
|
70
|
+
* @param method - HTTP method
|
|
71
|
+
* @param path - Route path
|
|
72
|
+
*/
|
|
73
|
+
unregister(method, path) {
|
|
74
|
+
const key = this.getRouteKey(method, path);
|
|
75
|
+
this.routes.delete(key);
|
|
76
|
+
// Note: Most server frameworks don't support unregistering routes at runtime
|
|
77
|
+
// This just removes it from our registry
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get route by method and path
|
|
81
|
+
* @param method - HTTP method
|
|
82
|
+
* @param path - Route path
|
|
83
|
+
*/
|
|
84
|
+
get(method, path) {
|
|
85
|
+
const key = this.getRouteKey(method, path);
|
|
86
|
+
return this.routes.get(key);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get all routes
|
|
90
|
+
*/
|
|
91
|
+
getAll() {
|
|
92
|
+
return Array.from(this.routes.values());
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get routes by method
|
|
96
|
+
* @param method - HTTP method
|
|
97
|
+
*/
|
|
98
|
+
getByMethod(method) {
|
|
99
|
+
return this.getAll().filter(route => route.method === method);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get routes by path prefix
|
|
103
|
+
* @param prefix - Path prefix
|
|
104
|
+
*/
|
|
105
|
+
getByPrefix(prefix) {
|
|
106
|
+
return this.getAll().filter(route => route.path.startsWith(prefix));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get routes by tag
|
|
110
|
+
* @param tag - Tag name
|
|
111
|
+
*/
|
|
112
|
+
getByTag(tag) {
|
|
113
|
+
return this.getAll().filter(route => route.metadata?.tags?.includes(tag));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a route group with common prefix
|
|
117
|
+
* @param prefix - Common path prefix
|
|
118
|
+
* @param configure - Function to configure routes in the group
|
|
119
|
+
*/
|
|
120
|
+
group(prefix, configure) {
|
|
121
|
+
const builder = new RouteGroupBuilder(this, prefix);
|
|
122
|
+
configure(builder);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get route count
|
|
126
|
+
*/
|
|
127
|
+
count() {
|
|
128
|
+
return this.routes.size;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Clear all routes
|
|
132
|
+
*/
|
|
133
|
+
clear() {
|
|
134
|
+
this.routes.clear();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get route key for storage
|
|
138
|
+
*/
|
|
139
|
+
getRouteKey(method, path) {
|
|
140
|
+
return `${method}:${path}`;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Register route with underlying server
|
|
144
|
+
*/
|
|
145
|
+
registerWithServer(entry) {
|
|
146
|
+
const { method, path, handler } = entry;
|
|
147
|
+
switch (method) {
|
|
148
|
+
case 'GET':
|
|
149
|
+
this.server.get(path, handler);
|
|
150
|
+
break;
|
|
151
|
+
case 'POST':
|
|
152
|
+
this.server.post(path, handler);
|
|
153
|
+
break;
|
|
154
|
+
case 'PUT':
|
|
155
|
+
this.server.put(path, handler);
|
|
156
|
+
break;
|
|
157
|
+
case 'DELETE':
|
|
158
|
+
this.server.delete(path, handler);
|
|
159
|
+
break;
|
|
160
|
+
case 'PATCH':
|
|
161
|
+
this.server.patch(path, handler);
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* RouteGroupBuilder
|
|
170
|
+
*
|
|
171
|
+
* Builder for creating route groups with common prefix
|
|
172
|
+
*/
|
|
173
|
+
export class RouteGroupBuilder {
|
|
174
|
+
constructor(manager, prefix) {
|
|
175
|
+
this.manager = manager;
|
|
176
|
+
this.prefix = prefix;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Register GET route in group
|
|
180
|
+
*/
|
|
181
|
+
get(path, handler, metadata) {
|
|
182
|
+
this.manager.register({
|
|
183
|
+
method: 'GET',
|
|
184
|
+
path: this.resolvePath(path),
|
|
185
|
+
handler,
|
|
186
|
+
metadata,
|
|
187
|
+
});
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Register POST route in group
|
|
192
|
+
*/
|
|
193
|
+
post(path, handler, metadata) {
|
|
194
|
+
this.manager.register({
|
|
195
|
+
method: 'POST',
|
|
196
|
+
path: this.resolvePath(path),
|
|
197
|
+
handler,
|
|
198
|
+
metadata,
|
|
199
|
+
});
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Register PUT route in group
|
|
204
|
+
*/
|
|
205
|
+
put(path, handler, metadata) {
|
|
206
|
+
this.manager.register({
|
|
207
|
+
method: 'PUT',
|
|
208
|
+
path: this.resolvePath(path),
|
|
209
|
+
handler,
|
|
210
|
+
metadata,
|
|
211
|
+
});
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Register PATCH route in group
|
|
216
|
+
*/
|
|
217
|
+
patch(path, handler, metadata) {
|
|
218
|
+
this.manager.register({
|
|
219
|
+
method: 'PATCH',
|
|
220
|
+
path: this.resolvePath(path),
|
|
221
|
+
handler,
|
|
222
|
+
metadata,
|
|
223
|
+
});
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Register DELETE route in group
|
|
228
|
+
*/
|
|
229
|
+
delete(path, handler, metadata) {
|
|
230
|
+
this.manager.register({
|
|
231
|
+
method: 'DELETE',
|
|
232
|
+
path: this.resolvePath(path),
|
|
233
|
+
handler,
|
|
234
|
+
metadata,
|
|
235
|
+
});
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Resolve full path with prefix
|
|
240
|
+
*/
|
|
241
|
+
resolvePath(path) {
|
|
242
|
+
// Normalize slashes
|
|
243
|
+
const normalizedPrefix = this.prefix.endsWith('/')
|
|
244
|
+
? this.prefix.slice(0, -1)
|
|
245
|
+
: this.prefix;
|
|
246
|
+
const normalizedPath = path.startsWith('/')
|
|
247
|
+
? path
|
|
248
|
+
: '/' + path;
|
|
249
|
+
return normalizedPrefix + normalizedPath;
|
|
250
|
+
}
|
|
251
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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.
|
|
10
|
-
"@objectstack/
|
|
11
|
-
"@objectstack/
|
|
12
|
-
"@objectstack/spec": "0.6.0"
|
|
9
|
+
"@objectstack/core": "0.7.1",
|
|
10
|
+
"@objectstack/types": "0.7.1",
|
|
11
|
+
"@objectstack/spec": "0.7.1"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
14
|
"typescript": "^5.0.0"
|
|
@@ -0,0 +1,100 @@
|
|
|
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.info('Registering App Service', {
|
|
33
|
+
appId,
|
|
34
|
+
pluginName: this.name,
|
|
35
|
+
version: this.version
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Register the app manifest as a service
|
|
39
|
+
// ObjectQLPlugin will discover this and call ql.registerApp()
|
|
40
|
+
const serviceName = `app.${appId}`;
|
|
41
|
+
|
|
42
|
+
// Merge manifest with the bundle to ensure objects/apps are accessible at root
|
|
43
|
+
// This supports both Legacy Manifests and new Stack Definitions
|
|
44
|
+
const servicePayload = this.bundle.manifest
|
|
45
|
+
? { ...this.bundle.manifest, ...this.bundle }
|
|
46
|
+
: this.bundle;
|
|
47
|
+
|
|
48
|
+
ctx.registerService(serviceName, servicePayload);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async start(ctx: PluginContext) {
|
|
52
|
+
const sys = this.bundle.manifest || this.bundle;
|
|
53
|
+
const appId = sys.id || sys.name;
|
|
54
|
+
|
|
55
|
+
// Execute Runtime Step
|
|
56
|
+
// Retrieve ObjectQL engine from services
|
|
57
|
+
// We cast to any/ObjectQL because ctx.getService returns unknown
|
|
58
|
+
const ql = ctx.getService('objectql') as any;
|
|
59
|
+
|
|
60
|
+
if (!ql) {
|
|
61
|
+
ctx.logger.warn('ObjectQL engine service not found', {
|
|
62
|
+
appName: this.name,
|
|
63
|
+
appId
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
ctx.logger.debug('Retrieved ObjectQL engine service', { appId });
|
|
69
|
+
|
|
70
|
+
const runtime = this.bundle.default || this.bundle;
|
|
71
|
+
|
|
72
|
+
if (runtime && typeof runtime.onEnable === 'function') {
|
|
73
|
+
ctx.logger.info('Executing runtime.onEnable', {
|
|
74
|
+
appName: this.name,
|
|
75
|
+
appId
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Construct the Host Context (mirroring old ObjectQL.use logic)
|
|
79
|
+
const hostContext = {
|
|
80
|
+
...ctx,
|
|
81
|
+
ql,
|
|
82
|
+
logger: ctx.logger,
|
|
83
|
+
drivers: {
|
|
84
|
+
register: (driver: any) => {
|
|
85
|
+
ctx.logger.debug('Registering driver via app runtime', {
|
|
86
|
+
driverName: driver.name,
|
|
87
|
+
appId
|
|
88
|
+
});
|
|
89
|
+
ql.registerDriver(driver);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
await runtime.onEnable(hostContext);
|
|
95
|
+
ctx.logger.debug('Runtime.onEnable completed', { appId });
|
|
96
|
+
} else {
|
|
97
|
+
ctx.logger.debug('No runtime.onEnable function found', { appId });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/driver-plugin.ts
CHANGED
|
@@ -30,11 +30,15 @@ export class DriverPlugin implements Plugin {
|
|
|
30
30
|
// Register driver as a service instead of directly to objectql
|
|
31
31
|
const serviceName = `driver.${this.driver.name || 'unknown'}`;
|
|
32
32
|
ctx.registerService(serviceName, this.driver);
|
|
33
|
-
ctx.logger.
|
|
33
|
+
ctx.logger.info('Driver service registered', {
|
|
34
|
+
serviceName,
|
|
35
|
+
driverName: this.driver.name,
|
|
36
|
+
driverVersion: this.driver.version
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
async start(ctx: PluginContext) {
|
|
37
41
|
// Drivers don't need start phase, initialization happens in init
|
|
38
|
-
ctx.logger.
|
|
42
|
+
ctx.logger.debug('Driver plugin started', { driverName: this.driver.name || 'unknown' });
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { IHttpServer, RouteHandler, Middleware } from '@objectstack/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HttpServer - Unified HTTP Server Abstraction
|
|
5
|
+
*
|
|
6
|
+
* Provides a framework-agnostic HTTP server interface that wraps
|
|
7
|
+
* underlying server implementations (Hono, Express, Fastify, etc.)
|
|
8
|
+
*
|
|
9
|
+
* This class serves as an adapter between the IHttpServer interface
|
|
10
|
+
* and concrete server implementations, allowing plugins to register
|
|
11
|
+
* routes and middleware without depending on specific frameworks.
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - Unified route registration API
|
|
15
|
+
* - Middleware management with ordering
|
|
16
|
+
* - Request/response lifecycle hooks
|
|
17
|
+
* - Framework-agnostic abstractions
|
|
18
|
+
*/
|
|
19
|
+
export class HttpServer implements IHttpServer {
|
|
20
|
+
protected server: IHttpServer;
|
|
21
|
+
protected routes: Map<string, RouteHandler>;
|
|
22
|
+
protected middlewares: Middleware[];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create an HTTP server wrapper
|
|
26
|
+
* @param server - The underlying server implementation (Hono, Express, etc.)
|
|
27
|
+
*/
|
|
28
|
+
constructor(server: IHttpServer) {
|
|
29
|
+
this.server = server;
|
|
30
|
+
this.routes = new Map();
|
|
31
|
+
this.middlewares = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Register a GET route handler
|
|
36
|
+
* @param path - Route path (e.g., '/api/users/:id')
|
|
37
|
+
* @param handler - Route handler function
|
|
38
|
+
*/
|
|
39
|
+
get(path: string, handler: RouteHandler): void {
|
|
40
|
+
const key = `GET:${path}`;
|
|
41
|
+
this.routes.set(key, handler);
|
|
42
|
+
this.server.get(path, handler);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Register a POST route handler
|
|
47
|
+
* @param path - Route path
|
|
48
|
+
* @param handler - Route handler function
|
|
49
|
+
*/
|
|
50
|
+
post(path: string, handler: RouteHandler): void {
|
|
51
|
+
const key = `POST:${path}`;
|
|
52
|
+
this.routes.set(key, handler);
|
|
53
|
+
this.server.post(path, handler);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register a PUT route handler
|
|
58
|
+
* @param path - Route path
|
|
59
|
+
* @param handler - Route handler function
|
|
60
|
+
*/
|
|
61
|
+
put(path: string, handler: RouteHandler): void {
|
|
62
|
+
const key = `PUT:${path}`;
|
|
63
|
+
this.routes.set(key, handler);
|
|
64
|
+
this.server.put(path, handler);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Register a DELETE route handler
|
|
69
|
+
* @param path - Route path
|
|
70
|
+
* @param handler - Route handler function
|
|
71
|
+
*/
|
|
72
|
+
delete(path: string, handler: RouteHandler): void {
|
|
73
|
+
const key = `DELETE:${path}`;
|
|
74
|
+
this.routes.set(key, handler);
|
|
75
|
+
this.server.delete(path, handler);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Register a PATCH route handler
|
|
80
|
+
* @param path - Route path
|
|
81
|
+
* @param handler - Route handler function
|
|
82
|
+
*/
|
|
83
|
+
patch(path: string, handler: RouteHandler): void {
|
|
84
|
+
const key = `PATCH:${path}`;
|
|
85
|
+
this.routes.set(key, handler);
|
|
86
|
+
this.server.patch(path, handler);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Register middleware
|
|
91
|
+
* @param path - Optional path to apply middleware to (if omitted, applies globally)
|
|
92
|
+
* @param handler - Middleware function
|
|
93
|
+
*/
|
|
94
|
+
use(path: string | Middleware, handler?: Middleware): void {
|
|
95
|
+
if (typeof path === 'function') {
|
|
96
|
+
// Global middleware
|
|
97
|
+
this.middlewares.push(path);
|
|
98
|
+
this.server.use(path);
|
|
99
|
+
} else if (handler) {
|
|
100
|
+
// Path-specific middleware
|
|
101
|
+
this.middlewares.push(handler);
|
|
102
|
+
this.server.use(path, handler);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Start the HTTP server
|
|
108
|
+
* @param port - Port number to listen on
|
|
109
|
+
* @returns Promise that resolves when server is ready
|
|
110
|
+
*/
|
|
111
|
+
async listen(port: number): Promise<void> {
|
|
112
|
+
await this.server.listen(port);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Stop the HTTP server
|
|
117
|
+
* @returns Promise that resolves when server is stopped
|
|
118
|
+
*/
|
|
119
|
+
async close(): Promise<void> {
|
|
120
|
+
if (this.server.close) {
|
|
121
|
+
await this.server.close();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get registered routes
|
|
127
|
+
* @returns Map of route keys to handlers
|
|
128
|
+
*/
|
|
129
|
+
getRoutes(): Map<string, RouteHandler> {
|
|
130
|
+
return new Map(this.routes);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get registered middlewares
|
|
135
|
+
* @returns Array of middleware functions
|
|
136
|
+
*/
|
|
137
|
+
getMiddlewares(): Middleware[] {
|
|
138
|
+
return [...this.middlewares];
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
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 {
|
|
9
|
-
export {
|
|
10
|
-
|
|
5
|
+
export { DriverPlugin } from './driver-plugin.js';
|
|
6
|
+
export { AppPlugin } from './app-plugin.js';
|
|
7
|
+
|
|
8
|
+
// Export HTTP Server Components
|
|
9
|
+
export { HttpServer } from './http-server.js';
|
|
10
|
+
export { RestServer } from './rest-server.js';
|
|
11
|
+
export { RouteManager, RouteGroupBuilder } from './route-manager.js';
|
|
12
|
+
export { MiddlewareManager } from './middleware.js';
|
|
11
13
|
|
|
12
14
|
// Export Types
|
|
13
15
|
export * from '@objectstack/core';
|
|
14
16
|
|
|
15
17
|
|
|
18
|
+
|