Skip to content

Commit f214964

Browse files
committed
重构服务器架构,删除旧的 @objectstack/server 包,添加 @objectstack/dev-server 插件以支持开发环境;更新相关依赖和配置
1 parent 7c036c2 commit f214964

File tree

10 files changed

+150
-385
lines changed

10 files changed

+150
-385
lines changed

examples/server/package.json

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,18 @@
44
"private": true,
55
"scripts": {
66
"dev": "ts-node src/index.ts",
7-
"build": "tsc"
7+
"clean": "rm -rf dist node_modules"
88
},
99
"dependencies": {
10-
"@objectstack/server": "workspace:*",
11-
"@objectstack/spec": "workspace:*",
12-
"@objectstack/example-crm": "workspace:*",
13-
"@objectstack/example-todo": "workspace:*",
14-
"@objectstack/plugin-bi": "workspace:*",
1510
"@objectstack/runtime": "workspace:*",
1611
"@objectstack/driver-memory": "workspace:*",
17-
"hono": "^4.0.0",
18-
"@hono/node-server": "^1.0.0",
19-
"zod": "^3.0.0"
12+
"@objectstack/dev-server": "workspace:*",
13+
"@objectstack/example-crm": "workspace:*",
14+
"@objectstack/example-todo": "workspace:*",
15+
"@objectstack/plugin-bi": "workspace:*"
2016
},
2117
"devDependencies": {
22-
"typescript": "^5.0.0",
23-
"ts-node": "^10.0.0",
24-
"@types/node": "^20.0.0"
18+
"ts-node": "^10.9.1",
19+
"typescript": "^5.0.0"
2520
}
2621
}

examples/server/src/index.ts

Lines changed: 11 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,23 @@
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';
6-
7-
// 1. 引入核心内核 (The Kernel)
8-
import { DataEngine, ObjectStackRuntimeProtocol } from '@objectstack/runtime';
9-
// 2. 引入驱动 (The Driver)
1+
import { DataEngine } from '@objectstack/runtime';
102
import { InMemoryDriver } from '@objectstack/driver-memory';
11-
// 3. 引入业务插件 (The Apps)
3+
import { DevServerPlugin } from '@objectstack/dev-server';
4+
125
import CrmApp from '@objectstack/example-crm/objectstack.config';
136
import TodoApp from '@objectstack/example-todo/objectstack.config';
147
import BiPluginManifest from '@objectstack/plugin-bi/objectstack.config';
158

169
(async () => {
17-
console.log('🚀 Starting ObjectStack in Raw Kernel Mode...');
10+
console.log('🚀 Booting Kernel...');
1811

19-
// --- A. 初始化内核 (Kernel Layer) ---
20-
21-
// 1. 创建数据引擎,加载业务插件
22-
const engine = new DataEngine([
12+
const kernel = new DataEngine([
2313
CrmApp,
2414
TodoApp,
25-
BiPluginManifest
15+
BiPluginManifest,
16+
new InMemoryDriver(),
17+
18+
// Load the Dev Server Plugin
19+
new DevServerPlugin({ port: 3004 })
2620
]);
2721

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-
}
102-
});
103-
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 });
133-
22+
await kernel.start();
13423
})();
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
{
2-
"name": "@objectstack/server",
2+
"name": "@objectstack/dev-server",
33
"version": "0.1.0",
4-
"description": "Standard Server Runtime for ObjectStack",
4+
"description": "Lightweight Development Server for ObjectStack UI Development",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
77
"scripts": {
88
"build": "tsc"
99
},
1010
"dependencies": {
11-
"hono": "^4.0.0",
12-
"@hono/node-server": "^1.0.0",
1311
"@objectstack/runtime": "workspace:*",
1412
"@objectstack/spec": "workspace:*",
15-
"zod": "^3.0.0"
13+
"hono": "^4.0.0",
14+
"@hono/node-server": "^1.2.0"
1615
},
1716
"devDependencies": {
18-
"typescript": "^5.0.0",
19-
"@types/node": "^20.0.0"
17+
"@types/node": "^20.0.0",
18+
"typescript": "^5.0.0"
2019
}
2120
}

