@objectstack/runtime 0.4.1 → 0.6.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 +28 -0
- package/README.md +277 -0
- package/dist/app-manifest-plugin.d.ts +19 -0
- package/dist/app-manifest-plugin.js +33 -0
- package/dist/driver-plugin.d.ts +23 -0
- package/dist/driver-plugin.js +31 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +9 -4
- package/dist/test-interfaces.d.ts +7 -0
- package/dist/test-interfaces.js +138 -0
- package/package.json +6 -4
- package/src/app-manifest-plugin.ts +48 -0
- package/src/driver-plugin.ts +40 -0
- package/src/index.ts +12 -4
- package/src/test-interfaces.ts +170 -0
- package/dist/kernel.d.ts +0 -142
- package/dist/kernel.js +0 -157
- package/dist/protocol.d.ts +0 -68
- package/dist/protocol.js +0 -108
- package/dist/types.d.ts +0 -9
- package/dist/types.js +0 -1
- package/src/kernel.ts +0 -182
- package/src/protocol.ts +0 -129
- package/src/types.ts +0 -11
package/dist/protocol.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { SchemaRegistry } from '@objectstack/objectql';
|
|
2
|
-
export class ObjectStackRuntimeProtocol {
|
|
3
|
-
constructor(engine) {
|
|
4
|
-
this.engine = engine;
|
|
5
|
-
}
|
|
6
|
-
// 1. Discovery
|
|
7
|
-
getDiscovery() {
|
|
8
|
-
return {
|
|
9
|
-
name: 'ObjectOS Server',
|
|
10
|
-
version: '1.0.0',
|
|
11
|
-
environment: process.env.NODE_ENV || 'development',
|
|
12
|
-
routes: {
|
|
13
|
-
discovery: '/api/v1',
|
|
14
|
-
metadata: '/api/v1/meta',
|
|
15
|
-
data: '/api/v1/data',
|
|
16
|
-
auth: '/api/v1/auth',
|
|
17
|
-
ui: '/api/v1/ui'
|
|
18
|
-
},
|
|
19
|
-
capabilities: {
|
|
20
|
-
search: true,
|
|
21
|
-
files: true
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
// 2. Metadata: List Types
|
|
26
|
-
getMetaTypes() {
|
|
27
|
-
const types = SchemaRegistry.getRegisteredTypes();
|
|
28
|
-
return {
|
|
29
|
-
data: types.map(type => ({
|
|
30
|
-
type,
|
|
31
|
-
href: `/api/v1/meta/${type}s`,
|
|
32
|
-
count: SchemaRegistry.listItems(type).length
|
|
33
|
-
}))
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
// 3. Metadata: List Items by Type
|
|
37
|
-
getMetaItems(typePlural) {
|
|
38
|
-
// Simple Singularization Mapping
|
|
39
|
-
const typeMap = {
|
|
40
|
-
'objects': 'object',
|
|
41
|
-
'apps': 'app',
|
|
42
|
-
'flows': 'flow',
|
|
43
|
-
'reports': 'report',
|
|
44
|
-
'plugins': 'plugin',
|
|
45
|
-
'kinds': 'kind'
|
|
46
|
-
};
|
|
47
|
-
const type = typeMap[typePlural] || typePlural;
|
|
48
|
-
const items = SchemaRegistry.listItems(type);
|
|
49
|
-
const summaries = items.map((item) => ({
|
|
50
|
-
id: item.id,
|
|
51
|
-
name: item.name,
|
|
52
|
-
label: item.label,
|
|
53
|
-
type: item.type,
|
|
54
|
-
icon: item.icon,
|
|
55
|
-
description: item.description,
|
|
56
|
-
...(type === 'object' ? { path: `/api/v1/data/${item.name}` } : {}),
|
|
57
|
-
self: `/api/v1/meta/${typePlural}/${item.name || item.id}`
|
|
58
|
-
}));
|
|
59
|
-
return { data: summaries };
|
|
60
|
-
}
|
|
61
|
-
// 4. Metadata: Get Single Item
|
|
62
|
-
getMetaItem(typePlural, name) {
|
|
63
|
-
const typeMap = {
|
|
64
|
-
'objects': 'object',
|
|
65
|
-
'apps': 'app',
|
|
66
|
-
'flows': 'flow',
|
|
67
|
-
'reports': 'report',
|
|
68
|
-
'plugins': 'plugin',
|
|
69
|
-
'kinds': 'kind'
|
|
70
|
-
};
|
|
71
|
-
const type = typeMap[typePlural] || typePlural;
|
|
72
|
-
const item = SchemaRegistry.getItem(type, name);
|
|
73
|
-
if (!item)
|
|
74
|
-
throw new Error(`Metadata not found: ${type}/${name}`);
|
|
75
|
-
return item;
|
|
76
|
-
}
|
|
77
|
-
// 5. UI: View Definition
|
|
78
|
-
getUiView(objectName, type) {
|
|
79
|
-
const view = this.engine.getView(objectName, type);
|
|
80
|
-
if (!view)
|
|
81
|
-
throw new Error('View not generated');
|
|
82
|
-
return view;
|
|
83
|
-
}
|
|
84
|
-
// 6. Data: Find
|
|
85
|
-
async findData(objectName, query) {
|
|
86
|
-
return await this.engine.find(objectName, query);
|
|
87
|
-
}
|
|
88
|
-
// 7. Data: Query (Advanced AST)
|
|
89
|
-
async queryData(objectName, body) {
|
|
90
|
-
return await this.engine.find(objectName, body);
|
|
91
|
-
}
|
|
92
|
-
// 8. Data: Get
|
|
93
|
-
async getData(objectName, id) {
|
|
94
|
-
return await this.engine.get(objectName, id);
|
|
95
|
-
}
|
|
96
|
-
// 9. Data: Create
|
|
97
|
-
async createData(objectName, body) {
|
|
98
|
-
return await this.engine.create(objectName, body);
|
|
99
|
-
}
|
|
100
|
-
// 10. Data: Update
|
|
101
|
-
async updateData(objectName, id, body) {
|
|
102
|
-
return await this.engine.update(objectName, id, body);
|
|
103
|
-
}
|
|
104
|
-
// 11. Data: Delete
|
|
105
|
-
async deleteData(objectName, id) {
|
|
106
|
-
return await this.engine.delete(objectName, id);
|
|
107
|
-
}
|
|
108
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ObjectStackKernel } from './kernel';
|
|
2
|
-
export interface RuntimeContext {
|
|
3
|
-
engine: ObjectStackKernel;
|
|
4
|
-
}
|
|
5
|
-
export interface RuntimePlugin {
|
|
6
|
-
name: string;
|
|
7
|
-
install?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
8
|
-
onStart?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
9
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/src/kernel.ts
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import { ServiceObject } from '@objectstack/spec/data';
|
|
2
|
-
import { SchemaRegistry, ObjectQL } from '@objectstack/objectql';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* ObjectStack Kernel (Microkernel)
|
|
6
|
-
*
|
|
7
|
-
* The central container orchestrating the application lifecycle,
|
|
8
|
-
* plugins, and the core ObjectQL engine.
|
|
9
|
-
*/
|
|
10
|
-
export class ObjectStackKernel {
|
|
11
|
-
public ql: ObjectQL;
|
|
12
|
-
private plugins: any[];
|
|
13
|
-
|
|
14
|
-
constructor(plugins: any[] = []) {
|
|
15
|
-
// 1. Initialize Engine with Host Context (Simulated OS services)
|
|
16
|
-
this.ql = new ObjectQL({
|
|
17
|
-
env: process.env.NODE_ENV || 'development'
|
|
18
|
-
});
|
|
19
|
-
this.plugins = plugins;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async start() {
|
|
23
|
-
console.log('[Kernel] Starting...');
|
|
24
|
-
|
|
25
|
-
// 0. Register Provided Plugins
|
|
26
|
-
for (const p of this.plugins) {
|
|
27
|
-
// Check if it is a Runtime Plugin (System Capability)
|
|
28
|
-
if ('onStart' in p || 'install' in p) {
|
|
29
|
-
console.log(`[Kernel] Loading Runtime Plugin: ${p.name}`);
|
|
30
|
-
if (p.install) await p.install({ engine: this });
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Otherwise treat as App Manifest
|
|
35
|
-
console.log(`[Kernel] Loading App Manifest: ${p.id || p.name}`);
|
|
36
|
-
SchemaRegistry.registerPlugin(p);
|
|
37
|
-
|
|
38
|
-
// Register Objects from App/Plugin
|
|
39
|
-
if (p.objects) {
|
|
40
|
-
for (const obj of p.objects) {
|
|
41
|
-
SchemaRegistry.registerObject(obj);
|
|
42
|
-
console.log(`[Kernel] Registered Object: ${obj.name}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 1. Load Drivers (Default to Memory if none provided in plugins)
|
|
48
|
-
// TODO: Detect driver from plugins. For now, we still hard load memory driver if needed?
|
|
49
|
-
// In strict mode, user should pass driver in plugins array (DriverManifest).
|
|
50
|
-
// check if driver is registered
|
|
51
|
-
|
|
52
|
-
// For Backwards Compat / Easy Dev, try dynamic import of memory driver if installed
|
|
53
|
-
try {
|
|
54
|
-
// @ts-ignore
|
|
55
|
-
const { InMemoryDriver } = await import('@objectstack/driver-memory');
|
|
56
|
-
const driver = new InMemoryDriver();
|
|
57
|
-
this.ql.registerDriver(driver);
|
|
58
|
-
} catch (e) {
|
|
59
|
-
// Ignore if not present
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 2. Initialize Engine
|
|
63
|
-
await this.ql.init();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// 3. Seed Data
|
|
67
|
-
await this.seed();
|
|
68
|
-
|
|
69
|
-
// 4. Start Runtime Plugins
|
|
70
|
-
for (const p of this.plugins) {
|
|
71
|
-
if (('onStart' in p) && typeof p.onStart === 'function') {
|
|
72
|
-
console.log(`[Kernel] Starting Plugin: ${p.name}`);
|
|
73
|
-
await p.onStart({ engine: this });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async seed() {
|
|
79
|
-
// If no driver registered yet, this might fail or wait.
|
|
80
|
-
// In real world, we wait for 'ready' event.
|
|
81
|
-
try {
|
|
82
|
-
// Mock System Table
|
|
83
|
-
try {
|
|
84
|
-
// We don't have SystemStatus defined in schema usually, skipping for general engine
|
|
85
|
-
// await this.ql.insert('SystemStatus', { status: 'OK', uptime: 0 });
|
|
86
|
-
} catch {}
|
|
87
|
-
|
|
88
|
-
// Iterate over all registered plugins/apps and check for 'data' property in manifest
|
|
89
|
-
|
|
90
|
-
const plugins = SchemaRegistry.getRegisteredTypes(); // This returns types like 'plugin', 'app'
|
|
91
|
-
|
|
92
|
-
// This is a bit hacky because we don't have a direct "getAllManifests" API exposed easily
|
|
93
|
-
// We will iterate known apps for now, or improve Registry API later.
|
|
94
|
-
// Actually, SchemaRegistry.listItems('app') returns the manifests!
|
|
95
|
-
|
|
96
|
-
const apps = [...SchemaRegistry.listItems('app'), ...SchemaRegistry.listItems('plugin')];
|
|
97
|
-
|
|
98
|
-
for (const appItem of apps) {
|
|
99
|
-
const app = appItem as any; // Cast to access data prop safely
|
|
100
|
-
if (app.data && Array.isArray(app.data)) {
|
|
101
|
-
console.log(`[Kernel] Seeding data for ${app.name || app.id}...`);
|
|
102
|
-
for (const seed of app.data) {
|
|
103
|
-
try {
|
|
104
|
-
// Check if data exists
|
|
105
|
-
const existing = await this.ql.find(seed.object, { top: 1 });
|
|
106
|
-
if (existing.length === 0) {
|
|
107
|
-
console.log(`[Kernel] Inserting ${seed.records.length} records into ${seed.object}`);
|
|
108
|
-
for (const record of seed.records) {
|
|
109
|
-
await this.ql.insert(seed.object, record);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch (e) {
|
|
113
|
-
console.warn(`[Kernel] Failed to seed ${seed.object}`, e);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
} catch(e) {
|
|
120
|
-
console.warn('Seed failed (driver might not be ready):', e);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Forward methods to ObjectQL
|
|
125
|
-
async find(objectName: string, query: any) {
|
|
126
|
-
this.ensureSchema(objectName);
|
|
127
|
-
const results = await this.ql.find(objectName, { top: 100 });
|
|
128
|
-
return { value: results, count: results.length };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async get(objectName: string, id: string) {
|
|
132
|
-
this.ensureSchema(objectName);
|
|
133
|
-
// Find One
|
|
134
|
-
const results = await this.ql.find(objectName, { top: 1 }); // Mock implementation
|
|
135
|
-
return results[0];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async create(objectName: string, data: any) {
|
|
139
|
-
this.ensureSchema(objectName);
|
|
140
|
-
return this.ql.insert(objectName, data);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async update(objectName: string, id: string, data: any) {
|
|
144
|
-
this.ensureSchema(objectName);
|
|
145
|
-
return this.ql.update(objectName, id, data);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async delete(objectName: string, id: string) {
|
|
149
|
-
this.ensureSchema(objectName);
|
|
150
|
-
return this.ql.delete(objectName, id);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// [New Methods for ObjectUI]
|
|
154
|
-
getMetadata(objectName: string) {
|
|
155
|
-
return this.ensureSchema(objectName);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
getView(objectName: string, viewType: 'list' | 'form' = 'list') {
|
|
159
|
-
const schema = this.ensureSchema(objectName);
|
|
160
|
-
|
|
161
|
-
// Auto-Scaffold Default View
|
|
162
|
-
if (viewType === 'list') {
|
|
163
|
-
return {
|
|
164
|
-
type: 'datagrid',
|
|
165
|
-
title: `${schema.label || objectName} List`,
|
|
166
|
-
columns: Object.keys(schema.fields || {}).map(key => ({
|
|
167
|
-
field: key,
|
|
168
|
-
label: schema.fields?.[key]?.label || key,
|
|
169
|
-
width: 150
|
|
170
|
-
})),
|
|
171
|
-
actions: ['create', 'edit', 'delete']
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private ensureSchema(name: string): ServiceObject {
|
|
178
|
-
const schema = SchemaRegistry.getObject(name);
|
|
179
|
-
if (!schema) throw new Error(`Unknown object: ${name}`);
|
|
180
|
-
return schema;
|
|
181
|
-
}
|
|
182
|
-
}
|
package/src/protocol.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { SchemaRegistry } from '@objectstack/objectql';
|
|
2
|
-
import { ObjectStackKernel } from './kernel';
|
|
3
|
-
|
|
4
|
-
export interface ApiRequest {
|
|
5
|
-
params: Record<string, string>;
|
|
6
|
-
query: Record<string, string | string[]>;
|
|
7
|
-
body?: any;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class ObjectStackRuntimeProtocol {
|
|
11
|
-
private engine: ObjectStackKernel;
|
|
12
|
-
|
|
13
|
-
constructor(engine: ObjectStackKernel) {
|
|
14
|
-
this.engine = engine;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// 1. Discovery
|
|
18
|
-
getDiscovery() {
|
|
19
|
-
return {
|
|
20
|
-
name: 'ObjectOS Server',
|
|
21
|
-
version: '1.0.0',
|
|
22
|
-
environment: process.env.NODE_ENV || 'development',
|
|
23
|
-
routes: {
|
|
24
|
-
discovery: '/api/v1',
|
|
25
|
-
metadata: '/api/v1/meta',
|
|
26
|
-
data: '/api/v1/data',
|
|
27
|
-
auth: '/api/v1/auth',
|
|
28
|
-
ui: '/api/v1/ui'
|
|
29
|
-
},
|
|
30
|
-
capabilities: {
|
|
31
|
-
search: true,
|
|
32
|
-
files: true
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// 2. Metadata: List Types
|
|
38
|
-
getMetaTypes() {
|
|
39
|
-
const types = SchemaRegistry.getRegisteredTypes();
|
|
40
|
-
return {
|
|
41
|
-
data: types.map(type => ({
|
|
42
|
-
type,
|
|
43
|
-
href: `/api/v1/meta/${type}s`,
|
|
44
|
-
count: SchemaRegistry.listItems(type).length
|
|
45
|
-
}))
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// 3. Metadata: List Items by Type
|
|
50
|
-
getMetaItems(typePlural: string) {
|
|
51
|
-
// Simple Singularization Mapping
|
|
52
|
-
const typeMap: Record<string, string> = {
|
|
53
|
-
'objects': 'object',
|
|
54
|
-
'apps': 'app',
|
|
55
|
-
'flows': 'flow',
|
|
56
|
-
'reports': 'report',
|
|
57
|
-
'plugins': 'plugin',
|
|
58
|
-
'kinds': 'kind'
|
|
59
|
-
};
|
|
60
|
-
const type = typeMap[typePlural] || typePlural;
|
|
61
|
-
const items = SchemaRegistry.listItems(type);
|
|
62
|
-
|
|
63
|
-
const summaries = items.map((item: any) => ({
|
|
64
|
-
id: item.id,
|
|
65
|
-
name: item.name,
|
|
66
|
-
label: item.label,
|
|
67
|
-
type: item.type,
|
|
68
|
-
icon: item.icon,
|
|
69
|
-
description: item.description,
|
|
70
|
-
...(type === 'object' ? { path: `/api/v1/data/${item.name}` } : {}),
|
|
71
|
-
self: `/api/v1/meta/${typePlural}/${item.name || item.id}`
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
return { data: summaries };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 4. Metadata: Get Single Item
|
|
78
|
-
getMetaItem(typePlural: string, name: string) {
|
|
79
|
-
const typeMap: Record<string, string> = {
|
|
80
|
-
'objects': 'object',
|
|
81
|
-
'apps': 'app',
|
|
82
|
-
'flows': 'flow',
|
|
83
|
-
'reports': 'report',
|
|
84
|
-
'plugins': 'plugin',
|
|
85
|
-
'kinds': 'kind'
|
|
86
|
-
};
|
|
87
|
-
const type = typeMap[typePlural] || typePlural;
|
|
88
|
-
const item = SchemaRegistry.getItem(type, name);
|
|
89
|
-
if (!item) throw new Error(`Metadata not found: ${type}/${name}`);
|
|
90
|
-
return item;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// 5. UI: View Definition
|
|
94
|
-
getUiView(objectName: string, type: 'list' | 'form') {
|
|
95
|
-
const view = this.engine.getView(objectName, type);
|
|
96
|
-
if (!view) throw new Error('View not generated');
|
|
97
|
-
return view;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 6. Data: Find
|
|
101
|
-
async findData(objectName: string, query: any) {
|
|
102
|
-
return await this.engine.find(objectName, query);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// 7. Data: Query (Advanced AST)
|
|
106
|
-
async queryData(objectName: string, body: any) {
|
|
107
|
-
return await this.engine.find(objectName, body);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// 8. Data: Get
|
|
111
|
-
async getData(objectName: string, id: string) {
|
|
112
|
-
return await this.engine.get(objectName, id);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 9. Data: Create
|
|
116
|
-
async createData(objectName: string, body: any) {
|
|
117
|
-
return await this.engine.create(objectName, body);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 10. Data: Update
|
|
121
|
-
async updateData(objectName: string, id: string, body: any) {
|
|
122
|
-
return await this.engine.update(objectName, id, body);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 11. Data: Delete
|
|
126
|
-
async deleteData(objectName: string, id: string) {
|
|
127
|
-
return await this.engine.delete(objectName, id);
|
|
128
|
-
}
|
|
129
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { ObjectStackKernel } from './kernel';
|
|
2
|
-
|
|
3
|
-
export interface RuntimeContext {
|
|
4
|
-
engine: ObjectStackKernel;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface RuntimePlugin {
|
|
8
|
-
name: string;
|
|
9
|
-
install?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
10
|
-
onStart?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
11
|
-
}
|