@objectstack/runtime 1.0.4 → 1.0.5

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.
@@ -1,251 +0,0 @@
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/dist/runtime.d.ts DELETED
@@ -1,45 +0,0 @@
1
- import { ObjectKernel, Plugin, IHttpServer, ObjectKernelConfig } from '@objectstack/core';
2
- import { ApiRegistryConfig } from './api-registry-plugin.js';
3
- export interface RuntimeConfig {
4
- /**
5
- * Optional existing server instance (e.g. Hono, Express app)
6
- * If provided, Runtime will use it as the 'http.server' service.
7
- * If not provided, Runtime expects a server plugin (like HonoServerPlugin) to be registered manually.
8
- */
9
- server?: IHttpServer;
10
- /**
11
- * API Registry Configuration
12
- */
13
- api?: ApiRegistryConfig;
14
- /**
15
- * Kernel Configuration
16
- */
17
- kernel?: ObjectKernelConfig;
18
- }
19
- /**
20
- * ObjectStack Runtime
21
- *
22
- * High-level entry point for bootstrapping an ObjectStack application.
23
- * Wraps ObjectKernel and provides standard orchestration for:
24
- * - HTTP Server binding
25
- * - API Registry (REST Routes)
26
- * - Plugin Management
27
- */
28
- export declare class Runtime {
29
- readonly kernel: ObjectKernel;
30
- constructor(config?: RuntimeConfig);
31
- /**
32
- * Register a plugin
33
- */
34
- use(plugin: Plugin): this;
35
- /**
36
- * Start the runtime
37
- * 1. Initializes all plugins (init phase)
38
- * 2. Starts all plugins (start phase)
39
- */
40
- start(): Promise<this>;
41
- /**
42
- * Get the kernel instance
43
- */
44
- getKernel(): ObjectKernel;
45
- }
package/dist/runtime.js DELETED
@@ -1,50 +0,0 @@
1
- import { ObjectKernel } from '@objectstack/core';
2
- import { createApiRegistryPlugin } from './api-registry-plugin.js';
3
- /**
4
- * ObjectStack Runtime
5
- *
6
- * High-level entry point for bootstrapping an ObjectStack application.
7
- * Wraps ObjectKernel and provides standard orchestration for:
8
- * - HTTP Server binding
9
- * - API Registry (REST Routes)
10
- * - Plugin Management
11
- */
12
- export class Runtime {
13
- constructor(config = {}) {
14
- this.kernel = new ObjectKernel(config.kernel);
15
- // If external server provided, register it immediately
16
- if (config.server) {
17
- // If the provided server is not already an HttpServer wrapper, wrap it?
18
- // Since IHttpServer is the interface, we assume it complies.
19
- // But HttpServer class in runtime is an adapter.
20
- // If user passes raw Hono, it won't work unless they wrapped it.
21
- // We'll assume they pass a compliant IHttpServer.
22
- this.kernel.registerService('http.server', config.server);
23
- }
24
- // Register API Registry by default
25
- // This plugin is passive (wait for services) so it's safe to add early.
26
- this.kernel.use(createApiRegistryPlugin(config.api));
27
- }
28
- /**
29
- * Register a plugin
30
- */
31
- use(plugin) {
32
- this.kernel.use(plugin);
33
- return this;
34
- }
35
- /**
36
- * Start the runtime
37
- * 1. Initializes all plugins (init phase)
38
- * 2. Starts all plugins (start phase)
39
- */
40
- async start() {
41
- await this.kernel.bootstrap();
42
- return this;
43
- }
44
- /**
45
- * Get the kernel instance
46
- */
47
- getKernel() {
48
- return this.kernel;
49
- }
50
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,57 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { Runtime } from './runtime';
3
- // Mock ObjectKernel to isolate Runtime logic
4
- vi.mock('@objectstack/core', async () => {
5
- const actual = await vi.importActual('@objectstack/core');
6
- return {
7
- ...actual,
8
- ObjectKernel: class {
9
- constructor() {
10
- this.use = vi.fn();
11
- this.registerService = vi.fn();
12
- this.bootstrap = vi.fn().mockResolvedValue(undefined);
13
- this.getServices = vi.fn().mockReturnValue(new Map());
14
- }
15
- }
16
- };
17
- });
18
- describe('Runtime', () => {
19
- it('should initialize successfully', () => {
20
- const runtime = new Runtime();
21
- expect(runtime).toBeDefined();
22
- // Should create a kernel
23
- expect(runtime.getKernel()).toBeDefined();
24
- });
25
- it('should register api registry plugin by default', () => {
26
- const runtime = new Runtime();
27
- const kernel = runtime.getKernel();
28
- // Check if use was called (at least once for api registry)
29
- expect(kernel.use).toHaveBeenCalled();
30
- });
31
- it('should register external http server if provided', () => {
32
- const mockServer = {
33
- listen: vi.fn(),
34
- close: vi.fn(),
35
- get: vi.fn(),
36
- post: vi.fn(),
37
- put: vi.fn(),
38
- delete: vi.fn(),
39
- patch: vi.fn(),
40
- use: vi.fn(),
41
- };
42
- const runtime = new Runtime({ server: mockServer });
43
- const kernel = runtime.getKernel();
44
- expect(kernel.registerService).toHaveBeenCalledWith('http.server', mockServer);
45
- });
46
- it('should delegate use() to kernel', () => {
47
- const runtime = new Runtime();
48
- const mockPlugin = { name: 'test', init: vi.fn() };
49
- runtime.use(mockPlugin);
50
- expect(runtime.getKernel().use).toHaveBeenCalledWith(mockPlugin);
51
- });
52
- it('should delegate start() to kernel.bootstrap()', async () => {
53
- const runtime = new Runtime();
54
- await runtime.start();
55
- expect(runtime.getKernel().bootstrap).toHaveBeenCalled();
56
- });
57
- });