packages/dev-server/src/index.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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';
6+
import { DataEngine, ObjectStackRuntimeProtocol, RuntimePlugin } from '@objectstack/runtime';
7+
8+
export interface DevServerOptions {
9+
port?: number;
10+
staticRoot?: string;
11+
cors?: boolean;
12+
}
13+
14+
/**
15+
* ObjectStack Development Server Plugin
16+
*
17+
* Drop-in plugin to expose Kernel via HTTP for UI development.
18+
* NOT for production use.
19+
*/
20+
export class DevServerPlugin implements RuntimePlugin {
21+
name = 'dev-server';
22+
private port: number;
23+
private staticRoot: string;
24+
private enableCors: boolean;
25+
26+
constructor(options: DevServerOptions = {}) {
27+
this.port = options.port || 3004;
28+
this.staticRoot = options.staticRoot || './public';
29+
this.enableCors = options.cors !== false;
30+
}
31+
32+
async onStart(ctx: { engine: DataEngine }) {
33+
const app = new Hono();
34+
const protocol = new ObjectStackRuntimeProtocol(ctx.engine);
35+
36+
// 1. Dev Middlewares
37+
app.use('*', logger());
38+
if (this.enableCors) {
39+
app.use('*', cors());
40+
}
41+
42+
// 2. Wiring Protocol (Automatic)
43+
// Discovery
44+
app.get('/api/v1', (c) => c.json(protocol.getDiscovery()));
45+
46+
// Meta (Types)
47+
app.get('/api/v1/meta', (c) => c.json(protocol.getMetaTypes()));
48+
// Meta (List)
49+
app.get('/api/v1/meta/:type', (c) => c.json(protocol.getMetaItems(c.req.param('type'))));
50+
// Meta (Item)
51+
app.get('/api/v1/meta/:type/:name', (c) => {
52+
try {
53+
return c.json(protocol.getMetaItem(c.req.param('type'), c.req.param('name')))
54+
} catch(e:any) {
55+
return c.json({error: e.message}, 404);
56+
}
57+
});
58+
59+
// Data (Read)
60+
app.get('/api/v1/data/:object', async (c) => {
61+
try { return c.json(await protocol.findData(c.req.param('object'), c.req.query())); }
62+
catch(e:any) { return c.json({error:e.message}, 400); }
63+
});
64+
app.get('/api/v1/data/:object/:id', async (c) => {
65+
try { return c.json(await protocol.getData(c.req.param('object'), c.req.param('id'))); }
66+
catch(e:any) { return c.json({error:e.message}, 404); }
67+
});
68+
69+
// Data (Write)
70+
app.post('/api/v1/data/:object', async (c) => {
71+
try { return c.json(await protocol.createData(c.req.param('object'), await c.req.json()), 201); }
72+
catch(e:any) { return c.json({error:e.message}, 400); }
73+
});
74+
app.patch('/api/v1/data/:object/:id', async (c) => {
75+
try { return c.json(await protocol.updateData(c.req.param('object'), c.req.param('id'), await c.req.json())); }
76+
catch(e:any) { return c.json({error:e.message}, 400); }
77+
});
78+
app.delete('/api/v1/data/:object/:id', async (c) => {
79+
try { return c.json(await protocol.deleteData(c.req.param('object'), c.req.param('id'))); }
80+
catch(e:any) { return c.json({error:e.message}, 400); }
81+
});
82+
83+
// UI View
84+
// @ts-ignore
85+
app.get('/api/v1/ui/view/:object', (c) => {
86+
try {
87+
const viewType = (c.req.query('type') as 'list' | 'form') || 'list';
88+
return c.json(protocol.getUiView(c.req.param('object'), viewType));
89+
}
90+
catch(e:any) { return c.json({error:e.message}, 404); }
91+
});
92+
93+
// 3. Static Files (UI Hosting)
94+
if (this.staticRoot) {
95+
app.get('/', serveStatic({ root: this.staticRoot, path: 'index.html' }));
96+
app.get('/*', serveStatic({ root: this.staticRoot }));
97+
}
98+
99+
console.log('');
100+
console.log(`📦 ObjectStack Dev Server running at: http://localhost:${this.port}`);
101+
console.log(`➜ API Discovery: http://localhost:${this.port}/api/v1`);
102+
console.log(`➜ UI Playground: http://localhost:${this.port}/index.html`);
103+
console.log('');
104+
105+
serve({ fetch: app.fetch, port: this.port });
106+
}
107+
}

0 commit comments

Comments
 (0)