@objectstack/plugin-hono-server 0.9.1 → 1.0.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 +25 -0
- package/README.md +6 -486
- package/dist/hono-plugin.d.ts +2 -2
- package/dist/hono-plugin.js +123 -4
- package/package.json +5 -4
- package/src/hono-plugin.ts +127 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @objectstack/plugin-hono-server
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Major version release for ObjectStack Protocol v1.0.
|
|
8
|
+
- Stabilized Protocol Definitions
|
|
9
|
+
- Enhanced Runtime Plugin Support
|
|
10
|
+
- Fixed Type Compliance across Monorepo
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
- @objectstack/spec@1.0.0
|
|
16
|
+
- @objectstack/core@1.0.0
|
|
17
|
+
- @objectstack/types@1.0.0
|
|
18
|
+
|
|
19
|
+
## 0.9.2
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies
|
|
24
|
+
- @objectstack/spec@0.9.2
|
|
25
|
+
- @objectstack/core@0.9.2
|
|
26
|
+
- @objectstack/types@0.9.2
|
|
27
|
+
|
|
3
28
|
## 0.9.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,499 +1,19 @@
|
|
|
1
1
|
# @objectstack/plugin-hono-server
|
|
2
2
|
|
|
3
|
-
HTTP Server
|
|
4
|
-
|
|
5
|
-
## Plugin Capabilities
|
|
6
|
-
|
|
7
|
-
This plugin implements the ObjectStack plugin capability protocol:
|
|
8
|
-
- **Type**: `adapter`
|
|
9
|
-
- **Protocol**: `com.objectstack.protocol.http.v1` (full conformance)
|
|
10
|
-
- **Protocol**: `com.objectstack.protocol.api.rest.v1` (full conformance)
|
|
11
|
-
- **Provides**: `IHttpServer` interface for HTTP server operations
|
|
12
|
-
- **Requires**: `com.objectstack.engine.objectql` (optional) for protocol implementation
|
|
13
|
-
- **Extension Points**:
|
|
14
|
-
- `middleware` - Register custom HTTP middleware
|
|
15
|
-
- `route` - Register custom API routes
|
|
16
|
-
|
|
17
|
-
See [objectstack.config.ts](./objectstack.config.ts) for the complete capability manifest.
|
|
3
|
+
HTTP Server adapter for ObjectStack using Hono.
|
|
18
4
|
|
|
19
5
|
## Features
|
|
20
6
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- 📡 **REST API**: Complete ObjectStack Runtime Protocol implementation
|
|
25
|
-
- 🎯 **Auto-Discovery**: Automatic endpoint registration
|
|
26
|
-
- 🔌 **Extensible**: Easy to add custom routes and middleware
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pnpm add @objectstack/plugin-hono-server hono @hono/node-server
|
|
32
|
-
```
|
|
7
|
+
- **Fast**: Built on Hono, a high-performance web framework.
|
|
8
|
+
- **Protocol Compliant**: Implements the `IHttpServer` interface required by `@objectstack/runtime`.
|
|
9
|
+
- **Middleware**: Supports standard ObjectStack middleware.
|
|
33
10
|
|
|
34
11
|
## Usage
|
|
35
12
|
|
|
36
|
-
### Basic Setup
|
|
37
|
-
|
|
38
13
|
```typescript
|
|
14
|
+
import { ObjectKernel } from '@objectstack/core';
|
|
39
15
|
import { HonoServerPlugin } from '@objectstack/plugin-hono-server';
|
|
40
|
-
import { ObjectKernel } from '@objectstack/runtime';
|
|
41
16
|
|
|
42
17
|
const kernel = new ObjectKernel();
|
|
43
|
-
|
|
44
|
-
// Register the server plugin
|
|
45
|
-
kernel.use(new HonoServerPlugin({
|
|
46
|
-
port: 3000,
|
|
47
|
-
staticRoot: './public' // Optional: serve static files
|
|
48
|
-
}));
|
|
49
|
-
|
|
50
|
-
await kernel.bootstrap();
|
|
51
|
-
|
|
52
|
-
// Server starts automatically when kernel is ready
|
|
53
|
-
// API available at: http://localhost:3000/api/v1
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### With Custom Port
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
const plugin = new HonoServerPlugin({
|
|
60
|
-
port: process.env.PORT || 8080
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
kernel.use(plugin);
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Configuration Options
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
interface HonoPluginOptions {
|
|
70
|
-
/**
|
|
71
|
-
* HTTP server port
|
|
72
|
-
* @default 3000
|
|
73
|
-
*/
|
|
74
|
-
port?: number;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Path to static files directory (optional)
|
|
78
|
-
*/
|
|
79
|
-
staticRoot?: string;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* REST server configuration
|
|
83
|
-
* Controls automatic endpoint generation and API behavior
|
|
84
|
-
*/
|
|
85
|
-
restConfig?: RestServerConfig;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Whether to register standard ObjectStack CRUD endpoints
|
|
89
|
-
* @default true
|
|
90
|
-
*/
|
|
91
|
-
registerStandardEndpoints?: boolean;
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Whether to load endpoints from API Registry
|
|
95
|
-
* When enabled, routes are loaded dynamically from the API Registry
|
|
96
|
-
* When disabled, uses legacy static route registration
|
|
97
|
-
* @default true
|
|
98
|
-
*/
|
|
99
|
-
useApiRegistry?: boolean;
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Using API Registry (New in v0.9.0)
|
|
104
|
-
|
|
105
|
-
The plugin now integrates with the ObjectStack API Registry for centralized endpoint management:
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import { createApiRegistryPlugin } from '@objectstack/core';
|
|
109
|
-
import { HonoServerPlugin } from '@objectstack/plugin-hono-server';
|
|
110
|
-
|
|
111
|
-
const kernel = new ObjectKernel();
|
|
112
|
-
|
|
113
|
-
// 1. Register API Registry Plugin first
|
|
114
|
-
kernel.use(createApiRegistryPlugin({
|
|
115
|
-
conflictResolution: 'priority' // Handle route conflicts by priority
|
|
116
|
-
}));
|
|
117
|
-
|
|
118
|
-
// 2. Register Hono Server Plugin
|
|
119
|
-
kernel.use(new HonoServerPlugin({
|
|
120
|
-
port: 3000,
|
|
121
|
-
useApiRegistry: true,
|
|
122
|
-
registerStandardEndpoints: true,
|
|
123
|
-
restConfig: {
|
|
124
|
-
api: {
|
|
125
|
-
version: 'v1',
|
|
126
|
-
basePath: '/api',
|
|
127
|
-
enableCrud: true,
|
|
128
|
-
enableMetadata: true,
|
|
129
|
-
enableBatch: true
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}));
|
|
133
|
-
|
|
134
|
-
await kernel.bootstrap();
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
**Benefits of API Registry Integration:**
|
|
138
|
-
- 📋 Centralized endpoint registration and discovery
|
|
139
|
-
- 🔀 Priority-based route conflict resolution
|
|
140
|
-
- 🧩 Support for plugin-registered custom endpoints
|
|
141
|
-
- ⚙️ Configurable endpoint generation via `RestServerConfig`
|
|
142
|
-
- 🔍 API introspection and documentation generation
|
|
143
|
-
|
|
144
|
-
### Configuring REST Server Behavior
|
|
145
|
-
|
|
146
|
-
Use `restConfig` to control which endpoints are automatically generated:
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
new HonoServerPlugin({
|
|
150
|
-
restConfig: {
|
|
151
|
-
api: {
|
|
152
|
-
version: 'v2',
|
|
153
|
-
basePath: '/api',
|
|
154
|
-
enableCrud: true,
|
|
155
|
-
enableMetadata: true,
|
|
156
|
-
enableBatch: true,
|
|
157
|
-
enableDiscovery: true
|
|
158
|
-
},
|
|
159
|
-
crud: {
|
|
160
|
-
dataPrefix: '/data',
|
|
161
|
-
operations: {
|
|
162
|
-
create: true,
|
|
163
|
-
read: true,
|
|
164
|
-
update: true,
|
|
165
|
-
delete: true,
|
|
166
|
-
list: true
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
metadata: {
|
|
170
|
-
prefix: '/meta',
|
|
171
|
-
enableCache: true,
|
|
172
|
-
cacheTtl: 3600
|
|
173
|
-
},
|
|
174
|
-
batch: {
|
|
175
|
-
maxBatchSize: 200,
|
|
176
|
-
operations: {
|
|
177
|
-
createMany: true,
|
|
178
|
-
updateMany: true,
|
|
179
|
-
deleteMany: true,
|
|
180
|
-
upsertMany: true
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Legacy Mode (Without API Registry)
|
|
188
|
-
|
|
189
|
-
If the API Registry plugin is not registered, the server automatically falls back to legacy mode:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// No API Registry needed for simple setups
|
|
193
|
-
const kernel = new ObjectKernel();
|
|
194
|
-
|
|
195
|
-
kernel.use(new HonoServerPlugin({
|
|
196
|
-
port: 3000,
|
|
197
|
-
useApiRegistry: false // Explicitly disable API Registry
|
|
198
|
-
}));
|
|
199
|
-
|
|
200
|
-
await kernel.bootstrap();
|
|
201
|
-
// All standard routes registered statically
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
## API Endpoints
|
|
205
|
-
|
|
206
|
-
The plugin automatically exposes the following ObjectStack REST API endpoints:
|
|
207
|
-
|
|
208
|
-
### Discovery
|
|
209
|
-
|
|
210
|
-
```http
|
|
211
|
-
GET /api/v1
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Returns API discovery information including available endpoints and versions.
|
|
215
|
-
|
|
216
|
-
### Metadata Protocol
|
|
217
|
-
|
|
218
|
-
```http
|
|
219
|
-
GET /api/v1/meta
|
|
220
|
-
GET /api/v1/meta/:type
|
|
221
|
-
GET /api/v1/meta/:type/:name
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Retrieve metadata about objects, views, and other system definitions.
|
|
225
|
-
|
|
226
|
-
### Data Protocol (CRUD Operations)
|
|
227
|
-
|
|
228
|
-
```http
|
|
229
|
-
GET /api/v1/data/:object # Find records
|
|
230
|
-
GET /api/v1/data/:object/:id # Get record by ID
|
|
231
|
-
POST /api/v1/data/:object # Create record
|
|
232
|
-
PATCH /api/v1/data/:object/:id # Update record
|
|
233
|
-
DELETE /api/v1/data/:object/:id # Delete record
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
Example requests:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
# Get all users
|
|
240
|
-
curl http://localhost:3000/api/v1/data/user
|
|
241
|
-
|
|
242
|
-
# Get user by ID
|
|
243
|
-
curl http://localhost:3000/api/v1/data/user/123
|
|
244
|
-
|
|
245
|
-
# Create a user
|
|
246
|
-
curl -X POST http://localhost:3000/api/v1/data/user \
|
|
247
|
-
-H "Content-Type: application/json" \
|
|
248
|
-
-d '{"name":"John Doe","email":"john@example.com"}'
|
|
249
|
-
|
|
250
|
-
# Update a user
|
|
251
|
-
curl -X PATCH http://localhost:3000/api/v1/data/user/123 \
|
|
252
|
-
-H "Content-Type: application/json" \
|
|
253
|
-
-d '{"name":"Jane Doe"}'
|
|
254
|
-
|
|
255
|
-
# Delete a user
|
|
256
|
-
curl -X DELETE http://localhost:3000/api/v1/data/user/123
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### UI Protocol
|
|
260
|
-
|
|
261
|
-
```http
|
|
262
|
-
GET /api/v1/ui/view/:object?type=list|form
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
Retrieve UI view configurations for objects.
|
|
266
|
-
|
|
267
|
-
## Advanced Usage
|
|
268
|
-
|
|
269
|
-
### Accessing the HTTP Server Instance
|
|
270
|
-
|
|
271
|
-
The server instance is registered as a service and can be accessed by other plugins:
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
export class MyPlugin implements Plugin {
|
|
275
|
-
name = 'my-custom-plugin';
|
|
276
|
-
|
|
277
|
-
async start(ctx: PluginContext) {
|
|
278
|
-
const httpServer = ctx.getService<IHttpServer>('http-server');
|
|
279
|
-
|
|
280
|
-
// Add custom routes
|
|
281
|
-
httpServer.get('/api/custom', (req, res) => {
|
|
282
|
-
res.json({ message: 'Custom endpoint' });
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
18
|
+
kernel.use(new HonoServerPlugin({ port: 3000 }));
|
|
286
19
|
```
|
|
287
|
-
|
|
288
|
-
### Registering Custom Endpoints via API Registry
|
|
289
|
-
|
|
290
|
-
Plugins can register their own endpoints through the API Registry:
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
export class MyApiPlugin implements Plugin {
|
|
294
|
-
name = 'my-api-plugin';
|
|
295
|
-
version = '1.0.0';
|
|
296
|
-
|
|
297
|
-
async init(ctx: PluginContext) {
|
|
298
|
-
const apiRegistry = ctx.getService<ApiRegistry>('api-registry');
|
|
299
|
-
|
|
300
|
-
apiRegistry.registerApi({
|
|
301
|
-
id: 'my_custom_api',
|
|
302
|
-
name: 'My Custom API',
|
|
303
|
-
type: 'rest',
|
|
304
|
-
version: 'v1',
|
|
305
|
-
basePath: '/api/v1/custom',
|
|
306
|
-
endpoints: [
|
|
307
|
-
{
|
|
308
|
-
id: 'get_custom_data',
|
|
309
|
-
method: 'GET',
|
|
310
|
-
path: '/api/v1/custom/data',
|
|
311
|
-
summary: 'Get custom data',
|
|
312
|
-
priority: 500, // Lower than core endpoints (950)
|
|
313
|
-
responses: [{
|
|
314
|
-
statusCode: 200,
|
|
315
|
-
description: 'Custom data retrieved'
|
|
316
|
-
}]
|
|
317
|
-
}
|
|
318
|
-
],
|
|
319
|
-
metadata: {
|
|
320
|
-
pluginSource: 'my-api-plugin',
|
|
321
|
-
status: 'active',
|
|
322
|
-
tags: ['custom']
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
ctx.logger.info('Custom API endpoints registered');
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async start(ctx: PluginContext) {
|
|
330
|
-
// Bind the actual handler implementation
|
|
331
|
-
const httpServer = ctx.getService<IHttpServer>('http-server');
|
|
332
|
-
|
|
333
|
-
httpServer.get('/api/v1/custom/data', async (req, res) => {
|
|
334
|
-
res.json({ data: 'my custom data' });
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
**Note:** The Hono Server Plugin loads routes from the API Registry sorted by priority (highest first), ensuring core endpoints take precedence over plugin endpoints.
|
|
341
|
-
|
|
342
|
-
### Extending with Middleware
|
|
343
|
-
|
|
344
|
-
The plugin provides extension points for adding custom middleware:
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
// In another plugin's manifest
|
|
348
|
-
capabilities: {
|
|
349
|
-
extensions: [
|
|
350
|
-
{
|
|
351
|
-
targetPluginId: 'com.objectstack.server.hono',
|
|
352
|
-
extensionPointId: 'com.objectstack.server.hono.extension.middleware',
|
|
353
|
-
implementation: './middleware/auth.ts',
|
|
354
|
-
priority: 10
|
|
355
|
-
}
|
|
356
|
-
]
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
### Custom Route Registration
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
// In another plugin's manifest
|
|
364
|
-
capabilities: {
|
|
365
|
-
extensions: [
|
|
366
|
-
{
|
|
367
|
-
targetPluginId: 'com.objectstack.server.hono',
|
|
368
|
-
extensionPointId: 'com.objectstack.server.hono.extension.route',
|
|
369
|
-
implementation: './routes/webhooks.ts',
|
|
370
|
-
priority: 50
|
|
371
|
-
}
|
|
372
|
-
]
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## Architecture
|
|
377
|
-
|
|
378
|
-
The Hono Server Plugin follows a clean architecture:
|
|
379
|
-
|
|
380
|
-
```
|
|
381
|
-
┌─────────────────────────────────┐
|
|
382
|
-
│ HonoServerPlugin │
|
|
383
|
-
│ (Plugin Lifecycle) │
|
|
384
|
-
└────────────┬────────────────────┘
|
|
385
|
-
│
|
|
386
|
-
├─ init() → Register HTTP server service
|
|
387
|
-
├─ start() → Bind routes, start server
|
|
388
|
-
└─ destroy() → Stop server
|
|
389
|
-
│
|
|
390
|
-
▼
|
|
391
|
-
┌─────────────────────┐
|
|
392
|
-
│ HonoHttpServer │
|
|
393
|
-
│ (Adapter) │
|
|
394
|
-
└──────┬──────────────┘
|
|
395
|
-
│
|
|
396
|
-
▼
|
|
397
|
-
┌─────────────────────┐
|
|
398
|
-
│ Hono Framework │
|
|
399
|
-
│ (Core Library) │
|
|
400
|
-
└─────────────────────┘
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
## Plugin Lifecycle
|
|
404
|
-
|
|
405
|
-
1. **Init Phase**:
|
|
406
|
-
- Creates HonoHttpServer instance
|
|
407
|
-
- Registers as `http-server` service
|
|
408
|
-
|
|
409
|
-
2. **Start Phase**:
|
|
410
|
-
- Retrieves protocol implementation service
|
|
411
|
-
- Registers all ObjectStack API routes
|
|
412
|
-
- Sets up lifecycle hooks
|
|
413
|
-
|
|
414
|
-
3. **Ready Hook** (`kernel:ready`):
|
|
415
|
-
- Starts HTTP server on configured port
|
|
416
|
-
- Logs server URL
|
|
417
|
-
|
|
418
|
-
4. **Destroy Phase**:
|
|
419
|
-
- Gracefully closes server
|
|
420
|
-
- Cleans up resources
|
|
421
|
-
|
|
422
|
-
## Error Handling
|
|
423
|
-
|
|
424
|
-
The plugin includes comprehensive error handling:
|
|
425
|
-
|
|
426
|
-
```typescript
|
|
427
|
-
// 404 Not Found
|
|
428
|
-
GET /api/v1/data/user/999
|
|
429
|
-
→ { "error": "Record not found" }
|
|
430
|
-
|
|
431
|
-
// 400 Bad Request
|
|
432
|
-
POST /api/v1/data/user (invalid data)
|
|
433
|
-
→ { "error": "Validation failed: email is required" }
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
## Production Deployment
|
|
437
|
-
|
|
438
|
-
### Environment Variables
|
|
439
|
-
|
|
440
|
-
```bash
|
|
441
|
-
PORT=8080
|
|
442
|
-
NODE_ENV=production
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### Docker Example
|
|
446
|
-
|
|
447
|
-
```dockerfile
|
|
448
|
-
FROM node:20-alpine
|
|
449
|
-
WORKDIR /app
|
|
450
|
-
COPY package.json pnpm-lock.yaml ./
|
|
451
|
-
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
|
452
|
-
COPY . .
|
|
453
|
-
RUN pnpm build
|
|
454
|
-
EXPOSE 8080
|
|
455
|
-
CMD ["node", "dist/index.js"]
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
### Serverless Deployment
|
|
459
|
-
|
|
460
|
-
Hono works seamlessly with serverless platforms:
|
|
461
|
-
|
|
462
|
-
```typescript
|
|
463
|
-
// Cloudflare Workers, Vercel Edge, etc.
|
|
464
|
-
export default {
|
|
465
|
-
async fetch(request: Request) {
|
|
466
|
-
const app = createHonoApp();
|
|
467
|
-
return app.fetch(request);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
## Performance
|
|
473
|
-
|
|
474
|
-
Hono is designed for performance:
|
|
475
|
-
- ⚡ One of the fastest web frameworks for Node.js
|
|
476
|
-
- 🪶 Minimal overhead and memory footprint
|
|
477
|
-
- 🚀 Optimized routing with RegExpRouter
|
|
478
|
-
- 📦 Small bundle size (~12KB)
|
|
479
|
-
|
|
480
|
-
## Comparison with Other Adapters
|
|
481
|
-
|
|
482
|
-
| Feature | Hono | Express | Fastify |
|
|
483
|
-
|---------|------|---------|---------|
|
|
484
|
-
| Universal Runtime | ✅ | ❌ | ❌ |
|
|
485
|
-
| Edge Support | ✅ | ❌ | ❌ |
|
|
486
|
-
| TypeScript | ✅ | Partial | ✅ |
|
|
487
|
-
| Performance | Excellent | Good | Excellent |
|
|
488
|
-
| Bundle Size | 12KB | 208KB | 28KB |
|
|
489
|
-
|
|
490
|
-
## License
|
|
491
|
-
|
|
492
|
-
Apache-2.0
|
|
493
|
-
|
|
494
|
-
## Related Packages
|
|
495
|
-
|
|
496
|
-
- [@objectstack/runtime](../../runtime) - ObjectStack Runtime
|
|
497
|
-
- [@objectstack/spec](../../spec) - ObjectStack Specifications
|
|
498
|
-
- [hono](https://hono.dev/) - Hono Web Framework
|
|
499
|
-
- [@hono/node-server](https://github.com/honojs/node-server) - Node.js adapter for Hono
|
package/dist/hono-plugin.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare class HonoServerPlugin implements Plugin {
|
|
|
37
37
|
/**
|
|
38
38
|
* Init phase - Setup HTTP server and register as service
|
|
39
39
|
*/
|
|
40
|
-
init(ctx: PluginContext)
|
|
40
|
+
init: (ctx: PluginContext) => Promise<void>;
|
|
41
41
|
/**
|
|
42
42
|
* Helper to create cache request object from HTTP headers
|
|
43
43
|
*/
|
|
@@ -45,7 +45,7 @@ export declare class HonoServerPlugin implements Plugin {
|
|
|
45
45
|
/**
|
|
46
46
|
* Start phase - Bind routes and start listening
|
|
47
47
|
*/
|
|
48
|
-
start(ctx: PluginContext)
|
|
48
|
+
start: (ctx: PluginContext) => Promise<void>;
|
|
49
49
|
/**
|
|
50
50
|
* Register standard ObjectStack API endpoints to the API Registry
|
|
51
51
|
*/
|
package/dist/hono-plugin.js
CHANGED
|
@@ -29,7 +29,7 @@ class HonoServerPlugin {
|
|
|
29
29
|
/**
|
|
30
30
|
* Init phase - Setup HTTP server and register as service
|
|
31
31
|
*/
|
|
32
|
-
async
|
|
32
|
+
init = async (ctx) => {
|
|
33
33
|
ctx.logger.debug('Initializing Hono server plugin', {
|
|
34
34
|
port: this.options.port,
|
|
35
35
|
staticRoot: this.options.staticRoot
|
|
@@ -37,7 +37,7 @@ class HonoServerPlugin {
|
|
|
37
37
|
// Register HTTP server service as IHttpServer
|
|
38
38
|
ctx.registerService('http-server', this.server);
|
|
39
39
|
ctx.logger.info('HTTP server service registered', { serviceName: 'http-server' });
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
41
|
/**
|
|
42
42
|
* Helper to create cache request object from HTTP headers
|
|
43
43
|
*/
|
|
@@ -50,7 +50,7 @@ class HonoServerPlugin {
|
|
|
50
50
|
/**
|
|
51
51
|
* Start phase - Bind routes and start listening
|
|
52
52
|
*/
|
|
53
|
-
async
|
|
53
|
+
start = async (ctx) => {
|
|
54
54
|
ctx.logger.debug('Starting Hono server plugin');
|
|
55
55
|
// Get protocol implementation instance
|
|
56
56
|
let protocol = null;
|
|
@@ -93,7 +93,7 @@ class HonoServerPlugin {
|
|
|
93
93
|
url: `http://localhost:${port}`
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
|
-
}
|
|
96
|
+
};
|
|
97
97
|
/**
|
|
98
98
|
* Register standard ObjectStack API endpoints to the API Registry
|
|
99
99
|
*/
|
|
@@ -450,6 +450,60 @@ class HonoServerPlugin {
|
|
|
450
450
|
],
|
|
451
451
|
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
452
452
|
});
|
|
453
|
+
// Analytics Endpoints
|
|
454
|
+
endpoints.push({
|
|
455
|
+
id: 'analytics_query',
|
|
456
|
+
method: 'POST',
|
|
457
|
+
path: `${apiPath}/analytics/query`,
|
|
458
|
+
summary: 'Analytics Query',
|
|
459
|
+
description: 'Execute analytics query',
|
|
460
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
461
|
+
}, {
|
|
462
|
+
id: 'get_analytics_meta',
|
|
463
|
+
method: 'GET',
|
|
464
|
+
path: `${apiPath}/analytics/meta`,
|
|
465
|
+
summary: 'Analytics Metadata',
|
|
466
|
+
description: 'Get analytics cubes definitions',
|
|
467
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
468
|
+
});
|
|
469
|
+
// Automation Endpoints
|
|
470
|
+
endpoints.push({
|
|
471
|
+
id: 'automation_trigger',
|
|
472
|
+
method: 'POST',
|
|
473
|
+
path: `${apiPath}/automation/trigger/:trigger`,
|
|
474
|
+
summary: 'Trigger Automation',
|
|
475
|
+
description: 'Trigger a named automation',
|
|
476
|
+
parameters: [{
|
|
477
|
+
name: 'trigger',
|
|
478
|
+
in: 'path',
|
|
479
|
+
required: true,
|
|
480
|
+
schema: { type: 'string' }
|
|
481
|
+
}],
|
|
482
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
483
|
+
});
|
|
484
|
+
// Hub Endpoints
|
|
485
|
+
endpoints.push({
|
|
486
|
+
id: 'hub_list_spaces',
|
|
487
|
+
method: 'GET',
|
|
488
|
+
path: `${apiPath}/hub/spaces`,
|
|
489
|
+
summary: 'List Spaces',
|
|
490
|
+
description: 'List all Hub spaces',
|
|
491
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
492
|
+
}, {
|
|
493
|
+
id: 'hub_create_space',
|
|
494
|
+
method: 'POST',
|
|
495
|
+
path: `${apiPath}/hub/spaces`,
|
|
496
|
+
summary: 'Create Space',
|
|
497
|
+
description: 'Create a new Hub space',
|
|
498
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
499
|
+
}, {
|
|
500
|
+
id: 'hub_install_plugin',
|
|
501
|
+
method: 'POST',
|
|
502
|
+
path: `${apiPath}/hub/plugins/install`,
|
|
503
|
+
summary: 'Install Plugin',
|
|
504
|
+
description: 'Install a plugin from marketplace',
|
|
505
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
506
|
+
});
|
|
453
507
|
// Register the API in the registry
|
|
454
508
|
const apiEntry = {
|
|
455
509
|
id: 'objectstack_core_api',
|
|
@@ -733,6 +787,71 @@ class HonoServerPlugin {
|
|
|
733
787
|
ctx.logger.warn('UI view not found', { object: req.params.object });
|
|
734
788
|
res.status(404).json({ error: e.message });
|
|
735
789
|
}
|
|
790
|
+
},
|
|
791
|
+
// Analytics
|
|
792
|
+
'analytics_query': async (req, res) => {
|
|
793
|
+
ctx.logger.info('Analytics query request');
|
|
794
|
+
try {
|
|
795
|
+
const result = await p.analyticsQuery(req.body);
|
|
796
|
+
res.json(result);
|
|
797
|
+
}
|
|
798
|
+
catch (e) {
|
|
799
|
+
ctx.logger.error('Analytics query failed', e);
|
|
800
|
+
res.status(400).json({ error: e.message });
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
'get_analytics_meta': async (req, res) => {
|
|
804
|
+
ctx.logger.info('Analytics meta request');
|
|
805
|
+
try {
|
|
806
|
+
const result = await p.getAnalyticsMeta({});
|
|
807
|
+
res.json(result);
|
|
808
|
+
}
|
|
809
|
+
catch (e) {
|
|
810
|
+
ctx.logger.error('Analytics meta failed', e);
|
|
811
|
+
res.status(500).json({ error: e.message });
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
// Automation
|
|
815
|
+
'automation_trigger': async (req, res) => {
|
|
816
|
+
const trigger = req.params.trigger;
|
|
817
|
+
ctx.logger.info('Automation trigger request', { trigger });
|
|
818
|
+
try {
|
|
819
|
+
const result = await p.triggerAutomation({ trigger, payload: req.body });
|
|
820
|
+
res.json(result);
|
|
821
|
+
}
|
|
822
|
+
catch (e) {
|
|
823
|
+
ctx.logger.error('Automation trigger failed', e, { trigger });
|
|
824
|
+
res.status(500).json({ error: e.message });
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
// Hub
|
|
828
|
+
'hub_list_spaces': async (req, res) => {
|
|
829
|
+
try {
|
|
830
|
+
const result = await p.listSpaces({ ...req.query });
|
|
831
|
+
res.json(result);
|
|
832
|
+
}
|
|
833
|
+
catch (e) {
|
|
834
|
+
res.status(500).json({ error: e.message });
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
'hub_create_space': async (req, res) => {
|
|
838
|
+
try {
|
|
839
|
+
const result = await p.createSpace(req.body);
|
|
840
|
+
res.status(201).json(result);
|
|
841
|
+
}
|
|
842
|
+
catch (e) {
|
|
843
|
+
res.status(500).json({ error: e.message });
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
'hub_install_plugin': async (req, res) => {
|
|
847
|
+
const spaceId = req.params.space_id;
|
|
848
|
+
try {
|
|
849
|
+
const result = await p.installPlugin({ spaceId, ...req.body });
|
|
850
|
+
res.json(result);
|
|
851
|
+
}
|
|
852
|
+
catch (e) {
|
|
853
|
+
res.status(500).json({ error: e.message });
|
|
854
|
+
}
|
|
736
855
|
}
|
|
737
856
|
};
|
|
738
857
|
return handlerMap[endpointId];
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/plugin-hono-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
4
5
|
"description": "Standard Hono Server Adapter for ObjectStack Runtime",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
8
|
"dependencies": {
|
|
8
9
|
"@hono/node-server": "^1.2.0",
|
|
9
10
|
"hono": "^4.0.0",
|
|
10
|
-
"@objectstack/
|
|
11
|
-
"@objectstack/
|
|
12
|
-
"@objectstack/
|
|
11
|
+
"@objectstack/spec": "1.0.0",
|
|
12
|
+
"@objectstack/types": "1.0.0",
|
|
13
|
+
"@objectstack/core": "1.0.0"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
15
16
|
"@types/node": "^25.1.0",
|
package/src/hono-plugin.ts
CHANGED
|
@@ -58,7 +58,7 @@ export class HonoServerPlugin implements Plugin {
|
|
|
58
58
|
/**
|
|
59
59
|
* Init phase - Setup HTTP server and register as service
|
|
60
60
|
*/
|
|
61
|
-
async
|
|
61
|
+
init = async (ctx: PluginContext) => {
|
|
62
62
|
ctx.logger.debug('Initializing Hono server plugin', {
|
|
63
63
|
port: this.options.port,
|
|
64
64
|
staticRoot: this.options.staticRoot
|
|
@@ -82,7 +82,7 @@ export class HonoServerPlugin implements Plugin {
|
|
|
82
82
|
/**
|
|
83
83
|
* Start phase - Bind routes and start listening
|
|
84
84
|
*/
|
|
85
|
-
async
|
|
85
|
+
start = async (ctx: PluginContext) => {
|
|
86
86
|
ctx.logger.debug('Starting Hono server plugin');
|
|
87
87
|
|
|
88
88
|
// Get protocol implementation instance
|
|
@@ -507,6 +507,72 @@ export class HonoServerPlugin implements Plugin {
|
|
|
507
507
|
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
508
508
|
});
|
|
509
509
|
|
|
510
|
+
// Analytics Endpoints
|
|
511
|
+
endpoints.push(
|
|
512
|
+
{
|
|
513
|
+
id: 'analytics_query',
|
|
514
|
+
method: 'POST',
|
|
515
|
+
path: `${apiPath}/analytics/query`,
|
|
516
|
+
summary: 'Analytics Query',
|
|
517
|
+
description: 'Execute analytics query',
|
|
518
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
id: 'get_analytics_meta',
|
|
522
|
+
method: 'GET',
|
|
523
|
+
path: `${apiPath}/analytics/meta`,
|
|
524
|
+
summary: 'Analytics Metadata',
|
|
525
|
+
description: 'Get analytics cubes definitions',
|
|
526
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
// Automation Endpoints
|
|
531
|
+
endpoints.push(
|
|
532
|
+
{
|
|
533
|
+
id: 'automation_trigger',
|
|
534
|
+
method: 'POST',
|
|
535
|
+
path: `${apiPath}/automation/trigger/:trigger`,
|
|
536
|
+
summary: 'Trigger Automation',
|
|
537
|
+
description: 'Trigger a named automation',
|
|
538
|
+
parameters: [{
|
|
539
|
+
name: 'trigger',
|
|
540
|
+
in: 'path',
|
|
541
|
+
required: true,
|
|
542
|
+
schema: { type: 'string' }
|
|
543
|
+
}],
|
|
544
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
// Hub Endpoints
|
|
549
|
+
endpoints.push(
|
|
550
|
+
{
|
|
551
|
+
id: 'hub_list_spaces',
|
|
552
|
+
method: 'GET',
|
|
553
|
+
path: `${apiPath}/hub/spaces`,
|
|
554
|
+
summary: 'List Spaces',
|
|
555
|
+
description: 'List all Hub spaces',
|
|
556
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
id: 'hub_create_space',
|
|
560
|
+
method: 'POST',
|
|
561
|
+
path: `${apiPath}/hub/spaces`,
|
|
562
|
+
summary: 'Create Space',
|
|
563
|
+
description: 'Create a new Hub space',
|
|
564
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
id: 'hub_install_plugin',
|
|
568
|
+
method: 'POST',
|
|
569
|
+
path: `${apiPath}/hub/plugins/install`,
|
|
570
|
+
summary: 'Install Plugin',
|
|
571
|
+
description: 'Install a plugin from marketplace',
|
|
572
|
+
priority: HonoServerPlugin.DISCOVERY_ENDPOINT_PRIORITY
|
|
573
|
+
}
|
|
574
|
+
);
|
|
575
|
+
|
|
510
576
|
// Register the API in the registry
|
|
511
577
|
const apiEntry: ApiRegistryEntryInput = {
|
|
512
578
|
id: 'objectstack_core_api',
|
|
@@ -798,6 +864,65 @@ export class HonoServerPlugin implements Plugin {
|
|
|
798
864
|
ctx.logger.warn('UI view not found', { object: req.params.object });
|
|
799
865
|
res.status(404).json({ error: e.message });
|
|
800
866
|
}
|
|
867
|
+
},
|
|
868
|
+
// Analytics
|
|
869
|
+
'analytics_query': async (req: any, res: any) => {
|
|
870
|
+
ctx.logger.info('Analytics query request');
|
|
871
|
+
try {
|
|
872
|
+
const result = await p.analyticsQuery(req.body);
|
|
873
|
+
res.json(result);
|
|
874
|
+
} catch (e: any) {
|
|
875
|
+
ctx.logger.error('Analytics query failed', e);
|
|
876
|
+
res.status(400).json({ error: e.message });
|
|
877
|
+
}
|
|
878
|
+
},
|
|
879
|
+
'get_analytics_meta': async (req: any, res: any) => {
|
|
880
|
+
ctx.logger.info('Analytics meta request');
|
|
881
|
+
try {
|
|
882
|
+
const result = await p.getAnalyticsMeta({});
|
|
883
|
+
res.json(result);
|
|
884
|
+
} catch (e: any) {
|
|
885
|
+
ctx.logger.error('Analytics meta failed', e);
|
|
886
|
+
res.status(500).json({ error: e.message });
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
// Automation
|
|
890
|
+
'automation_trigger': async (req: any, res: any) => {
|
|
891
|
+
const trigger = req.params.trigger;
|
|
892
|
+
ctx.logger.info('Automation trigger request', { trigger });
|
|
893
|
+
try {
|
|
894
|
+
const result = await p.triggerAutomation({ trigger, payload: req.body });
|
|
895
|
+
res.json(result);
|
|
896
|
+
} catch (e: any) {
|
|
897
|
+
ctx.logger.error('Automation trigger failed', e, { trigger });
|
|
898
|
+
res.status(500).json({ error: e.message });
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
// Hub
|
|
902
|
+
'hub_list_spaces': async (req: any, res: any) => {
|
|
903
|
+
try {
|
|
904
|
+
const result = await p.listSpaces({ ...req.query });
|
|
905
|
+
res.json(result);
|
|
906
|
+
} catch (e: any) {
|
|
907
|
+
res.status(500).json({ error: e.message });
|
|
908
|
+
}
|
|
909
|
+
},
|
|
910
|
+
'hub_create_space': async (req: any, res: any) => {
|
|
911
|
+
try {
|
|
912
|
+
const result = await p.createSpace(req.body);
|
|
913
|
+
res.status(201).json(result);
|
|
914
|
+
} catch (e: any) {
|
|
915
|
+
res.status(500).json({ error: e.message });
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
'hub_install_plugin': async (req: any, res: any) => {
|
|
919
|
+
const spaceId = req.params.space_id;
|
|
920
|
+
try {
|
|
921
|
+
const result = await p.installPlugin({ spaceId, ...req.body });
|
|
922
|
+
res.json(result);
|
|
923
|
+
} catch (e: any) {
|
|
924
|
+
res.status(500).json({ error: e.message });
|
|
925
|
+
}
|
|
801
926
|
}
|
|
802
927
|
};
|
|
803
928
|
|