Metadata loading, saving, and persistence for ObjectStack.
The @objectstack/metadata package provides a unified interface for managing metadata across the ObjectStack ecosystem. It handles:
- Metadata Serialization/Deserialization - Support for JSON, YAML, TypeScript, and JavaScript formats
- File System Operations - Load, save, and watch metadata files
- Validation - Integration with Zod schemas from
@objectstack/spec - Caching - ETag-based caching for performance optimization
- File Watching - Development mode with automatic reload on file changes
pnpm add @objectstack/metadataimport { MetadataManager } from '@objectstack/metadata';
import type { ServiceObject } from '@objectstack/spec/data';
// Create manager
const manager = new MetadataManager({
rootDir: './metadata',
formats: ['typescript', 'json', 'yaml'],
cache: { enabled: true, ttl: 3600 },
watch: process.env.NODE_ENV === 'development',
});
// Load metadata
const customer = await manager.load<ServiceObject>('object', 'customer');
// Save metadata
await manager.save('object', 'project', projectObject, {
format: 'typescript',
prettify: true,
});
// Load multiple items
const objects = await manager.loadMany<ServiceObject>('object', {
patterns: ['**/*.object.ts', '**/*.object.json'],
});
// Watch for changes
manager.watch('object', (event) => {
console.log(`Object ${event.type}:`, event.name);
});Main class for metadata operations.
new MetadataManager(config: MetadataManagerConfig)Config options:
rootDir- Root directory for metadata filesformats- Enabled serialization formats (default:['typescript', 'json', 'yaml'])cache- Cache configuration withenabledandttloptionswatch- Enable file watching (default:false)watchOptions- File watcher options (ignored,persistent,ignoreInitial)
load(type: string, name: string, options?: MetadataLoadOptions): Promise<T | null>
Load a single metadata item.
const customer = await manager.load<ServiceObject>('object', 'customer');loadMany(type: string, options?: MetadataLoadOptions): Promise<T[]>
Load multiple metadata items matching patterns.
const objects = await manager.loadMany<ServiceObject>('object', {
patterns: ['**/*.object.ts'],
limit: 100,
});save(type: string, name: string, data: T, options?: MetadataSaveOptions): Promise
Save metadata to disk.
await manager.save('object', 'customer', customerObject, {
format: 'typescript',
prettify: true,
backup: true,
});exists(type: string, name: string): Promise
Check if metadata item exists.
const exists = await manager.exists('object', 'customer');list(type: string): Promise<string[]>
List all items of a type.
const objectNames = await manager.list('object');watch(type: string, callback: WatchCallback): void
Watch for metadata changes.
manager.watch('object', (event) => {
if (event.type === 'added') {
console.log('New object:', event.name);
}
});stopWatching(): Promise
Stop all file watching.
{
"name": "customer",
"label": "Customer",
"fields": {
"name": { "type": "text", "label": "Name" }
}
}name: customer
label: Customer
fields:
name:
type: text
label: Nameimport type { ServiceObject } from '@objectstack/spec/data';
export const metadata: ServiceObject = {
name: 'customer',
label: 'Customer',
fields: {
name: { type: 'text', label: 'Name' },
},
};
export default metadata;The metadata package is designed as a Layer 3 package in the ObjectStack architecture:
@objectstack/metadata (Layer 3)
├── Dependencies:
│ ├── @objectstack/spec (validation)
│ ├── @objectstack/core (logging, DI)
│ ├── @objectstack/types (shared types)
│ ├── glob (file pattern matching)
│ ├── js-yaml (YAML support)
│ └── chokidar (file watching)
└── Used By:
├── @objectstack/cli (code generation)
├── @objectstack/runtime (manifest loading)
└── @objectstack/objectql (registry persistence)
MIT