@objectstack/metadata 0.9.0 → 0.9.2
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 +19 -0
- package/README.md +257 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @objectstack/metadata
|
|
2
2
|
|
|
3
|
+
## 0.9.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @objectstack/spec@0.9.2
|
|
9
|
+
- @objectstack/core@0.9.2
|
|
10
|
+
- @objectstack/types@0.9.2
|
|
11
|
+
|
|
12
|
+
## 0.9.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Patch release for maintenance and stability improvements. All packages updated with unified versioning.
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @objectstack/spec@0.9.1
|
|
19
|
+
- @objectstack/core@0.9.1
|
|
20
|
+
- @objectstack/types@0.9.1
|
|
21
|
+
|
|
3
22
|
## 0.8.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -12,6 +12,13 @@ The `@objectstack/metadata` package provides a unified interface for managing me
|
|
|
12
12
|
- **Caching** - ETag-based caching for performance optimization
|
|
13
13
|
- **File Watching** - Development mode with automatic reload on file changes
|
|
14
14
|
|
|
15
|
+
## 🤖 AI Development Context
|
|
16
|
+
|
|
17
|
+
**Role**: Metadata IO & Persistence
|
|
18
|
+
**Usage**:
|
|
19
|
+
- Use `MetadataManager` to read/write `.object.ts`, `.view.yaml` files.
|
|
20
|
+
- Handles format loading (TS, JSON, YAML).
|
|
21
|
+
|
|
15
22
|
## Installation
|
|
16
23
|
|
|
17
24
|
```bash
|
|
@@ -196,6 +203,256 @@ The metadata package is designed as a Layer 3 package in the ObjectStack archite
|
|
|
196
203
|
└── @objectstack/objectql (registry persistence)
|
|
197
204
|
```
|
|
198
205
|
|
|
206
|
+
## Common Workflows
|
|
207
|
+
|
|
208
|
+
### Development Workflow with File Watching
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
212
|
+
|
|
213
|
+
const manager = new MetadataManager({
|
|
214
|
+
rootDir: './metadata',
|
|
215
|
+
watch: true, // Enable file watching
|
|
216
|
+
cache: { enabled: true, ttl: 3600 }
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Watch for changes and reload
|
|
220
|
+
manager.watch('object', async (event) => {
|
|
221
|
+
if (event.type === 'modified' || event.type === 'added') {
|
|
222
|
+
console.log(`Reloading object: ${event.name}`);
|
|
223
|
+
const updated = await manager.load('object', event.name);
|
|
224
|
+
|
|
225
|
+
// Notify the system to reload
|
|
226
|
+
await objectQL.reloadObject(event.name, updated);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Hot module replacement for development
|
|
231
|
+
console.log('Watching metadata files for changes...');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Metadata Migration Workflow
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
238
|
+
|
|
239
|
+
async function migrateMetadata() {
|
|
240
|
+
const manager = new MetadataManager({
|
|
241
|
+
rootDir: './metadata'
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// 1. Load all existing objects
|
|
245
|
+
const objects = await manager.loadMany('object');
|
|
246
|
+
|
|
247
|
+
// 2. Transform metadata (e.g., rename field)
|
|
248
|
+
const transformed = objects.map(obj => ({
|
|
249
|
+
...obj,
|
|
250
|
+
fields: Object.entries(obj.fields).reduce((acc, [key, field]) => {
|
|
251
|
+
// Rename 'description' to 'notes'
|
|
252
|
+
const newKey = key === 'description' ? 'notes' : key;
|
|
253
|
+
acc[newKey] = field;
|
|
254
|
+
return acc;
|
|
255
|
+
}, {})
|
|
256
|
+
}));
|
|
257
|
+
|
|
258
|
+
// 3. Save with backup
|
|
259
|
+
for (const obj of transformed) {
|
|
260
|
+
await manager.save('object', obj.name, obj, {
|
|
261
|
+
format: 'typescript',
|
|
262
|
+
backup: true, // Create .bak file
|
|
263
|
+
prettify: true
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log(`Migrated ${objects.length} objects`);
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Multi-Format Support Workflow
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
275
|
+
|
|
276
|
+
const manager = new MetadataManager({
|
|
277
|
+
rootDir: './metadata',
|
|
278
|
+
formats: ['typescript', 'json', 'yaml']
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Load from any format - manager auto-detects
|
|
282
|
+
const customer = await manager.load('object', 'customer');
|
|
283
|
+
// Tries: customer.object.ts, customer.object.json, customer.object.yaml
|
|
284
|
+
|
|
285
|
+
// Save in preferred format
|
|
286
|
+
await manager.save('object', 'customer', customer, {
|
|
287
|
+
format: 'typescript' // Convert to TypeScript
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Generate documentation from metadata
|
|
291
|
+
const allObjects = await manager.loadMany('object');
|
|
292
|
+
const docs = allObjects.map(obj => `
|
|
293
|
+
## ${obj.label}
|
|
294
|
+
|
|
295
|
+
**Name:** ${obj.name}
|
|
296
|
+
|
|
297
|
+
**Fields:**
|
|
298
|
+
${Object.entries(obj.fields).map(([name, field]) =>
|
|
299
|
+
`- **${field.label}** (\`${name}\`): ${field.type}`
|
|
300
|
+
).join('\n')}
|
|
301
|
+
`).join('\n\n');
|
|
302
|
+
|
|
303
|
+
fs.writeFileSync('docs/objects.md', docs);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Validation and Testing Workflow
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
310
|
+
import { ObjectSchema } from '@objectstack/spec/data';
|
|
311
|
+
|
|
312
|
+
async function validateAllMetadata() {
|
|
313
|
+
const manager = new MetadataManager({
|
|
314
|
+
rootDir: './metadata'
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const objects = await manager.loadMany('object');
|
|
318
|
+
const errors = [];
|
|
319
|
+
|
|
320
|
+
for (const obj of objects) {
|
|
321
|
+
const result = ObjectSchema.safeParse(obj);
|
|
322
|
+
|
|
323
|
+
if (!result.success) {
|
|
324
|
+
errors.push({
|
|
325
|
+
name: obj.name,
|
|
326
|
+
issues: result.error.issues
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (errors.length > 0) {
|
|
332
|
+
console.error('Validation errors found:');
|
|
333
|
+
errors.forEach(({ name, issues }) => {
|
|
334
|
+
console.error(`\n${name}:`);
|
|
335
|
+
issues.forEach(issue => {
|
|
336
|
+
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.log(`✅ All ${objects.length} objects validated successfully`);
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Metadata Versioning Workflow
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
350
|
+
import { execSync } from 'child_process';
|
|
351
|
+
|
|
352
|
+
async function versionMetadata() {
|
|
353
|
+
const manager = new MetadataManager({
|
|
354
|
+
rootDir: './metadata'
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const objects = await manager.loadMany('object');
|
|
358
|
+
|
|
359
|
+
// Get git user name safely
|
|
360
|
+
let modifiedBy = 'unknown';
|
|
361
|
+
try {
|
|
362
|
+
modifiedBy = execSync('git config user.name', { encoding: 'utf-8' }).trim();
|
|
363
|
+
} catch (error) {
|
|
364
|
+
console.warn('Could not get git user name, using "unknown"');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Add version metadata
|
|
368
|
+
const versioned = objects.map(obj => ({
|
|
369
|
+
...obj,
|
|
370
|
+
metadata: {
|
|
371
|
+
...obj.metadata,
|
|
372
|
+
version: '2.0.0',
|
|
373
|
+
lastModified: new Date().toISOString(),
|
|
374
|
+
modifiedBy
|
|
375
|
+
}
|
|
376
|
+
}));
|
|
377
|
+
|
|
378
|
+
// Save versioned metadata
|
|
379
|
+
for (const obj of versioned) {
|
|
380
|
+
await manager.save('object', obj.name, obj, {
|
|
381
|
+
format: 'typescript',
|
|
382
|
+
prettify: true
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Commit to version control (if git is available)
|
|
387
|
+
try {
|
|
388
|
+
execSync('git add metadata/', { stdio: 'inherit' });
|
|
389
|
+
execSync('git commit -m "Version bump to 2.0.0"', { stdio: 'inherit' });
|
|
390
|
+
} catch (error) {
|
|
391
|
+
console.warn('Git commit failed, changes are staged but not committed');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Import/Export Workflow
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
400
|
+
|
|
401
|
+
async function exportToJSON() {
|
|
402
|
+
const manager = new MetadataManager({
|
|
403
|
+
rootDir: './metadata'
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Load all metadata
|
|
407
|
+
const [objects, views, apps] = await Promise.all([
|
|
408
|
+
manager.loadMany('object'),
|
|
409
|
+
manager.loadMany('view'),
|
|
410
|
+
manager.loadMany('app')
|
|
411
|
+
]);
|
|
412
|
+
|
|
413
|
+
// Create unified export
|
|
414
|
+
const exportData = {
|
|
415
|
+
version: '1.0.0',
|
|
416
|
+
exported: new Date().toISOString(),
|
|
417
|
+
objects,
|
|
418
|
+
views,
|
|
419
|
+
apps
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// Save as single JSON file
|
|
423
|
+
fs.writeFileSync(
|
|
424
|
+
'export/metadata-export.json',
|
|
425
|
+
JSON.stringify(exportData, null, 2)
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
console.log('Export complete!');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async function importFromJSON(filePath: string) {
|
|
432
|
+
const manager = new MetadataManager({
|
|
433
|
+
rootDir: './metadata'
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const importData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
437
|
+
|
|
438
|
+
// Import objects
|
|
439
|
+
for (const obj of importData.objects) {
|
|
440
|
+
await manager.save('object', obj.name, obj, {
|
|
441
|
+
format: 'typescript'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Import views
|
|
446
|
+
for (const view of importData.views) {
|
|
447
|
+
await manager.save('view', view.name, view, {
|
|
448
|
+
format: 'typescript'
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.log('Import complete!');
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
199
456
|
## License
|
|
200
457
|
|
|
201
458
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/metadata",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Metadata loading, saving, and persistence for ObjectStack",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"js-yaml": "^4.1.0",
|
|
17
17
|
"chokidar": "^3.5.3",
|
|
18
18
|
"zod": "^4.3.6",
|
|
19
|
-
"@objectstack/core": "0.9.
|
|
20
|
-
"@objectstack/spec": "0.9.
|
|
21
|
-
"@objectstack/types": "0.9.
|
|
19
|
+
"@objectstack/core": "0.9.2",
|
|
20
|
+
"@objectstack/spec": "0.9.2",
|
|
21
|
+
"@objectstack/types": "0.9.2"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/js-yaml": "^4.0.9",
|