Skip to content

Commit dbc0aa2

Browse files
authored
Merge pull request #428 from objectstack-ai/copilot/evaluate-metadata-loading-package
2 parents acf8bcc + 97a8c3c commit dbc0aa2

36 files changed

+3555
-10
lines changed

ARCHITECTURE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,19 @@ ObjectStack is organized as a **monorepo** with distinct package layers:
171171

172172
**Dependencies**: `@objectstack/core`, `@objectstack/spec`, `@objectstack/types`
173173

174+
#### `@objectstack/metadata`
175+
**Location**: `packages/metadata/`
176+
**Role**: Metadata Loading & Persistence
177+
178+
- Metadata serialization/deserialization (JSON, YAML, TypeScript)
179+
- File system operations (load, save, watch)
180+
- Validation using Zod schemas
181+
- ETag-based caching
182+
- Import/export tools
183+
- SchemaRegistry persistence bridge
184+
185+
**Dependencies**: `@objectstack/spec`, `@objectstack/core`, `@objectstack/types`, `glob`, `js-yaml`, `chokidar`
186+
174187
#### `@objectstack/runtime`
175188
**Location**: `packages/runtime/`
176189
**Role**: Runtime Utilities & Plugins
@@ -409,6 +422,12 @@ interface PluginCapabilityManifest {
409422
│ │ ↑
410423
│ │ └── @objectstack/plugin-msw
411424
│ │
425+
│ ├── @objectstack/metadata (Metadata I/O)
426+
│ │ ↑
427+
│ │ ├── @objectstack/runtime (Uses for manifest loading)
428+
│ │ ├── @objectstack/cli (Uses for code generation)
429+
│ │ └── @objectstack/objectql (Uses for registry persistence)
430+
│ │
412431
│ ├── @objectstack/runtime (Plugins & HTTP)
413432
│ │ ↑
414433
│ │ └── (Used by server plugins)

PACKAGE-DEPENDENCIES.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ This is the foundation layer. All other packages depend on `@objectstack/spec`.
4545
│ └── @objectstack/types
4646
└── Role: ObjectQL query engine
4747
48+
@objectstack/metadata
49+
├── Dependencies:
50+
│ ├── @objectstack/core
51+
│ ├── @objectstack/spec
52+
│ ├── @objectstack/types
53+
│ ├── glob
54+
│ ├── js-yaml
55+
│ └── chokidar (optional)
56+
└── Role: Metadata loading, saving, and persistence
57+
4858
@objectstack/runtime
4959
├── Dependencies:
5060
│ ├── @objectstack/core
@@ -131,6 +141,12 @@ This is the foundation layer. All other packages depend on `@objectstack/spec`.
131141
│ │ ↑
132142
│ │ └── @objectstack/plugin-msw (Layer 5)
133143
│ │
144+
│ ├── @objectstack/metadata (Layer 3)
145+
│ │ ↑
146+
│ │ ├── @objectstack/runtime (Layer 3)
147+
│ │ ├── @objectstack/cli (Layer 6)
148+
│ │ └── (Future integrations)
149+
│ │
134150
│ ├── @objectstack/runtime (Layer 3)
135151
│ │ ↑
136152
│ │ └── (Used by server plugins)
@@ -156,6 +172,7 @@ This is the foundation layer. All other packages depend on `@objectstack/spec`.
156172
| `@objectstack/types` | `@objectstack/spec` |
157173
| `@objectstack/core` | `@objectstack/spec`, `pino`, `zod` |
158174
| `@objectstack/objectql` | `@objectstack/core`, `@objectstack/spec`, `@objectstack/types` |
175+
| `@objectstack/metadata` | `@objectstack/core`, `@objectstack/spec`, `@objectstack/types`, `glob`, `js-yaml`, `chokidar` |
159176
| `@objectstack/runtime` | `@objectstack/core`, `@objectstack/spec`, `@objectstack/types` |
160177
| `@objectstack/client` | `@objectstack/core`, `@objectstack/spec` |
161178
| `@objectstack/client-react` | `@objectstack/client`, `@objectstack/core`, `@objectstack/spec`, `react` (peer) |
@@ -181,6 +198,7 @@ pnpm --filter @objectstack/core build
181198

182199
# Level 3
183200
pnpm --filter @objectstack/objectql build
201+
pnpm --filter @objectstack/metadata build
184202
pnpm --filter @objectstack/runtime build
185203

186204
# Level 4
@@ -253,7 +271,8 @@ Use peer dependencies for:
253271
|---------|---------------|-------------------|
254272
| `@objectstack/spec` | Define protocols | Runtime behavior |
255273
| `@objectstack/core` | Manage plugin lifecycle | Query execution, HTTP handling |
256-
| `@objectstack/objectql` | Execute queries | HTTP routing, UI rendering |
274+
| `@objectstack/objectql` | Execute queries | HTTP routing, UI rendering, Metadata persistence |
275+
| `@objectstack/metadata` | Load/save metadata | Query execution, Plugin lifecycle |
257276
| `@objectstack/runtime` | Provide plugin utilities | Execute queries directly |
258277

259278
## External Dependencies

content/docs/references/meta.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
{
22
"title": "Protocol Reference",
33
"pages": [
4-
"packages",
54
"data",
65
"ui",
76
"automation",
87
"system",
98
"permission",
109
"ai",
1110
"api",
12-
"driver",
13-
"hub",
14-
"integration",
15-
"auth",
16-
"shared"
11+
"driver"
1712
]
1813
}

content/docs/references/system/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This section contains all protocol schemas for the system layer of ObjectStack.
2424
<Card href="./manifest" title="Manifest" description="Source: packages/spec/src/system/manifest.zod.ts" />
2525
<Card href="./masking" title="Masking" description="Source: packages/spec/src/system/masking.zod.ts" />
2626
<Card href="./message-queue" title="Message Queue" description="Source: packages/spec/src/system/message-queue.zod.ts" />
27+
<Card href="./metadata-loader" title="Metadata Loader" description="Source: packages/spec/src/system/metadata-loader.zod.ts" />
2728
<Card href="./metrics" title="Metrics" description="Source: packages/spec/src/system/metrics.zod.ts" />
2829
<Card href="./notification" title="Notification" description="Source: packages/spec/src/system/notification.zod.ts" />
2930
<Card href="./object-storage" title="Object Storage" description="Source: packages/spec/src/system/object-storage.zod.ts" />

content/docs/references/system/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"manifest",
1818
"masking",
1919
"message-queue",
20+
"metadata-loader",
2021
"metrics",
2122
"notification",
2223
"object-storage",

examples/msw-react-crud/src/components/TaskList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export function TaskList({ client, onEdit, refreshTrigger }: TaskListProps) {
3636
sort: ['priority', '-created_at']
3737
});
3838

