Skip to content

Commit 5c12bd9

Browse files
committed
feat: 增加发现端点和动态元数据注册功能,优化应用程序架构
1 parent 7eac7da commit 5c12bd9

File tree

4 files changed

+60
-20
lines changed

4 files changed

+60
-20
lines changed

examples/server/src/index.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,38 @@ console.log('--- Plugins Loaded ---');
2020

2121
// 3. Define Unified Routes
2222

23+
/**
24+
* Discovery Endpoint
25+
* Allows clients to dynamically discover API routes and capabilities.
26+
*/
27+
const discoveryHandler = (c: any) => {
28+
return c.json({
29+
name: "ObjectStack Example Server",
30+
version: "0.1.0",
31+
environment: "development",
32+
routes: {
33+
data: "/api/v1/data",
34+
metadata: "/api/v1/meta",
35+
auth: "/api/v1/auth", // Not implemented yet
36+
actions: "/api/v1/actions",
37+
storage: "/api/v1/storage", // Not implemented yet
38+
},
39+
features: {
40+
graphql: false,
41+
search: true,
42+
files: false
43+
},
44+
locale: {
45+
default: "en-US",
46+
supported: ["en-US", "zh-CN"],
47+
timezone: "UTC"
48+
}
49+
});
50+
};
51+
52+
app.get('/.well-known/objectstack', discoveryHandler);
53+
app.get('/api/v1/discovery', discoveryHandler);
54+
2355
/**
2456
* Unified Metadata API: List Items by Type
2557
* GET /api/v1/meta/objects
@@ -28,14 +60,13 @@ console.log('--- Plugins Loaded ---');
2860
app.get('/api/v1/meta/:type', (c) => {
2961
const typePlural = c.req.param('type');
3062

31-
// Simple singularization mapping (can be enhanced)
63+
// Dynamic singularization:
64+
// 1. Check hardcoded map (for exceptions like 'indexes' -> 'index' if needed)
65+
// 2. Or fallback to removing trailing 's'
3266
const typeMap: Record<string, string> = {
33-
'objects': 'object',
34-
'apps': 'app',
35-
'flows': 'flow',
36-
'reports': 'report'
67+
// Add specific exceptions here if english pluralization rules fail
3768
};
38-
const type = typeMap[typePlural] || typePlural;
69+
const type = typeMap[typePlural] || (typePlural.endsWith('s') ? typePlural.slice(0, -1) : typePlural);
3970

4071
const items = SchemaRegistry.listItems(type);
4172

@@ -62,13 +93,8 @@ app.get('/api/v1/meta/:type/:name', (c) => {
6293
const typePlural = c.req.param('type');
6394
const name = c.req.param('name');
6495

65-
const typeMap: Record<string, string> = {
66-
'objects': 'object',
67-
'apps': 'app',
68-
'flows': 'flow',
69-
'reports': 'report'
70-
};
71-
const type = typeMap[typePlural] || typePlural;
96+
const typeMap: Record<string, string> = {};
97+
const type = typeMap[typePlural] || (typePlural.endsWith('s') ? typePlural.slice(0, -1) : typePlural);
7298

7399
const item = SchemaRegistry.getItem(type, name);
74100
if (!item) return c.json({ error: `Metadata not found: ${type}/${name}` }, 404);

examples/server/src/loader.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,25 @@ export function loadPlugins() {
2020
const parsedApp = AppSchema.parse(app);
2121
SchemaRegistry.registerApp(parsedApp);
2222

23-
// 1. Register Objects
24-
if (app.objects) {
25-
app.objects.forEach((obj: any) => {
26-
SchemaRegistry.registerObject(obj);
27-
});
23+
// 1. Scan and Register All Metadata
24+
// Known keys to exclude from metadata scanning
25+
const ignoredKeys = new Set(['name', 'label', 'description', 'version', 'branding', 'active', 'isDefault', 'navigation', 'menus', 'homePageId', 'requiredPermissions', 'icon', 'id']);
26+
27+
for (const [key, value] of Object.entries(app)) {
28+
if (ignoredKeys.has(key)) continue;
29+
30+
if (Array.isArray(value)) {
31+
// Singularize type name: remove trailing 's' if present
32+
const type = key.endsWith('s') ? key.slice(0, -1) : key;
33+
34+
value.forEach((item: any) => {
35+
// Ensure item has a name
36+
if (item && item.name) {
37+
SchemaRegistry.registerItem(type, item);
38+
}
39+
});
40+
console.log(`[Loader] Loaded ${value.length} ${type}s from ${app.name}`);
41+
}
2842
}
2943

3044
console.log(`[Loader] Loaded ${app.objects?.length || 0} objects from ${app.name}`);

packages/spec/json-schema/App.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@
294294
"name",
295295
"label"
296296
],
297-
"additionalProperties": false
297+
"additionalProperties": true
298298
}
299299
},
300300
"$schema": "http://json-schema.org/draft-07/schema#"

packages/spec/src/ui/app.zod.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export const AppSchema = z.object({
159159
*/
160160
objects: z.array(z.any()).optional().describe('Objects belonging to this app'),
161161
apis: z.array(z.any()).optional().describe('Custom APIs belonging to this app'),
162-
});
162+
}).passthrough();
163163

164164
export const App = Object.assign(AppSchema, {
165165
create: <T extends z.input<typeof AppSchema>>(config: T) => config,

0 commit comments

Comments
 (0)