|
1 | | -import { Context } from 'hono'; |
2 | 1 | import { ServerPlugin } from '../plugin'; |
3 | | -import { SchemaRegistry } from '@objectstack/runtime'; |
| 2 | +import { ObjectStackRuntimeProtocol } from '@objectstack/runtime'; |
4 | 3 |
|
5 | 4 | export const CoreRestApiPlugin: ServerPlugin = { |
6 | 5 | name: 'core-rest-api', |
7 | 6 | version: '1.0.0', |
8 | 7 | install: (server) => { |
9 | 8 | const { app, engine } = server; |
| 9 | + // Instantiate Transport-Agnostic Protocol Layer |
| 10 | + const protocol = new ObjectStackRuntimeProtocol(engine); |
10 | 11 |
|
11 | 12 | // 1. Discovery |
12 | | - app.get('/api/v1', (c) => { |
13 | | - return c.json({ |
14 | | - name: 'ObjectOS Server', |
15 | | - version: '1.0.0', |
16 | | - environment: process.env.NODE_ENV || 'development', |
17 | | - routes: { |
18 | | - discovery: '/api/v1', |
19 | | - metadata: '/api/v1/meta', |
20 | | - data: '/api/v1/data', |
21 | | - auth: '/api/v1/auth', |
22 | | - ui: '/api/v1/ui' |
23 | | - }, |
24 | | - capabilities: { |
25 | | - search: true, |
26 | | - files: true |
27 | | - } |
28 | | - }); |
29 | | - }); |
30 | | - |
31 | | - // 2. Metadata: List Types |
32 | | - app.get('/api/v1/meta', (c) => { |
33 | | - const types = SchemaRegistry.getRegisteredTypes(); |
34 | | - return c.json({ |
35 | | - data: types.map(type => ({ |
36 | | - type, |
37 | | - href: `/api/v1/meta/${type}s`, // Convention: pluralize |
38 | | - count: SchemaRegistry.listItems(type).length |
39 | | - })) |
40 | | - }); |
41 | | - }); |
| 13 | + app.get('/api/v1', (c) => c.json(protocol.getDiscovery())); |
42 | 14 |
|
43 | | - // 3. Metadata: List Items by Type |
44 | | - app.get('/api/v1/meta/:type', (c) => { |
45 | | - const typePlural = c.req.param('type'); |
46 | | - |
47 | | - const typeMap: Record<string, string> = { |
48 | | - 'objects': 'object', |
49 | | - 'apps': 'app', |
50 | | - 'flows': 'flow', |
51 | | - 'reports': 'report', |
52 | | - 'plugins': 'plugin', |
53 | | - 'kinds': 'kind' |
54 | | - }; |
55 | | - const type = typeMap[typePlural] || typePlural; |
| 15 | + // 2. Meta: Types |
| 16 | + app.get('/api/v1/meta', (c) => c.json(protocol.getMetaTypes())); |
56 | 17 |
|
57 | | - const items = SchemaRegistry.listItems(type); |
58 | | - |
59 | | - const summaries = items.map((item: any) => ({ |
60 | | - id: item.id, |
61 | | - name: item.name, |
62 | | - label: item.label, |
63 | | - type: item.type, |
64 | | - icon: item.icon, |
65 | | - description: item.description, |
66 | | - ...(type === 'object' ? { path: `/api/v1/data/${item.name}` } : {}), |
67 | | - self: `/api/v1/meta/${typePlural}/${item.name || item.id}` |
68 | | - })); |
| 18 | + // 3. Meta: Items by Type |
| 19 | + app.get('/api/v1/meta/:type', (c) => c.json(protocol.getMetaItems(c.req.param('type')))); |
69 | 20 |
|
70 | | - return c.json({ data: summaries }); |
71 | | - }); |
72 | | - |
73 | | - // 4. Metadata: Get Single Item |
| 21 | + // 4. Meta: Single Item |
74 | 22 | app.get('/api/v1/meta/:type/:name', (c) => { |
75 | | - const typePlural = c.req.param('type'); |
76 | | - const name = c.req.param('name'); |
77 | | - |
78 | | - const typeMap: Record<string, string> = { |
79 | | - 'objects': 'object', |
80 | | - 'apps': 'app', |
81 | | - 'flows': 'flow', |
82 | | - 'reports': 'report', |
83 | | - 'plugins': 'plugin', |
84 | | - 'kinds': 'kind' |
85 | | - }; |
86 | | - const type = typeMap[typePlural] || typePlural; |
87 | | - |
88 | | - const item = SchemaRegistry.getItem(type, name); |
89 | | - if (!item) return c.json({ error: `Metadata not found: ${type}/${name}` }, 404); |
90 | | - |
91 | | - return c.json(item); |
92 | | - }); |
93 | | - |
94 | | - // 5. UI: View Definition |
95 | | - app.get('/api/v1/ui/view/:object', (c) => { |
96 | | - const objectName = c.req.param('object'); |
97 | | - const type = (c.req.query('type') as 'list' | 'form') || 'list'; |
98 | 23 | try { |
99 | | - const view = engine.getView(objectName, type); |
100 | | - if (!view) return c.json({ error: 'View not generated' }, 404); |
101 | | - return c.json(view); |
| 24 | + return c.json(protocol.getMetaItem(c.req.param('type'), c.req.param('name'))); |
102 | 25 | } catch (e: any) { |
103 | | - return c.json({ error: e.message }, 400); |
| 26 | + return c.json({ error: e.message }, 404); |
104 | 27 | } |
105 | 28 | }); |
106 | 29 |
|
107 | | - // 6. Data: Find |
| 30 | + // 5. Data: Find (with Query) |
108 | 31 | app.get('/api/v1/data/:object', async (c) => { |
109 | | - const objectName = c.req.param('object'); |
110 | | - const query = c.req.query(); |
111 | | - |
112 | | - try { |
113 | | - const result = await engine.find(objectName, query); |
114 | | - return c.json(result); |
115 | | - } catch (e: any) { |
116 | | - return c.json({ error: e.message }, 400); |
117 | | - } |
118 | | - }); |
119 | | - |
120 | | - // 7. Data: Query (Advanced AST) |
121 | | - app.post('/api/v1/data/:object/query', async (c) => { |
122 | | - const objectName = c.req.param('object'); |
123 | | - const body = await c.req.json(); |
124 | | - |
125 | 32 | try { |
126 | | - const result = await engine.find(objectName, body); |
| 33 | + const result = await protocol.findData(c.req.param('object'), c.req.query()); |
127 | 34 | return c.json(result); |
128 | 35 | } catch (e: any) { |
129 | 36 | return c.json({ error: e.message }, 400); |
130 | 37 | } |
131 | 38 | }); |
132 | 39 |
|
133 | | - // 8. Data: Get |
| 40 | + // 6. Data: Get Single |
134 | 41 | app.get('/api/v1/data/:object/:id', async (c) => { |
135 | | - const objectName = c.req.param('object'); |
136 | | - const id = c.req.param('id'); |
137 | 42 | try { |
138 | | - const result = await engine.get(objectName, id); |
| 43 | + const result = await protocol.getData(c.req.param('object'), c.req.param('id')); |
139 | 44 | return c.json(result); |
140 | 45 | } catch (e: any) { |
141 | 46 | return c.json({ error: e.message }, 404); |
142 | 47 | } |
143 | 48 | }); |
144 | 49 |
|
145 | | - // 9. Data: Create |
| 50 | + // 7. Data: Create |
146 | 51 | app.post('/api/v1/data/:object', async (c) => { |
147 | | - const objectName = c.req.param('object'); |
148 | | - const body = await c.req.json(); |
149 | 52 | try { |
150 | | - const result = await engine.create(objectName, body); |
| 53 | + const body = await c.req.json(); |
| 54 | + const result = await protocol.createData(c.req.param('object'), body); |
151 | 55 | return c.json(result, 201); |
152 | 56 | } catch (e: any) { |
153 | 57 | return c.json({ error: e.message }, 400); |
154 | 58 | } |
155 | 59 | }); |
156 | 60 |
|
157 | | - // 10. Data: Update |
| 61 | + // 8. Data: Update |
158 | 62 | app.patch('/api/v1/data/:object/:id', async (c) => { |
159 | | - const objectName = c.req.param('object'); |
160 | | - const id = c.req.param('id'); |
161 | | - const body = await c.req.json(); |
162 | 63 | try { |
163 | | - const result = await engine.update(objectName, id, body); |
| 64 | + const body = await c.req.json(); |
| 65 | + const result = await protocol.updateData(c.req.param('object'), c.req.param('id'), body); |
164 | 66 | return c.json(result); |
165 | 67 | } catch (e: any) { |
166 | 68 | return c.json({ error: e.message }, 400); |
167 | 69 | } |
168 | 70 | }); |
169 | 71 |
|
170 | | - // 11. Data: Delete |
| 72 | + // 9. Data: Delete |
171 | 73 | app.delete('/api/v1/data/:object/:id', async (c) => { |
172 | | - const objectName = c.req.param('object'); |
173 | | - const id = c.req.param('id'); |
174 | 74 | try { |
175 | | - const result = await engine.delete(objectName, id); |
| 75 | + const result = await protocol.deleteData(c.req.param('object'), c.req.param('id')); |
176 | 76 | return c.json(result); |
177 | 77 | } catch (e: any) { |
178 | 78 | return c.json({ error: e.message }, 400); |
179 | 79 | } |
180 | 80 | }); |
181 | 81 |
|
182 | | - // 12. Batch Operations (Placeholders) |
183 | | - app.post('/api/v1/data/:object/batch', async (c) => { |
184 | | - return c.json({ error: 'Not implemented' }, 501); |
185 | | - }); |
186 | | - app.delete('/api/v1/data/:object/batch', async (c) => { |
187 | | - return c.json({ error: 'Not implemented' }, 501); |
| 82 | + // 10. UI: View Definition |
| 83 | + app.get('/api/v1/ui/view/:object', (c) => { |
| 84 | + try { |
| 85 | + // @ts-ignore |
| 86 | + const view = protocol.getUiView(c.req.param('object'), c.req.query('type') || 'list'); |
| 87 | + return c.json(view); |
| 88 | + } catch (e: any) { |
| 89 | + return c.json({ error: e.message }, 404); |
| 90 | + } |
188 | 91 | }); |
189 | 92 | } |
190 | 93 | }; |
0 commit comments