39-
// Handle { value: [] } (OData), { records: [] } (Protocol) and [] (Raw) formats
40-
const rawValues = Array.isArray(result) ? result : (result.value || result.records || []);
39+
// Handle { value: [] } (PaginatedResult) and [] (Raw) formats
40+
const rawValues = Array.isArray(result) ? result : (result.value || []);
4141
const fetchedTasks = [...rawValues] as Task[];
4242

4343
// Client-side sort fallback (since InMemoryDriver has limited sort support)

packages/metadata/README.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# @objectstack/metadata
2+
3+
Metadata loading, saving, and persistence for ObjectStack.
4+
5+
## Overview
6+
7+
The `@objectstack/metadata` package provides a unified interface for managing metadata across the ObjectStack ecosystem. It handles:
8+
9+
- **Metadata Serialization/Deserialization** - Support for JSON, YAML, TypeScript, and JavaScript formats
10+
- **File System Operations** - Load, save, and watch metadata files
11+
- **Validation** - Integration with Zod schemas from `@objectstack/spec`
12+
- **Caching** - ETag-based caching for performance optimization
13+
- **File Watching** - Development mode with automatic reload on file changes
14+
15+
## Installation
16+
17+
```bash
18+
pnpm add @objectstack/metadata
19+
```
20+
21+
## Quick Start
22+
23+
```typescript
24+
import { MetadataManager } from '@objectstack/metadata';
25+
import type { ServiceObject } from '@objectstack/spec/data';
26+
27+
// Create manager
28+
const manager = new MetadataManager({
29+
rootDir: './metadata',
30+
formats: ['typescript', 'json', 'yaml'],
31+
cache: { enabled: true, ttl: 3600 },
32+
watch: process.env.NODE_ENV === 'development',
33+
});
34+
35+
// Load metadata
36+
const customer = await manager.load<ServiceObject>('object', 'customer');
37+
38+
// Save metadata
39+
await manager.save('object', 'project', projectObject, {
40+
format: 'typescript',
41+
prettify: true,
42+
});
43+
44+
// Load multiple items
45+
const objects = await manager.loadMany<ServiceObject>('object', {
46+
patterns: ['**/*.object.ts', '**/*.object.json'],
47+
});
48+
49+
// Watch for changes
50+
manager.watch('object', (event) => {
51+
console.log(`Object ${event.type}:`, event.name);
52+
});
53+
```
54+
55+
## API
56+
57+
### MetadataManager
58+
59+
Main class for metadata operations.
60+
61+
#### Constructor
62+
63+
```typescript
64+
new MetadataManager(config: MetadataManagerConfig)
65+
```
66+
67+
**Config options:**
68+
- `rootDir` - Root directory for metadata files
69+
- `formats` - Enabled serialization formats (default: `['typescript', 'json', 'yaml']`)
70+
- `cache` - Cache configuration with `enabled` and `ttl` options
71+
- `watch` - Enable file watching (default: `false`)
72+
- `watchOptions` - File watcher options (`ignored`, `persistent`, `ignoreInitial`)
73+
74+
#### Methods
75+
76+
**load<T>(type: string, name: string, options?: MetadataLoadOptions): Promise<T | null>**
77+
78+
Load a single metadata item.
79+
80+
```typescript
81+
const customer = await manager.load<ServiceObject>('object', 'customer');
82+
```
83+
84+
**loadMany<T>(type: string, options?: MetadataLoadOptions): Promise<T[]>**
85+
86+
Load multiple metadata items matching patterns.
87+
88+
```typescript
89+
const objects = await manager.loadMany<ServiceObject>('object', {
90+
patterns: ['**/*.object.ts'],
91+
limit: 100,
92+
});
93+
```
94+
95+
**save<T>(type: string, name: string, data: T, options?: MetadataSaveOptions): Promise<MetadataSaveResult>**
96+
97+
Save metadata to disk.
98+
99+
```typescript
100+
await manager.save('object', 'customer', customerObject, {
101+
format: 'typescript',
102+
prettify: true,
103+
backup: true,
104+
});
105+
```
106+
107+
**exists(type: string, name: string): Promise<boolean>**
108+
109+
Check if metadata item exists.
110+
111+
```typescript
112+
const exists = await manager.exists('object', 'customer');
113+
```
114+
115+
**list(type: string): Promise<string[]>**
116+
117+
List all items of a type.
118+
119+
```typescript
120+
const objectNames = await manager.list('object');
121+
```
122+
123+
**watch(type: string, callback: WatchCallback): void**
124+
125+
Watch for metadata changes.
126+
127+
```typescript
128+
manager.watch('object', (event) => {
129+
if (event.type === 'added') {
130+
console.log('New object:', event.name);
131+
}
132+
});
133+
```
134+
135+
**stopWatching(): Promise<void>**
136+
137+
Stop all file watching.
138+
139+
## Serialization Formats
140+
141+
### JSON
142+
143+
```json
144+
{
145+
"name": "customer",
146+
"label": "Customer",
147+
"fields": {
148+
"name": { "type": "text", "label": "Name" }
149+
}
150+
}
151+
```
152+
153+
### YAML
154+
155+
```yaml
156+
name: customer
157+
label: Customer
158+
fields:
159+
name:
160+
type: text
161+
label: Name
162+
```
163+
164+
### TypeScript
165+
166+
```typescript
167+
import type { ServiceObject } from '@objectstack/spec/data';
168+
169+
export const metadata: ServiceObject = {
170+
name: 'customer',
171+
label: 'Customer',
172+
fields: {
173+
name: { type: 'text', label: 'Name' },
174+
},
175+
};
176+
177+
export default metadata;
178+
```
179+
180+
## Architecture
181+
182+
The metadata package is designed as a Layer 3 package in the ObjectStack architecture:
183+
184+
```
185+
@objectstack/metadata (Layer 3)
186+
├── Dependencies:
187+
│ ├── @objectstack/spec (validation)
188+
│ ├── @objectstack/core (logging, DI)
189+
│ ├── @objectstack/types (shared types)
190+
│ ├── glob (file pattern matching)
191+
│ ├── js-yaml (YAML support)
192+
│ └── chokidar (file watching)
193+
└── Used By:
194+
├── @objectstack/cli (code generation)
195+
├── @objectstack/runtime (manifest loading)
196+
└── @objectstack/objectql (registry persistence)
197+
```
198+
199+
## License
200+
201+
MIT

