|
1 | | -import { ObjectStackServer } from '@objectstack/server'; |
2 | | -import { InMemoryDriver } from '@objectstack/driver-memory'; |
| 1 | +import { serve } from '@hono/node-server'; |
| 2 | +import { serveStatic } from '@hono/node-server/serve-static'; |
| 3 | +import { Hono } from 'hono'; |
| 4 | +import { cors } from 'hono/cors'; |
| 5 | +import { logger } from 'hono/logger'; |
3 | 6 |
|
4 | | -// Standard Plugins |
| 7 | +// 1. 引入核心内核 (The Kernel) |
| 8 | +import { DataEngine, ObjectStackRuntimeProtocol } from '@objectstack/runtime'; |
| 9 | +// 2. 引入驱动 (The Driver) |
| 10 | +import { InMemoryDriver } from '@objectstack/driver-memory'; |
| 11 | +// 3. 引入业务插件 (The Apps) |
5 | 12 | import CrmApp from '@objectstack/example-crm/objectstack.config'; |
6 | 13 | import TodoApp from '@objectstack/example-todo/objectstack.config'; |
7 | 14 | import BiPluginManifest from '@objectstack/plugin-bi/objectstack.config'; |
8 | 15 |
|
9 | 16 | (async () => { |
10 | | - const server = new ObjectStackServer({ |
11 | | - port: 3004, |
12 | | - static: { |
13 | | - root: './public', |
14 | | - path: 'index.html' |
15 | | - }, |
16 | | - plugins: [ |
17 | | - CrmApp, |
18 | | - TodoApp, |
19 | | - BiPluginManifest |
20 | | - ] |
| 17 | + console.log('🚀 Starting ObjectStack in Raw Kernel Mode...'); |
| 18 | + |
| 19 | + // --- A. 初始化内核 (Kernel Layer) --- |
| 20 | + |
| 21 | + // 1. 创建数据引擎,加载业务插件 |
| 22 | + const engine = new DataEngine([ |
| 23 | + CrmApp, |
| 24 | + TodoApp, |
| 25 | + BiPluginManifest |
| 26 | + ]); |
| 27 | + |
| 28 | + // 2. 注册驱动 (显式注入) |
| 29 | + engine.ql.registerDriver(new InMemoryDriver()); |
| 30 | + |
| 31 | + // 3. 创建协议处理器 (Protocol Layer) |
| 32 | + // 这是 HTTP 和 Kernel 之间的翻译官 |
| 33 | + const protocol = new ObjectStackRuntimeProtocol(engine); |
| 34 | + |
| 35 | + // 4. 启动内核 (执行数据初始化/Seed) |
| 36 | + await engine.start(); |
| 37 | + |
| 38 | + |
| 39 | + // --- B. 初始化宿主 (Host Layer / Server Shell) --- |
| 40 | + |
| 41 | + const app = new Hono(); |
| 42 | + |
| 43 | + // 中间件 |
| 44 | + app.use('*', logger()); |
| 45 | + app.use('*', cors()); |
| 46 | + |
| 47 | + // --- C. 路由映射 (Wiring) --- |
| 48 | + // 这里展示了 "Server 只是个壳":它只负责把 Request 转给 Protocol |
| 49 | + |
| 50 | + // 1. Discovery |
| 51 | + app.get('/api/v1', (c) => c.json(protocol.getDiscovery())); |
| 52 | + |
| 53 | + // 2. Meta API |
| 54 | + app.get('/api/v1/meta', (c) => c.json(protocol.getMetaTypes())); |
| 55 | + app.get('/api/v1/meta/:type', (c) => c.json(protocol.getMetaItems(c.req.param('type')))); |
| 56 | + app.get('/api/v1/meta/:type/:name', (c) => { |
| 57 | + try { |
| 58 | + return c.json(protocol.getMetaItem(c.req.param('type'), c.req.param('name'))); |
| 59 | + } catch (e: any) { |
| 60 | + return c.json({ error: e.message }, 404); |
| 61 | + } |
| 62 | + }); |
| 63 | + |
| 64 | + // 3. Data API (CRUD) |
| 65 | + app.get('/api/v1/data/:object', async (c) => { |
| 66 | + // 将 URL Query (HTTP) 转换为 Protocol Query |
| 67 | + try { |
| 68 | + const result = await protocol.findData(c.req.param('object'), c.req.query()); |
| 69 | + return c.json(result); |
| 70 | + } catch (e: any) { |
| 71 | + return c.json({ error: e.message }, 400); |
| 72 | + } |
| 73 | + }); |
| 74 | + |
| 75 | + app.get('/api/v1/data/:object/:id', async (c) => { |
| 76 | + try { |
| 77 | + const result = await protocol.getData(c.req.param('object'), c.req.param('id')); |
| 78 | + return c.json(result); |
| 79 | + } catch (e: any) { |
| 80 | + return c.json({ error: e.message }, 404); |
| 81 | + } |
| 82 | + }); |
| 83 | + |
| 84 | + app.post('/api/v1/data/:object', async (c) => { |
| 85 | + try { |
| 86 | + const body = await c.req.json(); |
| 87 | + const result = await protocol.createData(c.req.param('object'), body); |
| 88 | + return c.json(result, 201); |
| 89 | + } catch (e: any) { |
| 90 | + return c.json({ error: e.message }, 400); |
| 91 | + } |
| 92 | + }); |
| 93 | + |
| 94 | + app.patch('/api/v1/data/:object/:id', async (c) => { |
| 95 | + try { |
| 96 | + const body = await c.req.json(); |
| 97 | + const result = await protocol.updateData(c.req.param('object'), c.req.param('id'), body); |
| 98 | + return c.json(result); |
| 99 | + } catch (e: any) { |
| 100 | + return c.json({ error: e.message }, 400); |
| 101 | + } |
21 | 102 | }); |
22 | 103 |
|
23 | | - // Explicitly register the driver |
24 | | - const driver = new InMemoryDriver(); |
25 | | - server.engine.ql.registerDriver(driver); |
| 104 | + app.delete('/api/v1/data/:object/:id', async (c) => { |
| 105 | + try { |
| 106 | + const result = await protocol.deleteData(c.req.param('object'), c.req.param('id')); |
| 107 | + return c.json(result); |
| 108 | + } catch (e: any) { |
| 109 | + return c.json({ error: e.message }, 400); |
| 110 | + } |
| 111 | + }); |
| 112 | + |
| 113 | + // 4. UI Protocol |
| 114 | + app.get('/api/v1/ui/view/:object', (c) => { |
| 115 | + try { |
| 116 | + // @ts-ignore |
| 117 | + const view = protocol.getUiView(c.req.param('object'), c.req.query('type') || 'list'); |
| 118 | + return c.json(view); |
| 119 | + } catch (e: any) { |
| 120 | + return c.json({ error: e.message }, 404); |
| 121 | + } |
| 122 | + }); |
| 123 | + |
| 124 | + // --- D. 静态资源 (前端宿主) --- |
| 125 | + app.get('/', serveStatic({ root: './public', path: 'index.html' })); |
| 126 | + app.get('/index.html', serveStatic({ root: './public', path: 'index.html' })); |
| 127 | + |
| 128 | + |
| 129 | + // --- E. 启动监听 --- |
| 130 | + const port = 3004; |
| 131 | + console.log(`✅ Server is running on http://localhost:${port}`); |
| 132 | + serve({ fetch: app.fetch, port }); |
26 | 133 |
|
27 | | - await server.start(); |
28 | 134 | })(); |
0 commit comments