packages/metadata/package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@objectstack/metadata",
3+
"version": "0.6.1",
4+
"description": "Metadata loading, saving, and persistence for ObjectStack",
5+
"main": "src/index.ts",
6+
"types": "src/index.ts",
7+
"scripts": {
8+
"build": "tsc",
9+
"dev": "tsc --watch",
10+
"clean": "rm -rf dist",
11+
"test": "vitest run",
12+
"test:watch": "vitest",
13+
"test:coverage": "vitest run --coverage"
14+
},
15+
"keywords": [
16+
"objectstack",
17+
"metadata",
18+
"persistence",
19+
"serialization",
20+
"loader"
21+
],
22+
"dependencies": {
23+
"@objectstack/core": "workspace:*",
24+
"@objectstack/spec": "workspace:*",
25+
"@objectstack/types": "workspace:*",
26+
"glob": "^10.3.10",
27+
"js-yaml": "^4.1.0",
28+
"chokidar": "^3.5.3",
29+
"zod": "^3.22.4"
30+
},
31+
"devDependencies": {
32+
"@types/js-yaml": "^4.0.9",
33+
"@types/node": "^20.0.0",
34+
"typescript": "^5.0.0",
35+
"vitest": "^1.0.0"
36+
}
37+
}

0 commit comments

Comments
 (0)