@objectstack/metadata 2.0.0 → 2.0.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +19 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/metadata-manager.ts +6 -1
- package/src/metadata.test.ts +432 -0
- package/vitest.config.ts +20 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @objectstack/metadata@2.0.
|
|
2
|
+
> @objectstack/metadata@2.0.2 build /home/runner/work/spec/spec/packages/metadata
|
|
3
3
|
> tsup --config ../../tsup.config.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m30.61 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m63.28 KB[39m
|
|
15
|
+
[32mCJS[39m ⚡️ Build success in 93ms
|
|
16
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m28.81 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m61.89 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 97ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 8374ms
|
|
21
21
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m9.83 KB[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m9.83 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @objectstack/metadata
|
|
2
2
|
|
|
3
|
+
## 2.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [1db8559]
|
|
8
|
+
- @objectstack/spec@2.0.2
|
|
9
|
+
- @objectstack/core@2.0.2
|
|
10
|
+
- @objectstack/types@2.0.2
|
|
11
|
+
|
|
12
|
+
## 2.0.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Patch release for maintenance and stability improvements
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @objectstack/spec@2.0.1
|
|
19
|
+
- @objectstack/core@2.0.1
|
|
20
|
+
- @objectstack/types@2.0.1
|
|
21
|
+
|
|
3
22
|
## 2.0.0
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -270,6 +270,11 @@ var MetadataManager = class {
|
|
|
270
270
|
try {
|
|
271
271
|
const items = await loader.loadMany(type, options);
|
|
272
272
|
for (const item of items) {
|
|
273
|
+
const itemAny = item;
|
|
274
|
+
if (itemAny && typeof itemAny.name === "string") {
|
|
275
|
+
const exists = results.some((r) => r && r.name === itemAny.name);
|
|
276
|
+
if (exists) continue;
|
|
277
|
+
}
|
|
273
278
|
results.push(item);
|
|
274
279
|
}
|
|
275
280
|
} catch (e) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/metadata-manager.ts","../src/serializers/json-serializer.ts","../src/serializers/yaml-serializer.ts","../src/serializers/typescript-serializer.ts","../src/node-metadata-manager.ts","../src/loaders/filesystem-loader.ts","../src/plugin.ts","../src/loaders/memory-loader.ts","../src/loaders/remote-loader.ts","../src/migration/index.ts","../src/migration/executor.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/metadata\n * \n * Metadata loading, saving, and persistence for ObjectStack\n */\n\n// Main Manager\nexport { MetadataManager, type WatchCallback, type MetadataManagerOptions } from './metadata-manager.js';\n\n// Plugin\nexport { MetadataPlugin } from './plugin.js';\n\n// Loaders\nexport { type MetadataLoader } from './loaders/loader-interface.js';\nexport { MemoryLoader } from './loaders/memory-loader.js';\nexport { RemoteLoader } from './loaders/remote-loader.js';\n\n// Serializers\nexport { type MetadataSerializer, type SerializeOptions } from './serializers/serializer-interface.js';\nexport { JSONSerializer } from './serializers/json-serializer.js';\nexport { YAMLSerializer } from './serializers/yaml-serializer.js';\nexport * as Migration from './migration/index.js';\nexport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\n\n// Re-export types from spec\nexport type {\n MetadataFormat,\n MetadataStats,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataExportOptions,\n MetadataImportOptions,\n MetadataLoadResult,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataCollectionInfo,\n MetadataLoaderContract,\n MetadataManagerConfig,\n} from '@objectstack/spec/system';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Manager\n * \n * Main orchestrator for metadata loading, saving, and persistence.\n * Browser-compatible (Pure).\n */\n\nimport type {\n MetadataManagerConfig,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataFormat,\n} from '@objectstack/spec/system';\nimport { createLogger, type Logger } from '@objectstack/core';\nimport { JSONSerializer } from './serializers/json-serializer.js';\nimport { YAMLSerializer } from './serializers/yaml-serializer.js';\nimport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\nimport type { MetadataSerializer } from './serializers/serializer-interface.js';\nimport type { MetadataLoader } from './loaders/loader-interface.js';\n\n/**\n * Watch callback function\n */\nexport type WatchCallback = (event: MetadataWatchEvent) => void | Promise<void>;\n\nexport interface MetadataManagerOptions extends MetadataManagerConfig {\n loaders?: MetadataLoader[];\n}\n\n/**\n * Main metadata manager class\n */\nexport class MetadataManager {\n private loaders: Map<string, MetadataLoader> = new Map();\n // Protected so subclasses can access serializers if needed\n protected serializers: Map<MetadataFormat, MetadataSerializer>;\n protected logger: Logger;\n protected watchCallbacks = new Map<string, Set<WatchCallback>>();\n protected config: MetadataManagerOptions;\n\n constructor(config: MetadataManagerOptions) {\n this.config = config;\n this.logger = createLogger({ level: 'info', format: 'pretty' });\n\n // Initialize serializers\n this.serializers = new Map();\n const formats = config.formats || ['typescript', 'json', 'yaml'];\n\n if (formats.includes('json')) {\n this.serializers.set('json', new JSONSerializer());\n }\n if (formats.includes('yaml')) {\n this.serializers.set('yaml', new YAMLSerializer());\n }\n if (formats.includes('typescript')) {\n this.serializers.set('typescript', new TypeScriptSerializer('typescript'));\n }\n if (formats.includes('javascript')) {\n this.serializers.set('javascript', new TypeScriptSerializer('javascript'));\n }\n\n // Initialize Loaders\n if (config.loaders && config.loaders.length > 0) {\n config.loaders.forEach(loader => this.registerLoader(loader));\n }\n // Note: No default loader in base class. Subclasses (NodeMetadataManager) or caller must provide one.\n }\n\n /**\n * Register a new metadata loader (data source)\n */\n registerLoader(loader: MetadataLoader) {\n this.loaders.set(loader.contract.name, loader);\n this.logger.info(`Registered metadata loader: ${loader.contract.name} (${loader.contract.protocol})`);\n }\n\n /**\n * Load a single metadata item\n * Iterates through registered loaders until found\n */\n async load<T = any>(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<T | null> {\n // Priority: Database > Filesystem (Implementation-dependent)\n // For now, we just iterate.\n for (const loader of this.loaders.values()) {\n try {\n const result = await loader.load(type, name, options);\n if (result.data) {\n return result.data as T;\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to load ${type}:${name}`, { error: e });\n }\n }\n return null;\n }\n\n /**\n * Load multiple metadata items\n * Aggregates results from all loaders\n */\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const results: T[] = [];\n\n for (const loader of this.loaders.values()) {\n try {\n const items = await loader.loadMany<T>(type, options);\n for (const item of items) {\n // TODO: Deduplicate based on 'name' if property exists\n results.push(item);\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to loadMany ${type}`, { error: e });\n }\n }\n return results;\n }\n\n /**\n * Save metadata to disk\n */\n /**\n * Save metadata item\n */\n async save<T = any>(\n type: string,\n name: string,\n data: T,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const targetLoader = (options as any)?.loader;\n\n // Find suitable loader\n let loader: MetadataLoader | undefined;\n \n if (targetLoader) {\n loader = this.loaders.get(targetLoader);\n if (!loader) {\n throw new Error(`Loader not found: ${targetLoader}`);\n }\n } else {\n // 1. Try to find existing writable loader containing this item (Update existing)\n for (const l of this.loaders.values()) {\n // Skip if loader is strictly read-only\n if (!l.save) continue;\n \n try {\n if (await l.exists(type, name)) {\n loader = l;\n this.logger.info(`Updating existing metadata in loader: ${l.contract.name}`);\n break;\n }\n } catch (e) {\n // Ignore existence check errors (e.g. network down)\n }\n }\n\n // 2. Default to 'filesystem' if available (Create new)\n if (!loader) {\n const fsLoader = this.loaders.get('filesystem');\n if (fsLoader && fsLoader.save) {\n loader = fsLoader;\n }\n }\n\n // 3. Fallback to any writable loader\n if (!loader) {\n for (const l of this.loaders.values()) {\n if (l.save) {\n loader = l;\n break;\n }\n }\n }\n }\n\n if (!loader) {\n throw new Error(`No loader available for saving type: ${type}`);\n }\n\n if (!loader.save) {\n throw new Error(`Loader '${loader.contract?.name}' does not support saving`);\n }\n\n return loader.save(type, name, data, options);\n }\n\n /**\n * Check if metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n for (const loader of this.loaders.values()) {\n if (await loader.exists(type, name)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<string[]> {\n const items = new Set<string>();\n for (const loader of this.loaders.values()) {\n const result = await loader.list(type);\n result.forEach(item => items.add(item));\n }\n return Array.from(items);\n }\n\n /**\n * Watch for metadata changes\n */\n watch(type: string, callback: WatchCallback): void {\n if (!this.watchCallbacks.has(type)) {\n this.watchCallbacks.set(type, new Set());\n }\n this.watchCallbacks.get(type)!.add(callback);\n }\n\n /**\n * Unwatch metadata changes\n */\n unwatch(type: string, callback: WatchCallback): void {\n const callbacks = this.watchCallbacks.get(type);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.watchCallbacks.delete(type);\n }\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n // Override in subclass\n }\n\n protected notifyWatchers(type: string, event: MetadataWatchEvent) {\n const callbacks = this.watchCallbacks.get(type);\n if (!callbacks) return;\n \n for (const callback of callbacks) {\n try {\n void callback(event);\n } catch (error) {\n this.logger.error('Watch callback error', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * JSON Metadata Serializer\n * \n * Handles JSON format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class JSONSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2, sortKeys = false } = options || {};\n\n if (sortKeys) {\n // Sort keys recursively\n const sorted = this.sortObjectKeys(item);\n return prettify\n ? JSON.stringify(sorted, null, indent)\n : JSON.stringify(sorted);\n }\n\n return prettify\n ? JSON.stringify(item, null, indent)\n : JSON.stringify(item);\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n const parsed = JSON.parse(content);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.json';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'json';\n }\n\n getFormat(): MetadataFormat {\n return 'json';\n }\n\n /**\n * Recursively sort object keys\n */\n private sortObjectKeys(obj: any): any {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => this.sortObjectKeys(item));\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = this.sortObjectKeys(obj[key]);\n }\n\n return sorted;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * YAML Metadata Serializer\n * \n * Handles YAML format serialization and deserialization\n */\n\nimport * as yaml from 'js-yaml';\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class YAMLSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { indent = 2, sortKeys = false } = options || {};\n\n return yaml.dump(item, {\n indent,\n sortKeys,\n lineWidth: -1, // Disable line wrapping\n noRefs: true, // Disable YAML references\n });\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // Use JSON_SCHEMA to prevent arbitrary code execution\n // This restricts YAML to JSON-compatible types only\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.yaml';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'yaml';\n }\n\n getFormat(): MetadataFormat {\n return 'yaml';\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * TypeScript/JavaScript Metadata Serializer\n * \n * Handles TypeScript/JavaScript module format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class TypeScriptSerializer implements MetadataSerializer {\n constructor(private format: 'typescript' | 'javascript' = 'typescript') {}\n\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2 } = options || {};\n\n const jsonStr = JSON.stringify(item, null, prettify ? indent : 0);\n \n if (this.format === 'typescript') {\n return `import type { ServiceObject } from '@objectstack/spec/data';\\n\\n` +\n `export const metadata: ServiceObject = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n } else {\n return `export const metadata = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n }\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // For TypeScript/JavaScript files, we need to extract the exported object\n // Note: This is a simplified parser that works with JSON-like object literals\n // For complex TypeScript with nested objects, consider using a proper TypeScript parser\n \n // Try to find the object literal in various export patterns\n // Pattern 1: export const metadata = {...};\n let objectStart = content.indexOf('export const');\n if (objectStart === -1) {\n // Pattern 2: export default {...};\n objectStart = content.indexOf('export default');\n }\n \n if (objectStart === -1) {\n throw new Error(\n 'Could not parse TypeScript/JavaScript module. ' +\n 'Expected export pattern: \"export const metadata = {...};\" or \"export default {...};\"'\n );\n }\n\n // Find the first opening brace after the export statement\n const braceStart = content.indexOf('{', objectStart);\n if (braceStart === -1) {\n throw new Error('Could not find object literal in export statement');\n }\n\n // Find the matching closing brace by counting braces\n // Handle string literals to avoid counting braces inside strings\n let braceCount = 0;\n let braceEnd = -1;\n let inString = false;\n let stringChar = '';\n \n for (let i = braceStart; i < content.length; i++) {\n const char = content[i];\n const prevChar = i > 0 ? content[i - 1] : '';\n \n // Track string literals (simple handling of \" and ')\n if ((char === '\"' || char === \"'\") && prevChar !== '\\\\') {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n \n // Count braces only when not inside strings\n if (!inString) {\n if (char === '{') braceCount++;\n if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n braceEnd = i;\n break;\n }\n }\n }\n }\n\n if (braceEnd === -1) {\n throw new Error('Could not find matching closing brace for object literal');\n }\n\n // Extract the object literal\n const objectLiteral = content.substring(braceStart, braceEnd + 1);\n\n try {\n // Parse as JSON\n const parsed = JSON.parse(objectLiteral);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n } catch (error) {\n throw new Error(\n `Failed to parse object literal as JSON: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Make sure the TypeScript/JavaScript object uses JSON-compatible syntax (no functions, comments, or trailing commas).'\n );\n }\n }\n\n getExtension(): string {\n return this.format === 'typescript' ? '.ts' : '.js';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'typescript' || format === 'javascript';\n }\n\n getFormat(): MetadataFormat {\n return this.format;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Node Metadata Manager\n * \n * Extends MetadataManager with Filesystem capabilities (Watching, default loader)\n */\n\nimport * as path from 'node:path';\nimport { watch as chokidarWatch, type FSWatcher } from 'chokidar';\nimport type {\n MetadataWatchEvent,\n} from '@objectstack/spec/system';\nimport { FilesystemLoader } from './loaders/filesystem-loader.js';\nimport { MetadataManager, type MetadataManagerOptions } from './metadata-manager.js';\n\n/**\n * Node metadata manager class\n */\nexport class NodeMetadataManager extends MetadataManager {\n private watcher?: FSWatcher;\n\n constructor(config: MetadataManagerOptions) {\n super(config);\n\n // Initialize Default Filesystem Loader if no loaders provided\n // This logic replaces the removed logic from base class\n if (!config.loaders || config.loaders.length === 0) {\n const rootDir = config.rootDir || process.cwd();\n this.registerLoader(new FilesystemLoader(rootDir, this.serializers, this.logger));\n }\n\n // Start watching if enabled\n if (config.watch) {\n this.startWatching();\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = undefined;\n }\n // Call base cleanup if any\n }\n\n /**\n * Start watching for file changes\n */\n private startWatching(): void {\n const rootDir = this.config.rootDir || process.cwd();\n const { ignored = ['**/node_modules/**', '**/*.test.*'], persistent = true } =\n this.config.watchOptions || {};\n\n this.watcher = chokidarWatch(rootDir, {\n ignored,\n persistent,\n ignoreInitial: true,\n });\n\n this.watcher.on('add', async (filePath) => {\n await this.handleFileEvent('added', filePath);\n });\n\n this.watcher.on('change', async (filePath) => {\n await this.handleFileEvent('changed', filePath);\n });\n\n this.watcher.on('unlink', async (filePath) => {\n await this.handleFileEvent('deleted', filePath);\n });\n\n this.logger.info('File watcher started', { rootDir });\n }\n\n /**\n * Handle file change events\n */\n private async handleFileEvent(\n eventType: 'added' | 'changed' | 'deleted',\n filePath: string\n ): Promise<void> {\n const rootDir = this.config.rootDir || process.cwd();\n const relativePath = path.relative(rootDir, filePath);\n const parts = relativePath.split(path.sep);\n\n if (parts.length < 2) {\n return; // Not a metadata file\n }\n\n const type = parts[0];\n const fileName = parts[parts.length - 1];\n const name = path.basename(fileName, path.extname(fileName));\n\n // We can't access private watchCallbacks from parent.\n // We need a protected method to trigger watch event or access it.\n // OPTION: Add a method `triggerWatchEvent` to MetadataManager\n \n let data: any = undefined;\n if (eventType !== 'deleted') {\n try {\n data = await this.load(type, name, { useCache: false });\n } catch (error) {\n this.logger.error('Failed to load changed file', undefined, {\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const event: MetadataWatchEvent = {\n type: eventType,\n metadataType: type,\n name,\n path: filePath,\n data,\n timestamp: new Date(),\n };\n\n this.notifyWatchers(type, event);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Filesystem Metadata Loader\n * \n * Loads metadata from the filesystem using glob patterns\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { glob } from 'glob';\nimport { createHash } from 'node:crypto';\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataFormat,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { Logger } from '@objectstack/core';\nimport type { MetadataLoader } from './loader-interface.js';\nimport type { MetadataSerializer } from '../serializers/serializer-interface.js';\n\nexport class FilesystemLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'filesystem',\n protocol: 'file',\n capabilities: {\n read: true,\n write: true,\n watch: true,\n list: true,\n },\n supportedFormats: ['json', 'yaml', 'typescript', 'javascript'],\n supportsWatch: true,\n supportsWrite: true,\n supportsCache: true,\n };\n\n private cache = new Map<string, { data: any; etag: string; timestamp: number }>();\n\n constructor(\n private rootDir: string,\n private serializers: Map<MetadataFormat, MetadataSerializer>,\n private logger?: Logger\n ) {}\n\n async load(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const startTime = Date.now();\n const { validate: _validate = true, useCache = true, ifNoneMatch } = options || {};\n\n try {\n // Find the file\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Get stats\n const stats = await this.stat(type, name);\n\n if (!stats) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check cache\n if (useCache && ifNoneMatch && stats.etag === ifNoneMatch) {\n return {\n data: null,\n fromCache: true,\n notModified: true,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check memory cache\n const cacheKey = `${type}:${name}`;\n if (useCache && this.cache.has(cacheKey)) {\n const cached = this.cache.get(cacheKey)!;\n if (cached.etag === stats.etag) {\n return {\n data: cached.data,\n fromCache: true,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n }\n\n // Load and deserialize\n const content = await fs.readFile(filePath, 'utf-8');\n const serializer = this.getSerializer(stats.format!);\n\n if (!serializer) {\n throw new Error(`No serializer found for format: ${stats.format}`);\n }\n\n const data = serializer.deserialize(content);\n\n // Update cache\n if (useCache) {\n this.cache.set(cacheKey, {\n data,\n etag: stats.etag || '',\n timestamp: Date.now(),\n });\n }\n\n return {\n data,\n fromCache: false,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to load metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const { patterns = ['**/*'], recursive: _recursive = true, limit } = options || {};\n\n const typeDir = path.join(this.rootDir, type);\n const items: T[] = [];\n\n try {\n // Build glob patterns\n const globPatterns = patterns.map(pattern =>\n path.join(typeDir, pattern)\n );\n\n for (const pattern of globPatterns) {\n const files = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n for (const file of files) {\n if (limit && items.length >= limit) {\n break;\n }\n\n try {\n const content = await fs.readFile(file, 'utf-8');\n const format = this.detectFormat(file);\n const serializer = this.getSerializer(format);\n\n if (serializer) {\n const data = serializer.deserialize<T>(content);\n items.push(data);\n }\n } catch (error) {\n this.logger?.warn('Failed to load file', {\n file,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (limit && items.length >= limit) {\n break;\n }\n }\n\n return items;\n } catch (error) {\n this.logger?.error('Failed to load many', undefined, {\n type,\n patterns,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const filePath = await this.findFile(type, name);\n return filePath !== null;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return null;\n }\n\n try {\n const stats = await fs.stat(filePath);\n const content = await fs.readFile(filePath, 'utf-8');\n const etag = this.generateETag(content);\n const format = this.detectFormat(filePath);\n\n return {\n size: stats.size,\n modifiedAt: stats.mtime,\n etag,\n format,\n path: filePath,\n };\n } catch (error) {\n this.logger?.error('Failed to stat file', undefined, {\n type,\n name,\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n\n async list(type: string): Promise<string[]> {\n const typeDir = path.join(this.rootDir, type);\n\n try {\n const files = await glob('**/*', {\n cwd: typeDir,\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n return files.map(file => {\n const ext = path.extname(file);\n const basename = path.basename(file, ext);\n return basename;\n });\n } catch (error) {\n this.logger?.error('Failed to list', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n return [];\n }\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const startTime = Date.now();\n const {\n format = 'typescript',\n prettify = true,\n indent = 2,\n sortKeys = false,\n backup = false,\n overwrite = true,\n atomic = true,\n path: customPath,\n } = options || {};\n\n try {\n // Get serializer\n const serializer = this.getSerializer(format);\n if (!serializer) {\n throw new Error(`No serializer found for format: ${format}`);\n }\n\n // Determine file path\n const typeDir = path.join(this.rootDir, type);\n const fileName = `${name}${serializer.getExtension()}`;\n const filePath = customPath || path.join(typeDir, fileName);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await fs.access(filePath);\n throw new Error(`File already exists: ${filePath}`);\n } catch (error) {\n // File doesn't exist, continue\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n // Create directory if it doesn't exist\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n // Create backup if requested\n let backupPath: string | undefined;\n if (backup) {\n try {\n await fs.access(filePath);\n backupPath = `${filePath}.bak`;\n await fs.copyFile(filePath, backupPath);\n } catch {\n // File doesn't exist, no backup needed\n }\n }\n\n // Serialize data\n const content = serializer.serialize(data, {\n prettify,\n indent,\n sortKeys,\n });\n\n // Write to disk (atomic or direct)\n if (atomic) {\n const tempPath = `${filePath}.tmp`;\n await fs.writeFile(tempPath, content, 'utf-8');\n await fs.rename(tempPath, filePath);\n } else {\n await fs.writeFile(filePath, content, 'utf-8');\n }\n\n // Update cache logic if needed (e.g., invalidate or update)\n // For now, we rely on the watcher to pick up changes\n\n return {\n success: true,\n path: filePath,\n // format, // Not in schema\n size: Buffer.byteLength(content, 'utf-8'),\n backupPath,\n saveTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to save metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Find file for a given type and name\n */\n private async findFile(type: string, name: string): Promise<string | null> {\n const typeDir = path.join(this.rootDir, type);\n const extensions = ['.json', '.yaml', '.yml', '.ts', '.js'];\n\n for (const ext of extensions) {\n const filePath = path.join(typeDir, `${name}${ext}`);\n\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, try next extension\n }\n }\n\n return null;\n }\n\n /**\n * Detect format from file extension\n */\n private detectFormat(filePath: string): MetadataFormat {\n const ext = path.extname(filePath).toLowerCase();\n\n switch (ext) {\n case '.json':\n return 'json';\n case '.yaml':\n case '.yml':\n return 'yaml';\n case '.ts':\n return 'typescript';\n case '.js':\n return 'javascript';\n default:\n return 'json'; // Default to JSON\n }\n }\n\n /**\n * Get serializer for format\n */\n private getSerializer(format: MetadataFormat): MetadataSerializer | undefined {\n return this.serializers.get(format);\n }\n\n /**\n * Generate ETag for content\n * Uses SHA-256 hash truncated to 32 characters for reasonable collision resistance\n * while keeping ETag headers compact (full 64-char hash is overkill for this use case)\n */\n private generateETag(content: string): string {\n const hash = createHash('sha256').update(content).digest('hex').substring(0, 32);\n return `\"${hash}\"`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { NodeMetadataManager } from './node-metadata-manager.js';\nimport { ObjectStackDefinitionSchema } from '@objectstack/spec';\n\nexport interface MetadataPluginOptions {\n rootDir?: string;\n watch?: boolean;\n}\n\nexport class MetadataPlugin implements Plugin {\n name = 'com.objectstack.metadata';\n type = 'standard';\n version = '1.0.0';\n \n private manager: NodeMetadataManager;\n private options: MetadataPluginOptions;\n\n constructor(options: MetadataPluginOptions = {}) {\n this.options = {\n watch: true,\n ...options\n };\n\n const rootDir = this.options.rootDir || process.cwd();\n\n this.manager = new NodeMetadataManager({ \n rootDir,\n watch: this.options.watch ?? true,\n formats: ['yaml', 'json', 'typescript', 'javascript'] \n });\n }\n\n init = async (ctx: PluginContext) => {\n ctx.logger.info('Initializing Metadata Manager', { root: this.options.rootDir || process.cwd() });\n \n // Register Metadata Manager as a service\n // This allows other plugins to query raw metadata or listen to changes\n ctx.registerService('metadata', this.manager);\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('Loading metadata...');\n \n // Define metadata types directly from the Protocol Definition\n // This ensures the loader is always in sync with the Spec\n const metadataTypes = Object.keys(ObjectStackDefinitionSchema.shape)\n .filter(key => key !== 'manifest'); // Manifest is handled separately\n\n for (const type of metadataTypes) {\n try {\n // Try to load metadata of this type\n const items = await this.manager.loadMany(type, {\n recursive: true\n });\n\n if (items.length > 0) {\n ctx.logger.info(`Loaded ${items.length} ${type}`);\n \n // Helper: Register with ObjectQL Registry\n const ql = ctx.getService('objectql') as any;\n if (ql && ql.registry) {\n items.forEach((item: any) => {\n // Determine key field (id or name)\n const keyField = item.id ? 'id' : 'name';\n \n // Map plural type to singular/registry type if needed\n // For now, we use the singular form for standard types: \n // objects -> object, apps -> app, etc.\n // But Registry seems to accept arbitrary strings.\n // To match Protocol standard, we might want to normalize.\n // Let's use the directory name (plural) as the type for now,\n // OR map 'objects' -> 'object' specifically.\n \n let registryType = type;\n if (type === 'objects') registryType = 'object';\n if (type === 'apps') registryType = 'app';\n if (type === 'plugins') registryType = 'plugin';\n if (type === 'functions') registryType = 'function';\n \n ql.registry.registerItem(registryType, item, keyField);\n });\n }\n }\n } catch (e: any) {\n // Ignore missing directories or errors\n // ctx.logger.debug(`No metadata found for type: ${type}`);\n }\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Memory Metadata Loader\n * \n * Stores metadata in memory only. Changes are lost when process restarts.\n * Useful for testing, temporary overrides, or \"dirty\" edits.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class MemoryLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'memory',\n protocol: 'memory',\n capabilities: {\n read: true,\n write: true,\n watch: false,\n list: true,\n },\n };\n\n // Storage: Type -> Name -> Data\n private storage = new Map<string, Map<string, any>>();\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const typeStore = this.storage.get(type);\n const data = typeStore?.get(name);\n\n if (data) {\n return {\n data,\n source: 'memory',\n format: 'json',\n loadTime: 0,\n };\n }\n\n return { data: null };\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.values()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n return this.storage.get(type)?.has(name) ?? false;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n if (await this.exists(type, name)) {\n return {\n size: 0, // In-memory\n mtime: new Date().toISOString(),\n format: 'json',\n };\n }\n return null;\n }\n\n async list(type: string): Promise<string[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.keys());\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n if (!this.storage.has(type)) {\n this.storage.set(type, new Map());\n }\n \n this.storage.get(type)!.set(name, data);\n\n return {\n success: true,\n path: `memory://${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Remote Metadata Loader\n * \n * Loads metadata from an HTTP API.\n * This loader is stateless and delegates storage to the remote server.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class RemoteLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'remote',\n protocol: 'http',\n capabilities: {\n read: true,\n write: true,\n watch: false, // Could implement SSE/WebSocket in future\n list: true,\n },\n };\n\n constructor(private baseUrl: string, private authToken?: string) {}\n\n private get headers() {\n return {\n 'Content-Type': 'application/json',\n ...(this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}),\n };\n }\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n try {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (response.status === 404) {\n return { data: null };\n }\n\n if (!response.ok) {\n throw new Error(`Remote load failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n data,\n source: this.baseUrl,\n format: 'json',\n loadTime: 0, \n };\n } catch (error) {\n console.error(`RemoteLoader error loading ${type}/${name}`, error);\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const response = await fetch(`${this.baseUrl}/${type}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (!response.ok) {\n return [];\n }\n\n return (await response.json()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n return response.ok;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n // Basic implementation using HEAD\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n \n if (!response.ok) return null;\n\n return {\n size: Number(response.headers.get('content-length') || 0),\n mtime: new Date(response.headers.get('last-modified') || Date.now()).toISOString(),\n format: 'json',\n };\n }\n\n async list(type: string): Promise<string[]> {\n const items = await this.loadMany<{ name: string }>(type);\n return items.map(i => i.name);\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'PUT',\n headers: this.headers,\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n throw new Error(`Remote save failed: ${response.statusText}`);\n }\n\n return {\n success: true,\n path: `${this.baseUrl}/${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './executor.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { System } from '@objectstack/spec';\nimport { ISchemaDriver } from '@objectstack/spec/contracts';\n\nexport class MigrationExecutor {\n constructor(private driver: ISchemaDriver) {}\n\n async executeChangeSet(changeSet: System.ChangeSet): Promise<void> {\n console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);\n \n for (const op of changeSet.operations) {\n try {\n await this.executeOperation(op);\n } catch (e) {\n console.error(`Failed to execute operation ${op.type}:`, e);\n throw e;\n }\n }\n }\n\n private async executeOperation(op: System.MigrationOperation): Promise<void> {\n switch (op.type) {\n case 'create_object':\n console.log(` > Create Object: ${op.object.name}`);\n await this.driver.createCollection(op.object.name, op.object);\n break;\n case 'add_field':\n console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.addColumn(op.objectName, op.fieldName, op.field);\n break;\n case 'remove_field':\n console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.dropColumn(op.objectName, op.fieldName);\n break;\n case 'delete_object':\n console.log(` > Delete Object: ${op.objectName}`);\n await this.driver.dropCollection(op.objectName);\n break;\n case 'execute_sql':\n console.log(` > Execute SQL`);\n await this.driver.executeRaw(op.sql);\n break;\n case 'modify_field':\n console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);\n break;\n case 'rename_object':\n console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);\n break;\n default:\n throw new Error(`Unknown operation type`);\n }\n }\n}\n"],"mappings":"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","names":["path","basename","chokidarWatch"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/metadata-manager.ts","../src/serializers/json-serializer.ts","../src/serializers/yaml-serializer.ts","../src/serializers/typescript-serializer.ts","../src/node-metadata-manager.ts","../src/loaders/filesystem-loader.ts","../src/plugin.ts","../src/loaders/memory-loader.ts","../src/loaders/remote-loader.ts","../src/migration/index.ts","../src/migration/executor.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/metadata\n * \n * Metadata loading, saving, and persistence for ObjectStack\n */\n\n// Main Manager\nexport { MetadataManager, type WatchCallback, type MetadataManagerOptions } from './metadata-manager.js';\n\n// Plugin\nexport { MetadataPlugin } from './plugin.js';\n\n// Loaders\nexport { type MetadataLoader } from './loaders/loader-interface.js';\nexport { MemoryLoader } from './loaders/memory-loader.js';\nexport { RemoteLoader } from './loaders/remote-loader.js';\n\n// Serializers\nexport { type MetadataSerializer, type SerializeOptions } from './serializers/serializer-interface.js';\nexport { JSONSerializer } from './serializers/json-serializer.js';\nexport { YAMLSerializer } from './serializers/yaml-serializer.js';\nexport * as Migration from './migration/index.js';\nexport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\n\n// Re-export types from spec\nexport type {\n MetadataFormat,\n MetadataStats,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataExportOptions,\n MetadataImportOptions,\n MetadataLoadResult,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataCollectionInfo,\n MetadataLoaderContract,\n MetadataManagerConfig,\n} from '@objectstack/spec/system';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Manager\n * \n * Main orchestrator for metadata loading, saving, and persistence.\n * Browser-compatible (Pure).\n */\n\nimport type {\n MetadataManagerConfig,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataFormat,\n} from '@objectstack/spec/system';\nimport { createLogger, type Logger } from '@objectstack/core';\nimport { JSONSerializer } from './serializers/json-serializer.js';\nimport { YAMLSerializer } from './serializers/yaml-serializer.js';\nimport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\nimport type { MetadataSerializer } from './serializers/serializer-interface.js';\nimport type { MetadataLoader } from './loaders/loader-interface.js';\n\n/**\n * Watch callback function\n */\nexport type WatchCallback = (event: MetadataWatchEvent) => void | Promise<void>;\n\nexport interface MetadataManagerOptions extends MetadataManagerConfig {\n loaders?: MetadataLoader[];\n}\n\n/**\n * Main metadata manager class\n */\nexport class MetadataManager {\n private loaders: Map<string, MetadataLoader> = new Map();\n // Protected so subclasses can access serializers if needed\n protected serializers: Map<MetadataFormat, MetadataSerializer>;\n protected logger: Logger;\n protected watchCallbacks = new Map<string, Set<WatchCallback>>();\n protected config: MetadataManagerOptions;\n\n constructor(config: MetadataManagerOptions) {\n this.config = config;\n this.logger = createLogger({ level: 'info', format: 'pretty' });\n\n // Initialize serializers\n this.serializers = new Map();\n const formats = config.formats || ['typescript', 'json', 'yaml'];\n\n if (formats.includes('json')) {\n this.serializers.set('json', new JSONSerializer());\n }\n if (formats.includes('yaml')) {\n this.serializers.set('yaml', new YAMLSerializer());\n }\n if (formats.includes('typescript')) {\n this.serializers.set('typescript', new TypeScriptSerializer('typescript'));\n }\n if (formats.includes('javascript')) {\n this.serializers.set('javascript', new TypeScriptSerializer('javascript'));\n }\n\n // Initialize Loaders\n if (config.loaders && config.loaders.length > 0) {\n config.loaders.forEach(loader => this.registerLoader(loader));\n }\n // Note: No default loader in base class. Subclasses (NodeMetadataManager) or caller must provide one.\n }\n\n /**\n * Register a new metadata loader (data source)\n */\n registerLoader(loader: MetadataLoader) {\n this.loaders.set(loader.contract.name, loader);\n this.logger.info(`Registered metadata loader: ${loader.contract.name} (${loader.contract.protocol})`);\n }\n\n /**\n * Load a single metadata item\n * Iterates through registered loaders until found\n */\n async load<T = any>(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<T | null> {\n // Priority: Database > Filesystem (Implementation-dependent)\n // For now, we just iterate.\n for (const loader of this.loaders.values()) {\n try {\n const result = await loader.load(type, name, options);\n if (result.data) {\n return result.data as T;\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to load ${type}:${name}`, { error: e });\n }\n }\n return null;\n }\n\n /**\n * Load multiple metadata items\n * Aggregates results from all loaders\n */\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const results: T[] = [];\n\n for (const loader of this.loaders.values()) {\n try {\n const items = await loader.loadMany<T>(type, options);\n for (const item of items) {\n // Deduplicate: skip items whose 'name' already exists in results\n const itemAny = item as any;\n if (itemAny && typeof itemAny.name === 'string') {\n const exists = results.some((r: any) => r && r.name === itemAny.name);\n if (exists) continue;\n }\n results.push(item);\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to loadMany ${type}`, { error: e });\n }\n }\n return results;\n }\n\n /**\n * Save metadata to disk\n */\n /**\n * Save metadata item\n */\n async save<T = any>(\n type: string,\n name: string,\n data: T,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const targetLoader = (options as any)?.loader;\n\n // Find suitable loader\n let loader: MetadataLoader | undefined;\n \n if (targetLoader) {\n loader = this.loaders.get(targetLoader);\n if (!loader) {\n throw new Error(`Loader not found: ${targetLoader}`);\n }\n } else {\n // 1. Try to find existing writable loader containing this item (Update existing)\n for (const l of this.loaders.values()) {\n // Skip if loader is strictly read-only\n if (!l.save) continue;\n \n try {\n if (await l.exists(type, name)) {\n loader = l;\n this.logger.info(`Updating existing metadata in loader: ${l.contract.name}`);\n break;\n }\n } catch (e) {\n // Ignore existence check errors (e.g. network down)\n }\n }\n\n // 2. Default to 'filesystem' if available (Create new)\n if (!loader) {\n const fsLoader = this.loaders.get('filesystem');\n if (fsLoader && fsLoader.save) {\n loader = fsLoader;\n }\n }\n\n // 3. Fallback to any writable loader\n if (!loader) {\n for (const l of this.loaders.values()) {\n if (l.save) {\n loader = l;\n break;\n }\n }\n }\n }\n\n if (!loader) {\n throw new Error(`No loader available for saving type: ${type}`);\n }\n\n if (!loader.save) {\n throw new Error(`Loader '${loader.contract?.name}' does not support saving`);\n }\n\n return loader.save(type, name, data, options);\n }\n\n /**\n * Check if metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n for (const loader of this.loaders.values()) {\n if (await loader.exists(type, name)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<string[]> {\n const items = new Set<string>();\n for (const loader of this.loaders.values()) {\n const result = await loader.list(type);\n result.forEach(item => items.add(item));\n }\n return Array.from(items);\n }\n\n /**\n * Watch for metadata changes\n */\n watch(type: string, callback: WatchCallback): void {\n if (!this.watchCallbacks.has(type)) {\n this.watchCallbacks.set(type, new Set());\n }\n this.watchCallbacks.get(type)!.add(callback);\n }\n\n /**\n * Unwatch metadata changes\n */\n unwatch(type: string, callback: WatchCallback): void {\n const callbacks = this.watchCallbacks.get(type);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.watchCallbacks.delete(type);\n }\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n // Override in subclass\n }\n\n protected notifyWatchers(type: string, event: MetadataWatchEvent) {\n const callbacks = this.watchCallbacks.get(type);\n if (!callbacks) return;\n \n for (const callback of callbacks) {\n try {\n void callback(event);\n } catch (error) {\n this.logger.error('Watch callback error', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * JSON Metadata Serializer\n * \n * Handles JSON format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class JSONSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2, sortKeys = false } = options || {};\n\n if (sortKeys) {\n // Sort keys recursively\n const sorted = this.sortObjectKeys(item);\n return prettify\n ? JSON.stringify(sorted, null, indent)\n : JSON.stringify(sorted);\n }\n\n return prettify\n ? JSON.stringify(item, null, indent)\n : JSON.stringify(item);\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n const parsed = JSON.parse(content);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.json';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'json';\n }\n\n getFormat(): MetadataFormat {\n return 'json';\n }\n\n /**\n * Recursively sort object keys\n */\n private sortObjectKeys(obj: any): any {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => this.sortObjectKeys(item));\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = this.sortObjectKeys(obj[key]);\n }\n\n return sorted;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * YAML Metadata Serializer\n * \n * Handles YAML format serialization and deserialization\n */\n\nimport * as yaml from 'js-yaml';\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class YAMLSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { indent = 2, sortKeys = false } = options || {};\n\n return yaml.dump(item, {\n indent,\n sortKeys,\n lineWidth: -1, // Disable line wrapping\n noRefs: true, // Disable YAML references\n });\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // Use JSON_SCHEMA to prevent arbitrary code execution\n // This restricts YAML to JSON-compatible types only\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.yaml';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'yaml';\n }\n\n getFormat(): MetadataFormat {\n return 'yaml';\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * TypeScript/JavaScript Metadata Serializer\n * \n * Handles TypeScript/JavaScript module format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class TypeScriptSerializer implements MetadataSerializer {\n constructor(private format: 'typescript' | 'javascript' = 'typescript') {}\n\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2 } = options || {};\n\n const jsonStr = JSON.stringify(item, null, prettify ? indent : 0);\n \n if (this.format === 'typescript') {\n return `import type { ServiceObject } from '@objectstack/spec/data';\\n\\n` +\n `export const metadata: ServiceObject = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n } else {\n return `export const metadata = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n }\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // For TypeScript/JavaScript files, we need to extract the exported object\n // Note: This is a simplified parser that works with JSON-like object literals\n // For complex TypeScript with nested objects, consider using a proper TypeScript parser\n \n // Try to find the object literal in various export patterns\n // Pattern 1: export const metadata = {...};\n let objectStart = content.indexOf('export const');\n if (objectStart === -1) {\n // Pattern 2: export default {...};\n objectStart = content.indexOf('export default');\n }\n \n if (objectStart === -1) {\n throw new Error(\n 'Could not parse TypeScript/JavaScript module. ' +\n 'Expected export pattern: \"export const metadata = {...};\" or \"export default {...};\"'\n );\n }\n\n // Find the first opening brace after the export statement\n const braceStart = content.indexOf('{', objectStart);\n if (braceStart === -1) {\n throw new Error('Could not find object literal in export statement');\n }\n\n // Find the matching closing brace by counting braces\n // Handle string literals to avoid counting braces inside strings\n let braceCount = 0;\n let braceEnd = -1;\n let inString = false;\n let stringChar = '';\n \n for (let i = braceStart; i < content.length; i++) {\n const char = content[i];\n const prevChar = i > 0 ? content[i - 1] : '';\n \n // Track string literals (simple handling of \" and ')\n if ((char === '\"' || char === \"'\") && prevChar !== '\\\\') {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n \n // Count braces only when not inside strings\n if (!inString) {\n if (char === '{') braceCount++;\n if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n braceEnd = i;\n break;\n }\n }\n }\n }\n\n if (braceEnd === -1) {\n throw new Error('Could not find matching closing brace for object literal');\n }\n\n // Extract the object literal\n const objectLiteral = content.substring(braceStart, braceEnd + 1);\n\n try {\n // Parse as JSON\n const parsed = JSON.parse(objectLiteral);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n } catch (error) {\n throw new Error(\n `Failed to parse object literal as JSON: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Make sure the TypeScript/JavaScript object uses JSON-compatible syntax (no functions, comments, or trailing commas).'\n );\n }\n }\n\n getExtension(): string {\n return this.format === 'typescript' ? '.ts' : '.js';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'typescript' || format === 'javascript';\n }\n\n getFormat(): MetadataFormat {\n return this.format;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Node Metadata Manager\n * \n * Extends MetadataManager with Filesystem capabilities (Watching, default loader)\n */\n\nimport * as path from 'node:path';\nimport { watch as chokidarWatch, type FSWatcher } from 'chokidar';\nimport type {\n MetadataWatchEvent,\n} from '@objectstack/spec/system';\nimport { FilesystemLoader } from './loaders/filesystem-loader.js';\nimport { MetadataManager, type MetadataManagerOptions } from './metadata-manager.js';\n\n/**\n * Node metadata manager class\n */\nexport class NodeMetadataManager extends MetadataManager {\n private watcher?: FSWatcher;\n\n constructor(config: MetadataManagerOptions) {\n super(config);\n\n // Initialize Default Filesystem Loader if no loaders provided\n // This logic replaces the removed logic from base class\n if (!config.loaders || config.loaders.length === 0) {\n const rootDir = config.rootDir || process.cwd();\n this.registerLoader(new FilesystemLoader(rootDir, this.serializers, this.logger));\n }\n\n // Start watching if enabled\n if (config.watch) {\n this.startWatching();\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = undefined;\n }\n // Call base cleanup if any\n }\n\n /**\n * Start watching for file changes\n */\n private startWatching(): void {\n const rootDir = this.config.rootDir || process.cwd();\n const { ignored = ['**/node_modules/**', '**/*.test.*'], persistent = true } =\n this.config.watchOptions || {};\n\n this.watcher = chokidarWatch(rootDir, {\n ignored,\n persistent,\n ignoreInitial: true,\n });\n\n this.watcher.on('add', async (filePath) => {\n await this.handleFileEvent('added', filePath);\n });\n\n this.watcher.on('change', async (filePath) => {\n await this.handleFileEvent('changed', filePath);\n });\n\n this.watcher.on('unlink', async (filePath) => {\n await this.handleFileEvent('deleted', filePath);\n });\n\n this.logger.info('File watcher started', { rootDir });\n }\n\n /**\n * Handle file change events\n */\n private async handleFileEvent(\n eventType: 'added' | 'changed' | 'deleted',\n filePath: string\n ): Promise<void> {\n const rootDir = this.config.rootDir || process.cwd();\n const relativePath = path.relative(rootDir, filePath);\n const parts = relativePath.split(path.sep);\n\n if (parts.length < 2) {\n return; // Not a metadata file\n }\n\n const type = parts[0];\n const fileName = parts[parts.length - 1];\n const name = path.basename(fileName, path.extname(fileName));\n\n // We can't access private watchCallbacks from parent.\n // We need a protected method to trigger watch event or access it.\n // OPTION: Add a method `triggerWatchEvent` to MetadataManager\n \n let data: any = undefined;\n if (eventType !== 'deleted') {\n try {\n data = await this.load(type, name, { useCache: false });\n } catch (error) {\n this.logger.error('Failed to load changed file', undefined, {\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const event: MetadataWatchEvent = {\n type: eventType,\n metadataType: type,\n name,\n path: filePath,\n data,\n timestamp: new Date(),\n };\n\n this.notifyWatchers(type, event);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Filesystem Metadata Loader\n * \n * Loads metadata from the filesystem using glob patterns\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { glob } from 'glob';\nimport { createHash } from 'node:crypto';\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataFormat,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { Logger } from '@objectstack/core';\nimport type { MetadataLoader } from './loader-interface.js';\nimport type { MetadataSerializer } from '../serializers/serializer-interface.js';\n\nexport class FilesystemLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'filesystem',\n protocol: 'file',\n capabilities: {\n read: true,\n write: true,\n watch: true,\n list: true,\n },\n supportedFormats: ['json', 'yaml', 'typescript', 'javascript'],\n supportsWatch: true,\n supportsWrite: true,\n supportsCache: true,\n };\n\n private cache = new Map<string, { data: any; etag: string; timestamp: number }>();\n\n constructor(\n private rootDir: string,\n private serializers: Map<MetadataFormat, MetadataSerializer>,\n private logger?: Logger\n ) {}\n\n async load(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const startTime = Date.now();\n const { validate: _validate = true, useCache = true, ifNoneMatch } = options || {};\n\n try {\n // Find the file\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Get stats\n const stats = await this.stat(type, name);\n\n if (!stats) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check cache\n if (useCache && ifNoneMatch && stats.etag === ifNoneMatch) {\n return {\n data: null,\n fromCache: true,\n notModified: true,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check memory cache\n const cacheKey = `${type}:${name}`;\n if (useCache && this.cache.has(cacheKey)) {\n const cached = this.cache.get(cacheKey)!;\n if (cached.etag === stats.etag) {\n return {\n data: cached.data,\n fromCache: true,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n }\n\n // Load and deserialize\n const content = await fs.readFile(filePath, 'utf-8');\n const serializer = this.getSerializer(stats.format!);\n\n if (!serializer) {\n throw new Error(`No serializer found for format: ${stats.format}`);\n }\n\n const data = serializer.deserialize(content);\n\n // Update cache\n if (useCache) {\n this.cache.set(cacheKey, {\n data,\n etag: stats.etag || '',\n timestamp: Date.now(),\n });\n }\n\n return {\n data,\n fromCache: false,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to load metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const { patterns = ['**/*'], recursive: _recursive = true, limit } = options || {};\n\n const typeDir = path.join(this.rootDir, type);\n const items: T[] = [];\n\n try {\n // Build glob patterns\n const globPatterns = patterns.map(pattern =>\n path.join(typeDir, pattern)\n );\n\n for (const pattern of globPatterns) {\n const files = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n for (const file of files) {\n if (limit && items.length >= limit) {\n break;\n }\n\n try {\n const content = await fs.readFile(file, 'utf-8');\n const format = this.detectFormat(file);\n const serializer = this.getSerializer(format);\n\n if (serializer) {\n const data = serializer.deserialize<T>(content);\n items.push(data);\n }\n } catch (error) {\n this.logger?.warn('Failed to load file', {\n file,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (limit && items.length >= limit) {\n break;\n }\n }\n\n return items;\n } catch (error) {\n this.logger?.error('Failed to load many', undefined, {\n type,\n patterns,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const filePath = await this.findFile(type, name);\n return filePath !== null;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return null;\n }\n\n try {\n const stats = await fs.stat(filePath);\n const content = await fs.readFile(filePath, 'utf-8');\n const etag = this.generateETag(content);\n const format = this.detectFormat(filePath);\n\n return {\n size: stats.size,\n modifiedAt: stats.mtime,\n etag,\n format,\n path: filePath,\n };\n } catch (error) {\n this.logger?.error('Failed to stat file', undefined, {\n type,\n name,\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n\n async list(type: string): Promise<string[]> {\n const typeDir = path.join(this.rootDir, type);\n\n try {\n const files = await glob('**/*', {\n cwd: typeDir,\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n return files.map(file => {\n const ext = path.extname(file);\n const basename = path.basename(file, ext);\n return basename;\n });\n } catch (error) {\n this.logger?.error('Failed to list', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n return [];\n }\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const startTime = Date.now();\n const {\n format = 'typescript',\n prettify = true,\n indent = 2,\n sortKeys = false,\n backup = false,\n overwrite = true,\n atomic = true,\n path: customPath,\n } = options || {};\n\n try {\n // Get serializer\n const serializer = this.getSerializer(format);\n if (!serializer) {\n throw new Error(`No serializer found for format: ${format}`);\n }\n\n // Determine file path\n const typeDir = path.join(this.rootDir, type);\n const fileName = `${name}${serializer.getExtension()}`;\n const filePath = customPath || path.join(typeDir, fileName);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await fs.access(filePath);\n throw new Error(`File already exists: ${filePath}`);\n } catch (error) {\n // File doesn't exist, continue\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n // Create directory if it doesn't exist\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n // Create backup if requested\n let backupPath: string | undefined;\n if (backup) {\n try {\n await fs.access(filePath);\n backupPath = `${filePath}.bak`;\n await fs.copyFile(filePath, backupPath);\n } catch {\n // File doesn't exist, no backup needed\n }\n }\n\n // Serialize data\n const content = serializer.serialize(data, {\n prettify,\n indent,\n sortKeys,\n });\n\n // Write to disk (atomic or direct)\n if (atomic) {\n const tempPath = `${filePath}.tmp`;\n await fs.writeFile(tempPath, content, 'utf-8');\n await fs.rename(tempPath, filePath);\n } else {\n await fs.writeFile(filePath, content, 'utf-8');\n }\n\n // Update cache logic if needed (e.g., invalidate or update)\n // For now, we rely on the watcher to pick up changes\n\n return {\n success: true,\n path: filePath,\n // format, // Not in schema\n size: Buffer.byteLength(content, 'utf-8'),\n backupPath,\n saveTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to save metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Find file for a given type and name\n */\n private async findFile(type: string, name: string): Promise<string | null> {\n const typeDir = path.join(this.rootDir, type);\n const extensions = ['.json', '.yaml', '.yml', '.ts', '.js'];\n\n for (const ext of extensions) {\n const filePath = path.join(typeDir, `${name}${ext}`);\n\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, try next extension\n }\n }\n\n return null;\n }\n\n /**\n * Detect format from file extension\n */\n private detectFormat(filePath: string): MetadataFormat {\n const ext = path.extname(filePath).toLowerCase();\n\n switch (ext) {\n case '.json':\n return 'json';\n case '.yaml':\n case '.yml':\n return 'yaml';\n case '.ts':\n return 'typescript';\n case '.js':\n return 'javascript';\n default:\n return 'json'; // Default to JSON\n }\n }\n\n /**\n * Get serializer for format\n */\n private getSerializer(format: MetadataFormat): MetadataSerializer | undefined {\n return this.serializers.get(format);\n }\n\n /**\n * Generate ETag for content\n * Uses SHA-256 hash truncated to 32 characters for reasonable collision resistance\n * while keeping ETag headers compact (full 64-char hash is overkill for this use case)\n */\n private generateETag(content: string): string {\n const hash = createHash('sha256').update(content).digest('hex').substring(0, 32);\n return `\"${hash}\"`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { NodeMetadataManager } from './node-metadata-manager.js';\nimport { ObjectStackDefinitionSchema } from '@objectstack/spec';\n\nexport interface MetadataPluginOptions {\n rootDir?: string;\n watch?: boolean;\n}\n\nexport class MetadataPlugin implements Plugin {\n name = 'com.objectstack.metadata';\n type = 'standard';\n version = '1.0.0';\n \n private manager: NodeMetadataManager;\n private options: MetadataPluginOptions;\n\n constructor(options: MetadataPluginOptions = {}) {\n this.options = {\n watch: true,\n ...options\n };\n\n const rootDir = this.options.rootDir || process.cwd();\n\n this.manager = new NodeMetadataManager({ \n rootDir,\n watch: this.options.watch ?? true,\n formats: ['yaml', 'json', 'typescript', 'javascript'] \n });\n }\n\n init = async (ctx: PluginContext) => {\n ctx.logger.info('Initializing Metadata Manager', { root: this.options.rootDir || process.cwd() });\n \n // Register Metadata Manager as a service\n // This allows other plugins to query raw metadata or listen to changes\n ctx.registerService('metadata', this.manager);\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('Loading metadata...');\n \n // Define metadata types directly from the Protocol Definition\n // This ensures the loader is always in sync with the Spec\n const metadataTypes = Object.keys(ObjectStackDefinitionSchema.shape)\n .filter(key => key !== 'manifest'); // Manifest is handled separately\n\n for (const type of metadataTypes) {\n try {\n // Try to load metadata of this type\n const items = await this.manager.loadMany(type, {\n recursive: true\n });\n\n if (items.length > 0) {\n ctx.logger.info(`Loaded ${items.length} ${type}`);\n \n // Helper: Register with ObjectQL Registry\n const ql = ctx.getService('objectql') as any;\n if (ql && ql.registry) {\n items.forEach((item: any) => {\n // Determine key field (id or name)\n const keyField = item.id ? 'id' : 'name';\n \n // Map plural type to singular/registry type if needed\n // For now, we use the singular form for standard types: \n // objects -> object, apps -> app, etc.\n // But Registry seems to accept arbitrary strings.\n // To match Protocol standard, we might want to normalize.\n // Let's use the directory name (plural) as the type for now,\n // OR map 'objects' -> 'object' specifically.\n \n let registryType = type;\n if (type === 'objects') registryType = 'object';\n if (type === 'apps') registryType = 'app';\n if (type === 'plugins') registryType = 'plugin';\n if (type === 'functions') registryType = 'function';\n \n ql.registry.registerItem(registryType, item, keyField);\n });\n }\n }\n } catch (e: any) {\n // Ignore missing directories or errors\n // ctx.logger.debug(`No metadata found for type: ${type}`);\n }\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Memory Metadata Loader\n * \n * Stores metadata in memory only. Changes are lost when process restarts.\n * Useful for testing, temporary overrides, or \"dirty\" edits.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class MemoryLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'memory',\n protocol: 'memory',\n capabilities: {\n read: true,\n write: true,\n watch: false,\n list: true,\n },\n };\n\n // Storage: Type -> Name -> Data\n private storage = new Map<string, Map<string, any>>();\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const typeStore = this.storage.get(type);\n const data = typeStore?.get(name);\n\n if (data) {\n return {\n data,\n source: 'memory',\n format: 'json',\n loadTime: 0,\n };\n }\n\n return { data: null };\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.values()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n return this.storage.get(type)?.has(name) ?? false;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n if (await this.exists(type, name)) {\n return {\n size: 0, // In-memory\n mtime: new Date().toISOString(),\n format: 'json',\n };\n }\n return null;\n }\n\n async list(type: string): Promise<string[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.keys());\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n if (!this.storage.has(type)) {\n this.storage.set(type, new Map());\n }\n \n this.storage.get(type)!.set(name, data);\n\n return {\n success: true,\n path: `memory://${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Remote Metadata Loader\n * \n * Loads metadata from an HTTP API.\n * This loader is stateless and delegates storage to the remote server.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class RemoteLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'remote',\n protocol: 'http',\n capabilities: {\n read: true,\n write: true,\n watch: false, // Could implement SSE/WebSocket in future\n list: true,\n },\n };\n\n constructor(private baseUrl: string, private authToken?: string) {}\n\n private get headers() {\n return {\n 'Content-Type': 'application/json',\n ...(this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}),\n };\n }\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n try {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (response.status === 404) {\n return { data: null };\n }\n\n if (!response.ok) {\n throw new Error(`Remote load failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n data,\n source: this.baseUrl,\n format: 'json',\n loadTime: 0, \n };\n } catch (error) {\n console.error(`RemoteLoader error loading ${type}/${name}`, error);\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const response = await fetch(`${this.baseUrl}/${type}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (!response.ok) {\n return [];\n }\n\n return (await response.json()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n return response.ok;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n // Basic implementation using HEAD\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n \n if (!response.ok) return null;\n\n return {\n size: Number(response.headers.get('content-length') || 0),\n mtime: new Date(response.headers.get('last-modified') || Date.now()).toISOString(),\n format: 'json',\n };\n }\n\n async list(type: string): Promise<string[]> {\n const items = await this.loadMany<{ name: string }>(type);\n return items.map(i => i.name);\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'PUT',\n headers: this.headers,\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n throw new Error(`Remote save failed: ${response.statusText}`);\n }\n\n return {\n success: true,\n path: `${this.baseUrl}/${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './executor.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { System } from '@objectstack/spec';\nimport { ISchemaDriver } from '@objectstack/spec/contracts';\n\nexport class MigrationExecutor {\n constructor(private driver: ISchemaDriver) {}\n\n async executeChangeSet(changeSet: System.ChangeSet): Promise<void> {\n console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);\n \n for (const op of changeSet.operations) {\n try {\n await this.executeOperation(op);\n } catch (e) {\n console.error(`Failed to execute operation ${op.type}:`, e);\n throw e;\n }\n }\n }\n\n private async executeOperation(op: System.MigrationOperation): Promise<void> {\n switch (op.type) {\n case 'create_object':\n console.log(` > Create Object: ${op.object.name}`);\n await this.driver.createCollection(op.object.name, op.object);\n break;\n case 'add_field':\n console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.addColumn(op.objectName, op.fieldName, op.field);\n break;\n case 'remove_field':\n console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.dropColumn(op.objectName, op.fieldName);\n break;\n case 'delete_object':\n console.log(` > Delete Object: ${op.objectName}`);\n await this.driver.dropCollection(op.objectName);\n break;\n case 'execute_sql':\n console.log(` > Execute SQL`);\n await this.driver.executeRaw(op.sql);\n break;\n case 'modify_field':\n console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);\n break;\n case 'rename_object':\n console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);\n break;\n default:\n throw new Error(`Unknown operation type`);\n }\n }\n}\n"],"mappings":"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","names":["path","basename","chokidarWatch"]}
|
package/dist/index.mjs
CHANGED
|
@@ -233,6 +233,11 @@ var MetadataManager = class {
|
|
|
233
233
|
try {
|
|
234
234
|
const items = await loader.loadMany(type, options);
|
|
235
235
|
for (const item of items) {
|
|
236
|
+
const itemAny = item;
|
|
237
|
+
if (itemAny && typeof itemAny.name === "string") {
|
|
238
|
+
const exists = results.some((r) => r && r.name === itemAny.name);
|
|
239
|
+
if (exists) continue;
|
|
240
|
+
}
|
|
236
241
|
results.push(item);
|
|
237
242
|
}
|
|
238
243
|
} catch (e) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metadata-manager.ts","../src/serializers/json-serializer.ts","../src/serializers/yaml-serializer.ts","../src/serializers/typescript-serializer.ts","../src/node-metadata-manager.ts","../src/loaders/filesystem-loader.ts","../src/plugin.ts","../src/loaders/memory-loader.ts","../src/loaders/remote-loader.ts","../src/migration/index.ts","../src/migration/executor.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Manager\n * \n * Main orchestrator for metadata loading, saving, and persistence.\n * Browser-compatible (Pure).\n */\n\nimport type {\n MetadataManagerConfig,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataFormat,\n} from '@objectstack/spec/system';\nimport { createLogger, type Logger } from '@objectstack/core';\nimport { JSONSerializer } from './serializers/json-serializer.js';\nimport { YAMLSerializer } from './serializers/yaml-serializer.js';\nimport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\nimport type { MetadataSerializer } from './serializers/serializer-interface.js';\nimport type { MetadataLoader } from './loaders/loader-interface.js';\n\n/**\n * Watch callback function\n */\nexport type WatchCallback = (event: MetadataWatchEvent) => void | Promise<void>;\n\nexport interface MetadataManagerOptions extends MetadataManagerConfig {\n loaders?: MetadataLoader[];\n}\n\n/**\n * Main metadata manager class\n */\nexport class MetadataManager {\n private loaders: Map<string, MetadataLoader> = new Map();\n // Protected so subclasses can access serializers if needed\n protected serializers: Map<MetadataFormat, MetadataSerializer>;\n protected logger: Logger;\n protected watchCallbacks = new Map<string, Set<WatchCallback>>();\n protected config: MetadataManagerOptions;\n\n constructor(config: MetadataManagerOptions) {\n this.config = config;\n this.logger = createLogger({ level: 'info', format: 'pretty' });\n\n // Initialize serializers\n this.serializers = new Map();\n const formats = config.formats || ['typescript', 'json', 'yaml'];\n\n if (formats.includes('json')) {\n this.serializers.set('json', new JSONSerializer());\n }\n if (formats.includes('yaml')) {\n this.serializers.set('yaml', new YAMLSerializer());\n }\n if (formats.includes('typescript')) {\n this.serializers.set('typescript', new TypeScriptSerializer('typescript'));\n }\n if (formats.includes('javascript')) {\n this.serializers.set('javascript', new TypeScriptSerializer('javascript'));\n }\n\n // Initialize Loaders\n if (config.loaders && config.loaders.length > 0) {\n config.loaders.forEach(loader => this.registerLoader(loader));\n }\n // Note: No default loader in base class. Subclasses (NodeMetadataManager) or caller must provide one.\n }\n\n /**\n * Register a new metadata loader (data source)\n */\n registerLoader(loader: MetadataLoader) {\n this.loaders.set(loader.contract.name, loader);\n this.logger.info(`Registered metadata loader: ${loader.contract.name} (${loader.contract.protocol})`);\n }\n\n /**\n * Load a single metadata item\n * Iterates through registered loaders until found\n */\n async load<T = any>(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<T | null> {\n // Priority: Database > Filesystem (Implementation-dependent)\n // For now, we just iterate.\n for (const loader of this.loaders.values()) {\n try {\n const result = await loader.load(type, name, options);\n if (result.data) {\n return result.data as T;\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to load ${type}:${name}`, { error: e });\n }\n }\n return null;\n }\n\n /**\n * Load multiple metadata items\n * Aggregates results from all loaders\n */\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const results: T[] = [];\n\n for (const loader of this.loaders.values()) {\n try {\n const items = await loader.loadMany<T>(type, options);\n for (const item of items) {\n // TODO: Deduplicate based on 'name' if property exists\n results.push(item);\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to loadMany ${type}`, { error: e });\n }\n }\n return results;\n }\n\n /**\n * Save metadata to disk\n */\n /**\n * Save metadata item\n */\n async save<T = any>(\n type: string,\n name: string,\n data: T,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const targetLoader = (options as any)?.loader;\n\n // Find suitable loader\n let loader: MetadataLoader | undefined;\n \n if (targetLoader) {\n loader = this.loaders.get(targetLoader);\n if (!loader) {\n throw new Error(`Loader not found: ${targetLoader}`);\n }\n } else {\n // 1. Try to find existing writable loader containing this item (Update existing)\n for (const l of this.loaders.values()) {\n // Skip if loader is strictly read-only\n if (!l.save) continue;\n \n try {\n if (await l.exists(type, name)) {\n loader = l;\n this.logger.info(`Updating existing metadata in loader: ${l.contract.name}`);\n break;\n }\n } catch (e) {\n // Ignore existence check errors (e.g. network down)\n }\n }\n\n // 2. Default to 'filesystem' if available (Create new)\n if (!loader) {\n const fsLoader = this.loaders.get('filesystem');\n if (fsLoader && fsLoader.save) {\n loader = fsLoader;\n }\n }\n\n // 3. Fallback to any writable loader\n if (!loader) {\n for (const l of this.loaders.values()) {\n if (l.save) {\n loader = l;\n break;\n }\n }\n }\n }\n\n if (!loader) {\n throw new Error(`No loader available for saving type: ${type}`);\n }\n\n if (!loader.save) {\n throw new Error(`Loader '${loader.contract?.name}' does not support saving`);\n }\n\n return loader.save(type, name, data, options);\n }\n\n /**\n * Check if metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n for (const loader of this.loaders.values()) {\n if (await loader.exists(type, name)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<string[]> {\n const items = new Set<string>();\n for (const loader of this.loaders.values()) {\n const result = await loader.list(type);\n result.forEach(item => items.add(item));\n }\n return Array.from(items);\n }\n\n /**\n * Watch for metadata changes\n */\n watch(type: string, callback: WatchCallback): void {\n if (!this.watchCallbacks.has(type)) {\n this.watchCallbacks.set(type, new Set());\n }\n this.watchCallbacks.get(type)!.add(callback);\n }\n\n /**\n * Unwatch metadata changes\n */\n unwatch(type: string, callback: WatchCallback): void {\n const callbacks = this.watchCallbacks.get(type);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.watchCallbacks.delete(type);\n }\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n // Override in subclass\n }\n\n protected notifyWatchers(type: string, event: MetadataWatchEvent) {\n const callbacks = this.watchCallbacks.get(type);\n if (!callbacks) return;\n \n for (const callback of callbacks) {\n try {\n void callback(event);\n } catch (error) {\n this.logger.error('Watch callback error', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * JSON Metadata Serializer\n * \n * Handles JSON format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class JSONSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2, sortKeys = false } = options || {};\n\n if (sortKeys) {\n // Sort keys recursively\n const sorted = this.sortObjectKeys(item);\n return prettify\n ? JSON.stringify(sorted, null, indent)\n : JSON.stringify(sorted);\n }\n\n return prettify\n ? JSON.stringify(item, null, indent)\n : JSON.stringify(item);\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n const parsed = JSON.parse(content);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.json';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'json';\n }\n\n getFormat(): MetadataFormat {\n return 'json';\n }\n\n /**\n * Recursively sort object keys\n */\n private sortObjectKeys(obj: any): any {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => this.sortObjectKeys(item));\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = this.sortObjectKeys(obj[key]);\n }\n\n return sorted;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * YAML Metadata Serializer\n * \n * Handles YAML format serialization and deserialization\n */\n\nimport * as yaml from 'js-yaml';\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class YAMLSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { indent = 2, sortKeys = false } = options || {};\n\n return yaml.dump(item, {\n indent,\n sortKeys,\n lineWidth: -1, // Disable line wrapping\n noRefs: true, // Disable YAML references\n });\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // Use JSON_SCHEMA to prevent arbitrary code execution\n // This restricts YAML to JSON-compatible types only\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.yaml';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'yaml';\n }\n\n getFormat(): MetadataFormat {\n return 'yaml';\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * TypeScript/JavaScript Metadata Serializer\n * \n * Handles TypeScript/JavaScript module format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class TypeScriptSerializer implements MetadataSerializer {\n constructor(private format: 'typescript' | 'javascript' = 'typescript') {}\n\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2 } = options || {};\n\n const jsonStr = JSON.stringify(item, null, prettify ? indent : 0);\n \n if (this.format === 'typescript') {\n return `import type { ServiceObject } from '@objectstack/spec/data';\\n\\n` +\n `export const metadata: ServiceObject = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n } else {\n return `export const metadata = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n }\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // For TypeScript/JavaScript files, we need to extract the exported object\n // Note: This is a simplified parser that works with JSON-like object literals\n // For complex TypeScript with nested objects, consider using a proper TypeScript parser\n \n // Try to find the object literal in various export patterns\n // Pattern 1: export const metadata = {...};\n let objectStart = content.indexOf('export const');\n if (objectStart === -1) {\n // Pattern 2: export default {...};\n objectStart = content.indexOf('export default');\n }\n \n if (objectStart === -1) {\n throw new Error(\n 'Could not parse TypeScript/JavaScript module. ' +\n 'Expected export pattern: \"export const metadata = {...};\" or \"export default {...};\"'\n );\n }\n\n // Find the first opening brace after the export statement\n const braceStart = content.indexOf('{', objectStart);\n if (braceStart === -1) {\n throw new Error('Could not find object literal in export statement');\n }\n\n // Find the matching closing brace by counting braces\n // Handle string literals to avoid counting braces inside strings\n let braceCount = 0;\n let braceEnd = -1;\n let inString = false;\n let stringChar = '';\n \n for (let i = braceStart; i < content.length; i++) {\n const char = content[i];\n const prevChar = i > 0 ? content[i - 1] : '';\n \n // Track string literals (simple handling of \" and ')\n if ((char === '\"' || char === \"'\") && prevChar !== '\\\\') {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n \n // Count braces only when not inside strings\n if (!inString) {\n if (char === '{') braceCount++;\n if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n braceEnd = i;\n break;\n }\n }\n }\n }\n\n if (braceEnd === -1) {\n throw new Error('Could not find matching closing brace for object literal');\n }\n\n // Extract the object literal\n const objectLiteral = content.substring(braceStart, braceEnd + 1);\n\n try {\n // Parse as JSON\n const parsed = JSON.parse(objectLiteral);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n } catch (error) {\n throw new Error(\n `Failed to parse object literal as JSON: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Make sure the TypeScript/JavaScript object uses JSON-compatible syntax (no functions, comments, or trailing commas).'\n );\n }\n }\n\n getExtension(): string {\n return this.format === 'typescript' ? '.ts' : '.js';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'typescript' || format === 'javascript';\n }\n\n getFormat(): MetadataFormat {\n return this.format;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Node Metadata Manager\n * \n * Extends MetadataManager with Filesystem capabilities (Watching, default loader)\n */\n\nimport * as path from 'node:path';\nimport { watch as chokidarWatch, type FSWatcher } from 'chokidar';\nimport type {\n MetadataWatchEvent,\n} from '@objectstack/spec/system';\nimport { FilesystemLoader } from './loaders/filesystem-loader.js';\nimport { MetadataManager, type MetadataManagerOptions } from './metadata-manager.js';\n\n/**\n * Node metadata manager class\n */\nexport class NodeMetadataManager extends MetadataManager {\n private watcher?: FSWatcher;\n\n constructor(config: MetadataManagerOptions) {\n super(config);\n\n // Initialize Default Filesystem Loader if no loaders provided\n // This logic replaces the removed logic from base class\n if (!config.loaders || config.loaders.length === 0) {\n const rootDir = config.rootDir || process.cwd();\n this.registerLoader(new FilesystemLoader(rootDir, this.serializers, this.logger));\n }\n\n // Start watching if enabled\n if (config.watch) {\n this.startWatching();\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = undefined;\n }\n // Call base cleanup if any\n }\n\n /**\n * Start watching for file changes\n */\n private startWatching(): void {\n const rootDir = this.config.rootDir || process.cwd();\n const { ignored = ['**/node_modules/**', '**/*.test.*'], persistent = true } =\n this.config.watchOptions || {};\n\n this.watcher = chokidarWatch(rootDir, {\n ignored,\n persistent,\n ignoreInitial: true,\n });\n\n this.watcher.on('add', async (filePath) => {\n await this.handleFileEvent('added', filePath);\n });\n\n this.watcher.on('change', async (filePath) => {\n await this.handleFileEvent('changed', filePath);\n });\n\n this.watcher.on('unlink', async (filePath) => {\n await this.handleFileEvent('deleted', filePath);\n });\n\n this.logger.info('File watcher started', { rootDir });\n }\n\n /**\n * Handle file change events\n */\n private async handleFileEvent(\n eventType: 'added' | 'changed' | 'deleted',\n filePath: string\n ): Promise<void> {\n const rootDir = this.config.rootDir || process.cwd();\n const relativePath = path.relative(rootDir, filePath);\n const parts = relativePath.split(path.sep);\n\n if (parts.length < 2) {\n return; // Not a metadata file\n }\n\n const type = parts[0];\n const fileName = parts[parts.length - 1];\n const name = path.basename(fileName, path.extname(fileName));\n\n // We can't access private watchCallbacks from parent.\n // We need a protected method to trigger watch event or access it.\n // OPTION: Add a method `triggerWatchEvent` to MetadataManager\n \n let data: any = undefined;\n if (eventType !== 'deleted') {\n try {\n data = await this.load(type, name, { useCache: false });\n } catch (error) {\n this.logger.error('Failed to load changed file', undefined, {\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const event: MetadataWatchEvent = {\n type: eventType,\n metadataType: type,\n name,\n path: filePath,\n data,\n timestamp: new Date(),\n };\n\n this.notifyWatchers(type, event);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Filesystem Metadata Loader\n * \n * Loads metadata from the filesystem using glob patterns\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { glob } from 'glob';\nimport { createHash } from 'node:crypto';\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataFormat,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { Logger } from '@objectstack/core';\nimport type { MetadataLoader } from './loader-interface.js';\nimport type { MetadataSerializer } from '../serializers/serializer-interface.js';\n\nexport class FilesystemLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'filesystem',\n protocol: 'file',\n capabilities: {\n read: true,\n write: true,\n watch: true,\n list: true,\n },\n supportedFormats: ['json', 'yaml', 'typescript', 'javascript'],\n supportsWatch: true,\n supportsWrite: true,\n supportsCache: true,\n };\n\n private cache = new Map<string, { data: any; etag: string; timestamp: number }>();\n\n constructor(\n private rootDir: string,\n private serializers: Map<MetadataFormat, MetadataSerializer>,\n private logger?: Logger\n ) {}\n\n async load(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const startTime = Date.now();\n const { validate: _validate = true, useCache = true, ifNoneMatch } = options || {};\n\n try {\n // Find the file\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Get stats\n const stats = await this.stat(type, name);\n\n if (!stats) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check cache\n if (useCache && ifNoneMatch && stats.etag === ifNoneMatch) {\n return {\n data: null,\n fromCache: true,\n notModified: true,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check memory cache\n const cacheKey = `${type}:${name}`;\n if (useCache && this.cache.has(cacheKey)) {\n const cached = this.cache.get(cacheKey)!;\n if (cached.etag === stats.etag) {\n return {\n data: cached.data,\n fromCache: true,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n }\n\n // Load and deserialize\n const content = await fs.readFile(filePath, 'utf-8');\n const serializer = this.getSerializer(stats.format!);\n\n if (!serializer) {\n throw new Error(`No serializer found for format: ${stats.format}`);\n }\n\n const data = serializer.deserialize(content);\n\n // Update cache\n if (useCache) {\n this.cache.set(cacheKey, {\n data,\n etag: stats.etag || '',\n timestamp: Date.now(),\n });\n }\n\n return {\n data,\n fromCache: false,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to load metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const { patterns = ['**/*'], recursive: _recursive = true, limit } = options || {};\n\n const typeDir = path.join(this.rootDir, type);\n const items: T[] = [];\n\n try {\n // Build glob patterns\n const globPatterns = patterns.map(pattern =>\n path.join(typeDir, pattern)\n );\n\n for (const pattern of globPatterns) {\n const files = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n for (const file of files) {\n if (limit && items.length >= limit) {\n break;\n }\n\n try {\n const content = await fs.readFile(file, 'utf-8');\n const format = this.detectFormat(file);\n const serializer = this.getSerializer(format);\n\n if (serializer) {\n const data = serializer.deserialize<T>(content);\n items.push(data);\n }\n } catch (error) {\n this.logger?.warn('Failed to load file', {\n file,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (limit && items.length >= limit) {\n break;\n }\n }\n\n return items;\n } catch (error) {\n this.logger?.error('Failed to load many', undefined, {\n type,\n patterns,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const filePath = await this.findFile(type, name);\n return filePath !== null;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return null;\n }\n\n try {\n const stats = await fs.stat(filePath);\n const content = await fs.readFile(filePath, 'utf-8');\n const etag = this.generateETag(content);\n const format = this.detectFormat(filePath);\n\n return {\n size: stats.size,\n modifiedAt: stats.mtime,\n etag,\n format,\n path: filePath,\n };\n } catch (error) {\n this.logger?.error('Failed to stat file', undefined, {\n type,\n name,\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n\n async list(type: string): Promise<string[]> {\n const typeDir = path.join(this.rootDir, type);\n\n try {\n const files = await glob('**/*', {\n cwd: typeDir,\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n return files.map(file => {\n const ext = path.extname(file);\n const basename = path.basename(file, ext);\n return basename;\n });\n } catch (error) {\n this.logger?.error('Failed to list', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n return [];\n }\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const startTime = Date.now();\n const {\n format = 'typescript',\n prettify = true,\n indent = 2,\n sortKeys = false,\n backup = false,\n overwrite = true,\n atomic = true,\n path: customPath,\n } = options || {};\n\n try {\n // Get serializer\n const serializer = this.getSerializer(format);\n if (!serializer) {\n throw new Error(`No serializer found for format: ${format}`);\n }\n\n // Determine file path\n const typeDir = path.join(this.rootDir, type);\n const fileName = `${name}${serializer.getExtension()}`;\n const filePath = customPath || path.join(typeDir, fileName);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await fs.access(filePath);\n throw new Error(`File already exists: ${filePath}`);\n } catch (error) {\n // File doesn't exist, continue\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n // Create directory if it doesn't exist\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n // Create backup if requested\n let backupPath: string | undefined;\n if (backup) {\n try {\n await fs.access(filePath);\n backupPath = `${filePath}.bak`;\n await fs.copyFile(filePath, backupPath);\n } catch {\n // File doesn't exist, no backup needed\n }\n }\n\n // Serialize data\n const content = serializer.serialize(data, {\n prettify,\n indent,\n sortKeys,\n });\n\n // Write to disk (atomic or direct)\n if (atomic) {\n const tempPath = `${filePath}.tmp`;\n await fs.writeFile(tempPath, content, 'utf-8');\n await fs.rename(tempPath, filePath);\n } else {\n await fs.writeFile(filePath, content, 'utf-8');\n }\n\n // Update cache logic if needed (e.g., invalidate or update)\n // For now, we rely on the watcher to pick up changes\n\n return {\n success: true,\n path: filePath,\n // format, // Not in schema\n size: Buffer.byteLength(content, 'utf-8'),\n backupPath,\n saveTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to save metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Find file for a given type and name\n */\n private async findFile(type: string, name: string): Promise<string | null> {\n const typeDir = path.join(this.rootDir, type);\n const extensions = ['.json', '.yaml', '.yml', '.ts', '.js'];\n\n for (const ext of extensions) {\n const filePath = path.join(typeDir, `${name}${ext}`);\n\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, try next extension\n }\n }\n\n return null;\n }\n\n /**\n * Detect format from file extension\n */\n private detectFormat(filePath: string): MetadataFormat {\n const ext = path.extname(filePath).toLowerCase();\n\n switch (ext) {\n case '.json':\n return 'json';\n case '.yaml':\n case '.yml':\n return 'yaml';\n case '.ts':\n return 'typescript';\n case '.js':\n return 'javascript';\n default:\n return 'json'; // Default to JSON\n }\n }\n\n /**\n * Get serializer for format\n */\n private getSerializer(format: MetadataFormat): MetadataSerializer | undefined {\n return this.serializers.get(format);\n }\n\n /**\n * Generate ETag for content\n * Uses SHA-256 hash truncated to 32 characters for reasonable collision resistance\n * while keeping ETag headers compact (full 64-char hash is overkill for this use case)\n */\n private generateETag(content: string): string {\n const hash = createHash('sha256').update(content).digest('hex').substring(0, 32);\n return `\"${hash}\"`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { NodeMetadataManager } from './node-metadata-manager.js';\nimport { ObjectStackDefinitionSchema } from '@objectstack/spec';\n\nexport interface MetadataPluginOptions {\n rootDir?: string;\n watch?: boolean;\n}\n\nexport class MetadataPlugin implements Plugin {\n name = 'com.objectstack.metadata';\n type = 'standard';\n version = '1.0.0';\n \n private manager: NodeMetadataManager;\n private options: MetadataPluginOptions;\n\n constructor(options: MetadataPluginOptions = {}) {\n this.options = {\n watch: true,\n ...options\n };\n\n const rootDir = this.options.rootDir || process.cwd();\n\n this.manager = new NodeMetadataManager({ \n rootDir,\n watch: this.options.watch ?? true,\n formats: ['yaml', 'json', 'typescript', 'javascript'] \n });\n }\n\n init = async (ctx: PluginContext) => {\n ctx.logger.info('Initializing Metadata Manager', { root: this.options.rootDir || process.cwd() });\n \n // Register Metadata Manager as a service\n // This allows other plugins to query raw metadata or listen to changes\n ctx.registerService('metadata', this.manager);\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('Loading metadata...');\n \n // Define metadata types directly from the Protocol Definition\n // This ensures the loader is always in sync with the Spec\n const metadataTypes = Object.keys(ObjectStackDefinitionSchema.shape)\n .filter(key => key !== 'manifest'); // Manifest is handled separately\n\n for (const type of metadataTypes) {\n try {\n // Try to load metadata of this type\n const items = await this.manager.loadMany(type, {\n recursive: true\n });\n\n if (items.length > 0) {\n ctx.logger.info(`Loaded ${items.length} ${type}`);\n \n // Helper: Register with ObjectQL Registry\n const ql = ctx.getService('objectql') as any;\n if (ql && ql.registry) {\n items.forEach((item: any) => {\n // Determine key field (id or name)\n const keyField = item.id ? 'id' : 'name';\n \n // Map plural type to singular/registry type if needed\n // For now, we use the singular form for standard types: \n // objects -> object, apps -> app, etc.\n // But Registry seems to accept arbitrary strings.\n // To match Protocol standard, we might want to normalize.\n // Let's use the directory name (plural) as the type for now,\n // OR map 'objects' -> 'object' specifically.\n \n let registryType = type;\n if (type === 'objects') registryType = 'object';\n if (type === 'apps') registryType = 'app';\n if (type === 'plugins') registryType = 'plugin';\n if (type === 'functions') registryType = 'function';\n \n ql.registry.registerItem(registryType, item, keyField);\n });\n }\n }\n } catch (e: any) {\n // Ignore missing directories or errors\n // ctx.logger.debug(`No metadata found for type: ${type}`);\n }\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Memory Metadata Loader\n * \n * Stores metadata in memory only. Changes are lost when process restarts.\n * Useful for testing, temporary overrides, or \"dirty\" edits.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class MemoryLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'memory',\n protocol: 'memory',\n capabilities: {\n read: true,\n write: true,\n watch: false,\n list: true,\n },\n };\n\n // Storage: Type -> Name -> Data\n private storage = new Map<string, Map<string, any>>();\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const typeStore = this.storage.get(type);\n const data = typeStore?.get(name);\n\n if (data) {\n return {\n data,\n source: 'memory',\n format: 'json',\n loadTime: 0,\n };\n }\n\n return { data: null };\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.values()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n return this.storage.get(type)?.has(name) ?? false;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n if (await this.exists(type, name)) {\n return {\n size: 0, // In-memory\n mtime: new Date().toISOString(),\n format: 'json',\n };\n }\n return null;\n }\n\n async list(type: string): Promise<string[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.keys());\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n if (!this.storage.has(type)) {\n this.storage.set(type, new Map());\n }\n \n this.storage.get(type)!.set(name, data);\n\n return {\n success: true,\n path: `memory://${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Remote Metadata Loader\n * \n * Loads metadata from an HTTP API.\n * This loader is stateless and delegates storage to the remote server.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class RemoteLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'remote',\n protocol: 'http',\n capabilities: {\n read: true,\n write: true,\n watch: false, // Could implement SSE/WebSocket in future\n list: true,\n },\n };\n\n constructor(private baseUrl: string, private authToken?: string) {}\n\n private get headers() {\n return {\n 'Content-Type': 'application/json',\n ...(this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}),\n };\n }\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n try {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (response.status === 404) {\n return { data: null };\n }\n\n if (!response.ok) {\n throw new Error(`Remote load failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n data,\n source: this.baseUrl,\n format: 'json',\n loadTime: 0, \n };\n } catch (error) {\n console.error(`RemoteLoader error loading ${type}/${name}`, error);\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const response = await fetch(`${this.baseUrl}/${type}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (!response.ok) {\n return [];\n }\n\n return (await response.json()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n return response.ok;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n // Basic implementation using HEAD\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n \n if (!response.ok) return null;\n\n return {\n size: Number(response.headers.get('content-length') || 0),\n mtime: new Date(response.headers.get('last-modified') || Date.now()).toISOString(),\n format: 'json',\n };\n }\n\n async list(type: string): Promise<string[]> {\n const items = await this.loadMany<{ name: string }>(type);\n return items.map(i => i.name);\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'PUT',\n headers: this.headers,\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n throw new Error(`Remote save failed: ${response.statusText}`);\n }\n\n return {\n success: true,\n path: `${this.baseUrl}/${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './executor.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { System } from '@objectstack/spec';\nimport { ISchemaDriver } from '@objectstack/spec/contracts';\n\nexport class MigrationExecutor {\n constructor(private driver: ISchemaDriver) {}\n\n async executeChangeSet(changeSet: System.ChangeSet): Promise<void> {\n console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);\n \n for (const op of changeSet.operations) {\n try {\n await this.executeOperation(op);\n } catch (e) {\n console.error(`Failed to execute operation ${op.type}:`, e);\n throw e;\n }\n }\n }\n\n private async executeOperation(op: System.MigrationOperation): Promise<void> {\n switch (op.type) {\n case 'create_object':\n console.log(` > Create Object: ${op.object.name}`);\n await this.driver.createCollection(op.object.name, op.object);\n break;\n case 'add_field':\n console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.addColumn(op.objectName, op.fieldName, op.field);\n break;\n case 'remove_field':\n console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.dropColumn(op.objectName, op.fieldName);\n break;\n case 'delete_object':\n console.log(` > Delete Object: ${op.objectName}`);\n await this.driver.dropCollection(op.objectName);\n break;\n case 'execute_sql':\n console.log(` > Execute SQL`);\n await this.driver.executeRaw(op.sql);\n break;\n case 'modify_field':\n console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);\n break;\n case 'rename_object':\n console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);\n break;\n default:\n throw new Error(`Unknown operation type`);\n }\n }\n}\n"],"mappings":"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","names":["path","basename"]}
|
|
1
|
+
{"version":3,"sources":["../src/metadata-manager.ts","../src/serializers/json-serializer.ts","../src/serializers/yaml-serializer.ts","../src/serializers/typescript-serializer.ts","../src/node-metadata-manager.ts","../src/loaders/filesystem-loader.ts","../src/plugin.ts","../src/loaders/memory-loader.ts","../src/loaders/remote-loader.ts","../src/migration/index.ts","../src/migration/executor.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Metadata Manager\n * \n * Main orchestrator for metadata loading, saving, and persistence.\n * Browser-compatible (Pure).\n */\n\nimport type {\n MetadataManagerConfig,\n MetadataLoadOptions,\n MetadataSaveOptions,\n MetadataSaveResult,\n MetadataWatchEvent,\n MetadataFormat,\n} from '@objectstack/spec/system';\nimport { createLogger, type Logger } from '@objectstack/core';\nimport { JSONSerializer } from './serializers/json-serializer.js';\nimport { YAMLSerializer } from './serializers/yaml-serializer.js';\nimport { TypeScriptSerializer } from './serializers/typescript-serializer.js';\nimport type { MetadataSerializer } from './serializers/serializer-interface.js';\nimport type { MetadataLoader } from './loaders/loader-interface.js';\n\n/**\n * Watch callback function\n */\nexport type WatchCallback = (event: MetadataWatchEvent) => void | Promise<void>;\n\nexport interface MetadataManagerOptions extends MetadataManagerConfig {\n loaders?: MetadataLoader[];\n}\n\n/**\n * Main metadata manager class\n */\nexport class MetadataManager {\n private loaders: Map<string, MetadataLoader> = new Map();\n // Protected so subclasses can access serializers if needed\n protected serializers: Map<MetadataFormat, MetadataSerializer>;\n protected logger: Logger;\n protected watchCallbacks = new Map<string, Set<WatchCallback>>();\n protected config: MetadataManagerOptions;\n\n constructor(config: MetadataManagerOptions) {\n this.config = config;\n this.logger = createLogger({ level: 'info', format: 'pretty' });\n\n // Initialize serializers\n this.serializers = new Map();\n const formats = config.formats || ['typescript', 'json', 'yaml'];\n\n if (formats.includes('json')) {\n this.serializers.set('json', new JSONSerializer());\n }\n if (formats.includes('yaml')) {\n this.serializers.set('yaml', new YAMLSerializer());\n }\n if (formats.includes('typescript')) {\n this.serializers.set('typescript', new TypeScriptSerializer('typescript'));\n }\n if (formats.includes('javascript')) {\n this.serializers.set('javascript', new TypeScriptSerializer('javascript'));\n }\n\n // Initialize Loaders\n if (config.loaders && config.loaders.length > 0) {\n config.loaders.forEach(loader => this.registerLoader(loader));\n }\n // Note: No default loader in base class. Subclasses (NodeMetadataManager) or caller must provide one.\n }\n\n /**\n * Register a new metadata loader (data source)\n */\n registerLoader(loader: MetadataLoader) {\n this.loaders.set(loader.contract.name, loader);\n this.logger.info(`Registered metadata loader: ${loader.contract.name} (${loader.contract.protocol})`);\n }\n\n /**\n * Load a single metadata item\n * Iterates through registered loaders until found\n */\n async load<T = any>(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<T | null> {\n // Priority: Database > Filesystem (Implementation-dependent)\n // For now, we just iterate.\n for (const loader of this.loaders.values()) {\n try {\n const result = await loader.load(type, name, options);\n if (result.data) {\n return result.data as T;\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to load ${type}:${name}`, { error: e });\n }\n }\n return null;\n }\n\n /**\n * Load multiple metadata items\n * Aggregates results from all loaders\n */\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const results: T[] = [];\n\n for (const loader of this.loaders.values()) {\n try {\n const items = await loader.loadMany<T>(type, options);\n for (const item of items) {\n // Deduplicate: skip items whose 'name' already exists in results\n const itemAny = item as any;\n if (itemAny && typeof itemAny.name === 'string') {\n const exists = results.some((r: any) => r && r.name === itemAny.name);\n if (exists) continue;\n }\n results.push(item);\n }\n } catch (e) {\n this.logger.warn(`Loader ${loader.contract.name} failed to loadMany ${type}`, { error: e });\n }\n }\n return results;\n }\n\n /**\n * Save metadata to disk\n */\n /**\n * Save metadata item\n */\n async save<T = any>(\n type: string,\n name: string,\n data: T,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const targetLoader = (options as any)?.loader;\n\n // Find suitable loader\n let loader: MetadataLoader | undefined;\n \n if (targetLoader) {\n loader = this.loaders.get(targetLoader);\n if (!loader) {\n throw new Error(`Loader not found: ${targetLoader}`);\n }\n } else {\n // 1. Try to find existing writable loader containing this item (Update existing)\n for (const l of this.loaders.values()) {\n // Skip if loader is strictly read-only\n if (!l.save) continue;\n \n try {\n if (await l.exists(type, name)) {\n loader = l;\n this.logger.info(`Updating existing metadata in loader: ${l.contract.name}`);\n break;\n }\n } catch (e) {\n // Ignore existence check errors (e.g. network down)\n }\n }\n\n // 2. Default to 'filesystem' if available (Create new)\n if (!loader) {\n const fsLoader = this.loaders.get('filesystem');\n if (fsLoader && fsLoader.save) {\n loader = fsLoader;\n }\n }\n\n // 3. Fallback to any writable loader\n if (!loader) {\n for (const l of this.loaders.values()) {\n if (l.save) {\n loader = l;\n break;\n }\n }\n }\n }\n\n if (!loader) {\n throw new Error(`No loader available for saving type: ${type}`);\n }\n\n if (!loader.save) {\n throw new Error(`Loader '${loader.contract?.name}' does not support saving`);\n }\n\n return loader.save(type, name, data, options);\n }\n\n /**\n * Check if metadata item exists\n */\n async exists(type: string, name: string): Promise<boolean> {\n for (const loader of this.loaders.values()) {\n if (await loader.exists(type, name)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * List all items of a type\n */\n async list(type: string): Promise<string[]> {\n const items = new Set<string>();\n for (const loader of this.loaders.values()) {\n const result = await loader.list(type);\n result.forEach(item => items.add(item));\n }\n return Array.from(items);\n }\n\n /**\n * Watch for metadata changes\n */\n watch(type: string, callback: WatchCallback): void {\n if (!this.watchCallbacks.has(type)) {\n this.watchCallbacks.set(type, new Set());\n }\n this.watchCallbacks.get(type)!.add(callback);\n }\n\n /**\n * Unwatch metadata changes\n */\n unwatch(type: string, callback: WatchCallback): void {\n const callbacks = this.watchCallbacks.get(type);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.watchCallbacks.delete(type);\n }\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n // Override in subclass\n }\n\n protected notifyWatchers(type: string, event: MetadataWatchEvent) {\n const callbacks = this.watchCallbacks.get(type);\n if (!callbacks) return;\n \n for (const callback of callbacks) {\n try {\n void callback(event);\n } catch (error) {\n this.logger.error('Watch callback error', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * JSON Metadata Serializer\n * \n * Handles JSON format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class JSONSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2, sortKeys = false } = options || {};\n\n if (sortKeys) {\n // Sort keys recursively\n const sorted = this.sortObjectKeys(item);\n return prettify\n ? JSON.stringify(sorted, null, indent)\n : JSON.stringify(sorted);\n }\n\n return prettify\n ? JSON.stringify(item, null, indent)\n : JSON.stringify(item);\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n const parsed = JSON.parse(content);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.json';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'json';\n }\n\n getFormat(): MetadataFormat {\n return 'json';\n }\n\n /**\n * Recursively sort object keys\n */\n private sortObjectKeys(obj: any): any {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => this.sortObjectKeys(item));\n }\n\n const sorted: Record<string, any> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = this.sortObjectKeys(obj[key]);\n }\n\n return sorted;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * YAML Metadata Serializer\n * \n * Handles YAML format serialization and deserialization\n */\n\nimport * as yaml from 'js-yaml';\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class YAMLSerializer implements MetadataSerializer {\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { indent = 2, sortKeys = false } = options || {};\n\n return yaml.dump(item, {\n indent,\n sortKeys,\n lineWidth: -1, // Disable line wrapping\n noRefs: true, // Disable YAML references\n });\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // Use JSON_SCHEMA to prevent arbitrary code execution\n // This restricts YAML to JSON-compatible types only\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n }\n\n getExtension(): string {\n return '.yaml';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'yaml';\n }\n\n getFormat(): MetadataFormat {\n return 'yaml';\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * TypeScript/JavaScript Metadata Serializer\n * \n * Handles TypeScript/JavaScript module format serialization and deserialization\n */\n\nimport type { z } from 'zod';\nimport type { MetadataFormat } from '@objectstack/spec/system';\nimport type { MetadataSerializer, SerializeOptions } from './serializer-interface.js';\n\nexport class TypeScriptSerializer implements MetadataSerializer {\n constructor(private format: 'typescript' | 'javascript' = 'typescript') {}\n\n serialize<T>(item: T, options?: SerializeOptions): string {\n const { prettify = true, indent = 2 } = options || {};\n\n const jsonStr = JSON.stringify(item, null, prettify ? indent : 0);\n \n if (this.format === 'typescript') {\n return `import type { ServiceObject } from '@objectstack/spec/data';\\n\\n` +\n `export const metadata: ServiceObject = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n } else {\n return `export const metadata = ${jsonStr};\\n\\n` +\n `export default metadata;\\n`;\n }\n }\n\n deserialize<T>(content: string, schema?: z.ZodSchema): T {\n // For TypeScript/JavaScript files, we need to extract the exported object\n // Note: This is a simplified parser that works with JSON-like object literals\n // For complex TypeScript with nested objects, consider using a proper TypeScript parser\n \n // Try to find the object literal in various export patterns\n // Pattern 1: export const metadata = {...};\n let objectStart = content.indexOf('export const');\n if (objectStart === -1) {\n // Pattern 2: export default {...};\n objectStart = content.indexOf('export default');\n }\n \n if (objectStart === -1) {\n throw new Error(\n 'Could not parse TypeScript/JavaScript module. ' +\n 'Expected export pattern: \"export const metadata = {...};\" or \"export default {...};\"'\n );\n }\n\n // Find the first opening brace after the export statement\n const braceStart = content.indexOf('{', objectStart);\n if (braceStart === -1) {\n throw new Error('Could not find object literal in export statement');\n }\n\n // Find the matching closing brace by counting braces\n // Handle string literals to avoid counting braces inside strings\n let braceCount = 0;\n let braceEnd = -1;\n let inString = false;\n let stringChar = '';\n \n for (let i = braceStart; i < content.length; i++) {\n const char = content[i];\n const prevChar = i > 0 ? content[i - 1] : '';\n \n // Track string literals (simple handling of \" and ')\n if ((char === '\"' || char === \"'\") && prevChar !== '\\\\') {\n if (!inString) {\n inString = true;\n stringChar = char;\n } else if (char === stringChar) {\n inString = false;\n stringChar = '';\n }\n }\n \n // Count braces only when not inside strings\n if (!inString) {\n if (char === '{') braceCount++;\n if (char === '}') {\n braceCount--;\n if (braceCount === 0) {\n braceEnd = i;\n break;\n }\n }\n }\n }\n\n if (braceEnd === -1) {\n throw new Error('Could not find matching closing brace for object literal');\n }\n\n // Extract the object literal\n const objectLiteral = content.substring(braceStart, braceEnd + 1);\n\n try {\n // Parse as JSON\n const parsed = JSON.parse(objectLiteral);\n\n if (schema) {\n return schema.parse(parsed) as T;\n }\n\n return parsed as T;\n } catch (error) {\n throw new Error(\n `Failed to parse object literal as JSON: ${error instanceof Error ? error.message : String(error)}. ` +\n 'Make sure the TypeScript/JavaScript object uses JSON-compatible syntax (no functions, comments, or trailing commas).'\n );\n }\n }\n\n getExtension(): string {\n return this.format === 'typescript' ? '.ts' : '.js';\n }\n\n canHandle(format: MetadataFormat): boolean {\n return format === 'typescript' || format === 'javascript';\n }\n\n getFormat(): MetadataFormat {\n return this.format;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Node Metadata Manager\n * \n * Extends MetadataManager with Filesystem capabilities (Watching, default loader)\n */\n\nimport * as path from 'node:path';\nimport { watch as chokidarWatch, type FSWatcher } from 'chokidar';\nimport type {\n MetadataWatchEvent,\n} from '@objectstack/spec/system';\nimport { FilesystemLoader } from './loaders/filesystem-loader.js';\nimport { MetadataManager, type MetadataManagerOptions } from './metadata-manager.js';\n\n/**\n * Node metadata manager class\n */\nexport class NodeMetadataManager extends MetadataManager {\n private watcher?: FSWatcher;\n\n constructor(config: MetadataManagerOptions) {\n super(config);\n\n // Initialize Default Filesystem Loader if no loaders provided\n // This logic replaces the removed logic from base class\n if (!config.loaders || config.loaders.length === 0) {\n const rootDir = config.rootDir || process.cwd();\n this.registerLoader(new FilesystemLoader(rootDir, this.serializers, this.logger));\n }\n\n // Start watching if enabled\n if (config.watch) {\n this.startWatching();\n }\n }\n\n /**\n * Stop all watching\n */\n async stopWatching(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = undefined;\n }\n // Call base cleanup if any\n }\n\n /**\n * Start watching for file changes\n */\n private startWatching(): void {\n const rootDir = this.config.rootDir || process.cwd();\n const { ignored = ['**/node_modules/**', '**/*.test.*'], persistent = true } =\n this.config.watchOptions || {};\n\n this.watcher = chokidarWatch(rootDir, {\n ignored,\n persistent,\n ignoreInitial: true,\n });\n\n this.watcher.on('add', async (filePath) => {\n await this.handleFileEvent('added', filePath);\n });\n\n this.watcher.on('change', async (filePath) => {\n await this.handleFileEvent('changed', filePath);\n });\n\n this.watcher.on('unlink', async (filePath) => {\n await this.handleFileEvent('deleted', filePath);\n });\n\n this.logger.info('File watcher started', { rootDir });\n }\n\n /**\n * Handle file change events\n */\n private async handleFileEvent(\n eventType: 'added' | 'changed' | 'deleted',\n filePath: string\n ): Promise<void> {\n const rootDir = this.config.rootDir || process.cwd();\n const relativePath = path.relative(rootDir, filePath);\n const parts = relativePath.split(path.sep);\n\n if (parts.length < 2) {\n return; // Not a metadata file\n }\n\n const type = parts[0];\n const fileName = parts[parts.length - 1];\n const name = path.basename(fileName, path.extname(fileName));\n\n // We can't access private watchCallbacks from parent.\n // We need a protected method to trigger watch event or access it.\n // OPTION: Add a method `triggerWatchEvent` to MetadataManager\n \n let data: any = undefined;\n if (eventType !== 'deleted') {\n try {\n data = await this.load(type, name, { useCache: false });\n } catch (error) {\n this.logger.error('Failed to load changed file', undefined, {\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n }\n\n const event: MetadataWatchEvent = {\n type: eventType,\n metadataType: type,\n name,\n path: filePath,\n data,\n timestamp: new Date(),\n };\n\n this.notifyWatchers(type, event);\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Filesystem Metadata Loader\n * \n * Loads metadata from the filesystem using glob patterns\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { glob } from 'glob';\nimport { createHash } from 'node:crypto';\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataFormat,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { Logger } from '@objectstack/core';\nimport type { MetadataLoader } from './loader-interface.js';\nimport type { MetadataSerializer } from '../serializers/serializer-interface.js';\n\nexport class FilesystemLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'filesystem',\n protocol: 'file',\n capabilities: {\n read: true,\n write: true,\n watch: true,\n list: true,\n },\n supportedFormats: ['json', 'yaml', 'typescript', 'javascript'],\n supportsWatch: true,\n supportsWrite: true,\n supportsCache: true,\n };\n\n private cache = new Map<string, { data: any; etag: string; timestamp: number }>();\n\n constructor(\n private rootDir: string,\n private serializers: Map<MetadataFormat, MetadataSerializer>,\n private logger?: Logger\n ) {}\n\n async load(\n type: string,\n name: string,\n options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const startTime = Date.now();\n const { validate: _validate = true, useCache = true, ifNoneMatch } = options || {};\n\n try {\n // Find the file\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Get stats\n const stats = await this.stat(type, name);\n\n if (!stats) {\n return {\n data: null,\n fromCache: false,\n notModified: false,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check cache\n if (useCache && ifNoneMatch && stats.etag === ifNoneMatch) {\n return {\n data: null,\n fromCache: true,\n notModified: true,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n\n // Check memory cache\n const cacheKey = `${type}:${name}`;\n if (useCache && this.cache.has(cacheKey)) {\n const cached = this.cache.get(cacheKey)!;\n if (cached.etag === stats.etag) {\n return {\n data: cached.data,\n fromCache: true,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n }\n }\n\n // Load and deserialize\n const content = await fs.readFile(filePath, 'utf-8');\n const serializer = this.getSerializer(stats.format!);\n\n if (!serializer) {\n throw new Error(`No serializer found for format: ${stats.format}`);\n }\n\n const data = serializer.deserialize(content);\n\n // Update cache\n if (useCache) {\n this.cache.set(cacheKey, {\n data,\n etag: stats.etag || '',\n timestamp: Date.now(),\n });\n }\n\n return {\n data,\n fromCache: false,\n notModified: false,\n etag: stats.etag,\n stats,\n loadTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to load metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n options?: MetadataLoadOptions\n ): Promise<T[]> {\n const { patterns = ['**/*'], recursive: _recursive = true, limit } = options || {};\n\n const typeDir = path.join(this.rootDir, type);\n const items: T[] = [];\n\n try {\n // Build glob patterns\n const globPatterns = patterns.map(pattern =>\n path.join(typeDir, pattern)\n );\n\n for (const pattern of globPatterns) {\n const files = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n for (const file of files) {\n if (limit && items.length >= limit) {\n break;\n }\n\n try {\n const content = await fs.readFile(file, 'utf-8');\n const format = this.detectFormat(file);\n const serializer = this.getSerializer(format);\n\n if (serializer) {\n const data = serializer.deserialize<T>(content);\n items.push(data);\n }\n } catch (error) {\n this.logger?.warn('Failed to load file', {\n file,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (limit && items.length >= limit) {\n break;\n }\n }\n\n return items;\n } catch (error) {\n this.logger?.error('Failed to load many', undefined, {\n type,\n patterns,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const filePath = await this.findFile(type, name);\n return filePath !== null;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n const filePath = await this.findFile(type, name);\n\n if (!filePath) {\n return null;\n }\n\n try {\n const stats = await fs.stat(filePath);\n const content = await fs.readFile(filePath, 'utf-8');\n const etag = this.generateETag(content);\n const format = this.detectFormat(filePath);\n\n return {\n size: stats.size,\n modifiedAt: stats.mtime,\n etag,\n format,\n path: filePath,\n };\n } catch (error) {\n this.logger?.error('Failed to stat file', undefined, {\n type,\n name,\n filePath,\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n\n async list(type: string): Promise<string[]> {\n const typeDir = path.join(this.rootDir, type);\n\n try {\n const files = await glob('**/*', {\n cwd: typeDir,\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*'],\n nodir: true,\n });\n\n return files.map(file => {\n const ext = path.extname(file);\n const basename = path.basename(file, ext);\n return basename;\n });\n } catch (error) {\n this.logger?.error('Failed to list', undefined, {\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n return [];\n }\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const startTime = Date.now();\n const {\n format = 'typescript',\n prettify = true,\n indent = 2,\n sortKeys = false,\n backup = false,\n overwrite = true,\n atomic = true,\n path: customPath,\n } = options || {};\n\n try {\n // Get serializer\n const serializer = this.getSerializer(format);\n if (!serializer) {\n throw new Error(`No serializer found for format: ${format}`);\n }\n\n // Determine file path\n const typeDir = path.join(this.rootDir, type);\n const fileName = `${name}${serializer.getExtension()}`;\n const filePath = customPath || path.join(typeDir, fileName);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await fs.access(filePath);\n throw new Error(`File already exists: ${filePath}`);\n } catch (error) {\n // File doesn't exist, continue\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n // Create directory if it doesn't exist\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n // Create backup if requested\n let backupPath: string | undefined;\n if (backup) {\n try {\n await fs.access(filePath);\n backupPath = `${filePath}.bak`;\n await fs.copyFile(filePath, backupPath);\n } catch {\n // File doesn't exist, no backup needed\n }\n }\n\n // Serialize data\n const content = serializer.serialize(data, {\n prettify,\n indent,\n sortKeys,\n });\n\n // Write to disk (atomic or direct)\n if (atomic) {\n const tempPath = `${filePath}.tmp`;\n await fs.writeFile(tempPath, content, 'utf-8');\n await fs.rename(tempPath, filePath);\n } else {\n await fs.writeFile(filePath, content, 'utf-8');\n }\n\n // Update cache logic if needed (e.g., invalidate or update)\n // For now, we rely on the watcher to pick up changes\n\n return {\n success: true,\n path: filePath,\n // format, // Not in schema\n size: Buffer.byteLength(content, 'utf-8'),\n backupPath,\n saveTime: Date.now() - startTime,\n };\n } catch (error) {\n this.logger?.error('Failed to save metadata', undefined, {\n type,\n name,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Find file for a given type and name\n */\n private async findFile(type: string, name: string): Promise<string | null> {\n const typeDir = path.join(this.rootDir, type);\n const extensions = ['.json', '.yaml', '.yml', '.ts', '.js'];\n\n for (const ext of extensions) {\n const filePath = path.join(typeDir, `${name}${ext}`);\n\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, try next extension\n }\n }\n\n return null;\n }\n\n /**\n * Detect format from file extension\n */\n private detectFormat(filePath: string): MetadataFormat {\n const ext = path.extname(filePath).toLowerCase();\n\n switch (ext) {\n case '.json':\n return 'json';\n case '.yaml':\n case '.yml':\n return 'yaml';\n case '.ts':\n return 'typescript';\n case '.js':\n return 'javascript';\n default:\n return 'json'; // Default to JSON\n }\n }\n\n /**\n * Get serializer for format\n */\n private getSerializer(format: MetadataFormat): MetadataSerializer | undefined {\n return this.serializers.get(format);\n }\n\n /**\n * Generate ETag for content\n * Uses SHA-256 hash truncated to 32 characters for reasonable collision resistance\n * while keeping ETag headers compact (full 64-char hash is overkill for this use case)\n */\n private generateETag(content: string): string {\n const hash = createHash('sha256').update(content).digest('hex').substring(0, 32);\n return `\"${hash}\"`;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport { NodeMetadataManager } from './node-metadata-manager.js';\nimport { ObjectStackDefinitionSchema } from '@objectstack/spec';\n\nexport interface MetadataPluginOptions {\n rootDir?: string;\n watch?: boolean;\n}\n\nexport class MetadataPlugin implements Plugin {\n name = 'com.objectstack.metadata';\n type = 'standard';\n version = '1.0.0';\n \n private manager: NodeMetadataManager;\n private options: MetadataPluginOptions;\n\n constructor(options: MetadataPluginOptions = {}) {\n this.options = {\n watch: true,\n ...options\n };\n\n const rootDir = this.options.rootDir || process.cwd();\n\n this.manager = new NodeMetadataManager({ \n rootDir,\n watch: this.options.watch ?? true,\n formats: ['yaml', 'json', 'typescript', 'javascript'] \n });\n }\n\n init = async (ctx: PluginContext) => {\n ctx.logger.info('Initializing Metadata Manager', { root: this.options.rootDir || process.cwd() });\n \n // Register Metadata Manager as a service\n // This allows other plugins to query raw metadata or listen to changes\n ctx.registerService('metadata', this.manager);\n }\n\n start = async (ctx: PluginContext) => {\n ctx.logger.info('Loading metadata...');\n \n // Define metadata types directly from the Protocol Definition\n // This ensures the loader is always in sync with the Spec\n const metadataTypes = Object.keys(ObjectStackDefinitionSchema.shape)\n .filter(key => key !== 'manifest'); // Manifest is handled separately\n\n for (const type of metadataTypes) {\n try {\n // Try to load metadata of this type\n const items = await this.manager.loadMany(type, {\n recursive: true\n });\n\n if (items.length > 0) {\n ctx.logger.info(`Loaded ${items.length} ${type}`);\n \n // Helper: Register with ObjectQL Registry\n const ql = ctx.getService('objectql') as any;\n if (ql && ql.registry) {\n items.forEach((item: any) => {\n // Determine key field (id or name)\n const keyField = item.id ? 'id' : 'name';\n \n // Map plural type to singular/registry type if needed\n // For now, we use the singular form for standard types: \n // objects -> object, apps -> app, etc.\n // But Registry seems to accept arbitrary strings.\n // To match Protocol standard, we might want to normalize.\n // Let's use the directory name (plural) as the type for now,\n // OR map 'objects' -> 'object' specifically.\n \n let registryType = type;\n if (type === 'objects') registryType = 'object';\n if (type === 'apps') registryType = 'app';\n if (type === 'plugins') registryType = 'plugin';\n if (type === 'functions') registryType = 'function';\n \n ql.registry.registerItem(registryType, item, keyField);\n });\n }\n }\n } catch (e: any) {\n // Ignore missing directories or errors\n // ctx.logger.debug(`No metadata found for type: ${type}`);\n }\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Memory Metadata Loader\n * \n * Stores metadata in memory only. Changes are lost when process restarts.\n * Useful for testing, temporary overrides, or \"dirty\" edits.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class MemoryLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'memory',\n protocol: 'memory',\n capabilities: {\n read: true,\n write: true,\n watch: false,\n list: true,\n },\n };\n\n // Storage: Type -> Name -> Data\n private storage = new Map<string, Map<string, any>>();\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n const typeStore = this.storage.get(type);\n const data = typeStore?.get(name);\n\n if (data) {\n return {\n data,\n source: 'memory',\n format: 'json',\n loadTime: 0,\n };\n }\n\n return { data: null };\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.values()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n return this.storage.get(type)?.has(name) ?? false;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n if (await this.exists(type, name)) {\n return {\n size: 0, // In-memory\n mtime: new Date().toISOString(),\n format: 'json',\n };\n }\n return null;\n }\n\n async list(type: string): Promise<string[]> {\n const typeStore = this.storage.get(type);\n if (!typeStore) return [];\n return Array.from(typeStore.keys());\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n if (!this.storage.has(type)) {\n this.storage.set(type, new Map());\n }\n \n this.storage.get(type)!.set(name, data);\n\n return {\n success: true,\n path: `memory://${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Remote Metadata Loader\n * \n * Loads metadata from an HTTP API.\n * This loader is stateless and delegates storage to the remote server.\n */\n\nimport type {\n MetadataLoadOptions,\n MetadataLoadResult,\n MetadataStats,\n MetadataLoaderContract,\n MetadataSaveOptions,\n MetadataSaveResult,\n} from '@objectstack/spec/system';\nimport type { MetadataLoader } from './loader-interface.js';\n\nexport class RemoteLoader implements MetadataLoader {\n readonly contract: MetadataLoaderContract = {\n name: 'remote',\n protocol: 'http',\n capabilities: {\n read: true,\n write: true,\n watch: false, // Could implement SSE/WebSocket in future\n list: true,\n },\n };\n\n constructor(private baseUrl: string, private authToken?: string) {}\n\n private get headers() {\n return {\n 'Content-Type': 'application/json',\n ...(this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {}),\n };\n }\n\n async load(\n type: string,\n name: string,\n _options?: MetadataLoadOptions\n ): Promise<MetadataLoadResult> {\n try {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (response.status === 404) {\n return { data: null };\n }\n\n if (!response.ok) {\n throw new Error(`Remote load failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n data,\n source: this.baseUrl,\n format: 'json',\n loadTime: 0, \n };\n } catch (error) {\n console.error(`RemoteLoader error loading ${type}/${name}`, error);\n throw error;\n }\n }\n\n async loadMany<T = any>(\n type: string,\n _options?: MetadataLoadOptions\n ): Promise<T[]> {\n const response = await fetch(`${this.baseUrl}/${type}`, {\n method: 'GET',\n headers: this.headers,\n });\n\n if (!response.ok) {\n return [];\n }\n\n return (await response.json()) as T[];\n }\n\n async exists(type: string, name: string): Promise<boolean> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n return response.ok;\n }\n\n async stat(type: string, name: string): Promise<MetadataStats | null> {\n // Basic implementation using HEAD\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'HEAD',\n headers: this.headers,\n });\n \n if (!response.ok) return null;\n\n return {\n size: Number(response.headers.get('content-length') || 0),\n mtime: new Date(response.headers.get('last-modified') || Date.now()).toISOString(),\n format: 'json',\n };\n }\n\n async list(type: string): Promise<string[]> {\n const items = await this.loadMany<{ name: string }>(type);\n return items.map(i => i.name);\n }\n\n async save(\n type: string,\n name: string,\n data: any,\n _options?: MetadataSaveOptions\n ): Promise<MetadataSaveResult> {\n const response = await fetch(`${this.baseUrl}/${type}/${name}`, {\n method: 'PUT',\n headers: this.headers,\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n throw new Error(`Remote save failed: ${response.statusText}`);\n }\n\n return {\n success: true,\n path: `${this.baseUrl}/${type}/${name}`,\n saveTime: 0,\n };\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './executor.js';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { System } from '@objectstack/spec';\nimport { ISchemaDriver } from '@objectstack/spec/contracts';\n\nexport class MigrationExecutor {\n constructor(private driver: ISchemaDriver) {}\n\n async executeChangeSet(changeSet: System.ChangeSet): Promise<void> {\n console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);\n \n for (const op of changeSet.operations) {\n try {\n await this.executeOperation(op);\n } catch (e) {\n console.error(`Failed to execute operation ${op.type}:`, e);\n throw e;\n }\n }\n }\n\n private async executeOperation(op: System.MigrationOperation): Promise<void> {\n switch (op.type) {\n case 'create_object':\n console.log(` > Create Object: ${op.object.name}`);\n await this.driver.createCollection(op.object.name, op.object);\n break;\n case 'add_field':\n console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.addColumn(op.objectName, op.fieldName, op.field);\n break;\n case 'remove_field':\n console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);\n await this.driver.dropColumn(op.objectName, op.fieldName);\n break;\n case 'delete_object':\n console.log(` > Delete Object: ${op.objectName}`);\n await this.driver.dropCollection(op.objectName);\n break;\n case 'execute_sql':\n console.log(` > Execute SQL`);\n await this.driver.executeRaw(op.sql);\n break;\n case 'modify_field':\n console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);\n break;\n case 'rename_object':\n console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);\n break;\n default:\n throw new Error(`Unknown operation type`);\n }\n }\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,oBAAiC;;;ACLnC,IAAM,iBAAN,MAAmD;AAAA,EACxD,UAAa,MAAS,SAAoC;AACxD,UAAM,EAAE,WAAW,MAAM,SAAS,GAAG,WAAW,MAAM,IAAI,WAAW,CAAC;AAEtE,QAAI,UAAU;AAEZ,YAAM,SAAS,KAAK,eAAe,IAAI;AACvC,aAAO,WACH,KAAK,UAAU,QAAQ,MAAM,MAAM,IACnC,KAAK,UAAU,MAAM;AAAA,IAC3B;AAEA,WAAO,WACH,KAAK,UAAU,MAAM,MAAM,MAAM,IACjC,KAAK,UAAU,IAAI;AAAA,EACzB;AAAA,EAEA,YAAe,SAAiB,QAAyB;AACvD,UAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,QAAI,QAAQ;AACV,aAAO,OAAO,MAAM,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,eAAuB;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAAiC;AACzC,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,YAA4B;AAC1B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,KAAe;AACpC,QAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAO,IAAI,IAAI,UAAQ,KAAK,eAAe,IAAI,CAAC;AAAA,IAClD;AAEA,UAAM,SAA8B,CAAC;AACrC,UAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK;AAEnC,eAAW,OAAO,MAAM;AACtB,aAAO,GAAG,IAAI,KAAK,eAAe,IAAI,GAAG,CAAC;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT;AACF;;;AChEA,YAAY,UAAU;AAKf,IAAM,iBAAN,MAAmD;AAAA,EACxD,UAAa,MAAS,SAAoC;AACxD,UAAM,EAAE,SAAS,GAAG,WAAW,MAAM,IAAI,WAAW,CAAC;AAErD,WAAY,UAAK,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA,WAAW;AAAA;AAAA,MACX,QAAQ;AAAA;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,YAAe,SAAiB,QAAyB;AAGvD,UAAM,SAAc,UAAK,SAAS,EAAE,QAAa,iBAAY,CAAC;AAE9D,QAAI,QAAQ;AACV,aAAO,OAAO,MAAM,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,eAAuB;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAAiC;AACzC,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,YAA4B;AAC1B,WAAO;AAAA,EACT;AACF;;;ACpCO,IAAM,uBAAN,MAAyD;AAAA,EAC9D,YAAoB,SAAsC,cAAc;AAApD;AAAA,EAAqD;AAAA,EAEzE,UAAa,MAAS,SAAoC;AACxD,UAAM,EAAE,WAAW,MAAM,SAAS,EAAE,IAAI,WAAW,CAAC;AAEpD,UAAM,UAAU,KAAK,UAAU,MAAM,MAAM,WAAW,SAAS,CAAC;AAEhE,QAAI,KAAK,WAAW,cAAc;AAChC,aAAO;AAAA;AAAA,yCACqC,OAAO;AAAA;AAAA;AAAA;AAAA,IAErD,OAAO;AACL,aAAO,2BAA2B,OAAO;AAAA;AAAA;AAAA;AAAA,IAE3C;AAAA,EACF;AAAA,EAEA,YAAe,SAAiB,QAAyB;AAOvD,QAAI,cAAc,QAAQ,QAAQ,cAAc;AAChD,QAAI,gBAAgB,IAAI;AAEtB,oBAAc,QAAQ,QAAQ,gBAAgB;AAAA,IAChD;AAEA,QAAI,gBAAgB,IAAI;AACtB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAGA,UAAM,aAAa,QAAQ,QAAQ,KAAK,WAAW;AACnD,QAAI,eAAe,IAAI;AACrB,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AAIA,QAAI,aAAa;AACjB,QAAI,WAAW;AACf,QAAI,WAAW;AACf,QAAI,aAAa;AAEjB,aAAS,IAAI,YAAY,IAAI,QAAQ,QAAQ,KAAK;AAChD,YAAM,OAAO,QAAQ,CAAC;AACtB,YAAM,WAAW,IAAI,IAAI,QAAQ,IAAI,CAAC,IAAI;AAG1C,WAAK,SAAS,OAAO,SAAS,QAAQ,aAAa,MAAM;AACvD,YAAI,CAAC,UAAU;AACb,qBAAW;AACX,uBAAa;AAAA,QACf,WAAW,SAAS,YAAY;AAC9B,qBAAW;AACX,uBAAa;AAAA,QACf;AAAA,MACF;AAGA,UAAI,CAAC,UAAU;AACb,YAAI,SAAS,IAAK;AAClB,YAAI,SAAS,KAAK;AAChB;AACA,cAAI,eAAe,GAAG;AACpB,uBAAW;AACX;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,aAAa,IAAI;AACnB,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AAGA,UAAM,gBAAgB,QAAQ,UAAU,YAAY,WAAW,CAAC;AAEhE,QAAI;AAEF,YAAM,SAAS,KAAK,MAAM,aAAa;AAEvC,UAAI,QAAQ;AACV,eAAO,OAAO,MAAM,MAAM;AAAA,MAC5B;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,2CAA2C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAEnG;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eAAuB;AACrB,WAAO,KAAK,WAAW,eAAe,QAAQ;AAAA,EAChD;AAAA,EAEA,UAAU,QAAiC;AACzC,WAAO,WAAW,gBAAgB,WAAW;AAAA,EAC/C;AAAA,EAEA,YAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AACF;;;AH1FO,IAAM,kBAAN,MAAsB;AAAA,EAQ3B,YAAY,QAAgC;AAP5C,SAAQ,UAAuC,oBAAI,IAAI;AAIvD,SAAU,iBAAiB,oBAAI,IAAgC;AAI7D,SAAK,SAAS;AACd,SAAK,SAAS,aAAa,EAAE,OAAO,QAAQ,QAAQ,SAAS,CAAC;AAG9D,SAAK,cAAc,oBAAI,IAAI;AAC3B,UAAM,UAAU,OAAO,WAAW,CAAC,cAAc,QAAQ,MAAM;AAE/D,QAAI,QAAQ,SAAS,MAAM,GAAG;AAC5B,WAAK,YAAY,IAAI,QAAQ,IAAI,eAAe,CAAC;AAAA,IACnD;AACA,QAAI,QAAQ,SAAS,MAAM,GAAG;AAC5B,WAAK,YAAY,IAAI,QAAQ,IAAI,eAAe,CAAC;AAAA,IACnD;AACA,QAAI,QAAQ,SAAS,YAAY,GAAG;AAClC,WAAK,YAAY,IAAI,cAAc,IAAI,qBAAqB,YAAY,CAAC;AAAA,IAC3E;AACA,QAAI,QAAQ,SAAS,YAAY,GAAG;AAClC,WAAK,YAAY,IAAI,cAAc,IAAI,qBAAqB,YAAY,CAAC;AAAA,IAC3E;AAGA,QAAI,OAAO,WAAW,OAAO,QAAQ,SAAS,GAAG;AAC/C,aAAO,QAAQ,QAAQ,YAAU,KAAK,eAAe,MAAM,CAAC;AAAA,IAC9D;AAAA,EAEF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,QAAwB;AACrC,SAAK,QAAQ,IAAI,OAAO,SAAS,MAAM,MAAM;AAC7C,SAAK,OAAO,KAAK,+BAA+B,OAAO,SAAS,IAAI,KAAK,OAAO,SAAS,QAAQ,GAAG;AAAA,EACtG;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KACJ,MACA,MACA,SACmB;AAGnB,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AACxC,UAAI;AACA,cAAM,SAAS,MAAM,OAAO,KAAK,MAAM,MAAM,OAAO;AACpD,YAAI,OAAO,MAAM;AACb,iBAAO,OAAO;AAAA,QAClB;AAAA,MACJ,SAAS,GAAG;AACR,aAAK,OAAO,KAAK,UAAU,OAAO,SAAS,IAAI,mBAAmB,IAAI,IAAI,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;AAAA,MAClG;AAAA,IACJ;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SACJ,MACA,SACc;AACd,UAAM,UAAe,CAAC;AAEtB,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AACxC,UAAI;AACA,cAAM,QAAQ,MAAM,OAAO,SAAY,MAAM,OAAO;AACpD,mBAAW,QAAQ,OAAO;AAEtB,gBAAM,UAAU;AAChB,cAAI,WAAW,OAAO,QAAQ,SAAS,UAAU;AAC7C,kBAAM,SAAS,QAAQ,KAAK,CAAC,MAAW,KAAK,EAAE,SAAS,QAAQ,IAAI;AACpE,gBAAI,OAAQ;AAAA,UAChB;AACA,kBAAQ,KAAK,IAAI;AAAA,QACrB;AAAA,MACJ,SAAS,GAAG;AACT,aAAK,OAAO,KAAK,UAAU,OAAO,SAAS,IAAI,uBAAuB,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;AAAA,MAC7F;AAAA,IACJ;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KACJ,MACA,MACA,MACA,SAC6B;AAC7B,UAAM,eAAgB,SAAiB;AAGvC,QAAI;AAEJ,QAAI,cAAc;AAChB,eAAS,KAAK,QAAQ,IAAI,YAAY;AACtC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,qBAAqB,YAAY,EAAE;AAAA,MACrD;AAAA,IACF,OAAO;AAEL,iBAAW,KAAK,KAAK,QAAQ,OAAO,GAAG;AAEnC,YAAI,CAAC,EAAE,KAAM;AAEb,YAAI;AACF,cAAI,MAAM,EAAE,OAAO,MAAM,IAAI,GAAG;AAC5B,qBAAS;AACT,iBAAK,OAAO,KAAK,yCAAyC,EAAE,SAAS,IAAI,EAAE;AAC3E;AAAA,UACJ;AAAA,QACF,SAAS,GAAG;AAAA,QAEZ;AAAA,MACJ;AAGA,UAAI,CAAC,QAAQ;AACX,cAAM,WAAW,KAAK,QAAQ,IAAI,YAAY;AAC9C,YAAI,YAAY,SAAS,MAAM;AAC5B,mBAAS;AAAA,QACZ;AAAA,MACF;AAGA,UAAI,CAAC,QAAQ;AACX,mBAAW,KAAK,KAAK,QAAQ,OAAO,GAAG;AACrC,cAAI,EAAE,MAAM;AACV,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,wCAAwC,IAAI,EAAE;AAAA,IAChE;AAEA,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,MAAM,WAAW,OAAO,UAAU,IAAI,2BAA2B;AAAA,IAC7E;AAEA,WAAO,OAAO,KAAK,MAAM,MAAM,MAAM,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,MAAc,MAAgC;AACzD,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,MAAM,OAAO,OAAO,MAAM,IAAI,GAAG;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,MAAiC;AAC1C,UAAM,QAAQ,oBAAI,IAAY;AAC9B,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,YAAM,SAAS,MAAM,OAAO,KAAK,IAAI;AACrC,aAAO,QAAQ,UAAQ,MAAM,IAAI,IAAI,CAAC;AAAA,IACxC;AACA,WAAO,MAAM,KAAK,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAc,UAA+B;AACjD,QAAI,CAAC,KAAK,eAAe,IAAI,IAAI,GAAG;AAClC,WAAK,eAAe,IAAI,MAAM,oBAAI,IAAI,CAAC;AAAA,IACzC;AACA,SAAK,eAAe,IAAI,IAAI,EAAG,IAAI,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,MAAc,UAA+B;AACnD,UAAM,YAAY,KAAK,eAAe,IAAI,IAAI;AAC9C,QAAI,WAAW;AACb,gBAAU,OAAO,QAAQ;AACzB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,eAAe,OAAO,IAAI;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAA8B;AAAA,EAEpC;AAAA,EAEU,eAAe,MAAc,OAA2B;AAChE,UAAM,YAAY,KAAK,eAAe,IAAI,IAAI;AAC9C,QAAI,CAAC,UAAW;AAEhB,eAAW,YAAY,WAAW;AAChC,UAAI;AACF,aAAK,SAAS,KAAK;AAAA,MACrB,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,wBAAwB,QAAW;AAAA,UACnD;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;AIvQA,YAAYA,WAAU;AACtB,SAAS,SAAS,qBAAqC;;;ACDvD,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAcpB,IAAM,mBAAN,MAAiD;AAAA,EAkBtD,YACU,SACA,aACA,QACR;AAHQ;AACA;AACA;AApBV,SAAS,WAAmC;AAAA,MAC1C,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,kBAAkB,CAAC,QAAQ,QAAQ,cAAc,YAAY;AAAA,MAC7D,eAAe;AAAA,MACf,eAAe;AAAA,MACf,eAAe;AAAA,IACjB;AAEA,SAAQ,QAAQ,oBAAI,IAA4D;AAAA,EAM7E;AAAA,EAEH,MAAM,KACJ,MACA,MACA,SAC6B;AAC7B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,EAAE,UAAU,YAAY,MAAM,WAAW,MAAM,YAAY,IAAI,WAAW,CAAC;AAEjF,QAAI;AAEF,YAAM,WAAW,MAAM,KAAK,SAAS,MAAM,IAAI;AAE/C,UAAI,CAAC,UAAU;AACb,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,aAAa;AAAA,UACb,UAAU,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAGA,YAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,IAAI;AAExC,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,aAAa;AAAA,UACb,UAAU,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAGA,UAAI,YAAY,eAAe,MAAM,SAAS,aAAa;AACzD,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,aAAa;AAAA,UACb,MAAM,MAAM;AAAA,UACZ;AAAA,UACA,UAAU,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAGA,YAAM,WAAW,GAAG,IAAI,IAAI,IAAI;AAChC,UAAI,YAAY,KAAK,MAAM,IAAI,QAAQ,GAAG;AACxC,cAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,YAAI,OAAO,SAAS,MAAM,MAAM;AAC9B,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,WAAW;AAAA,YACX,aAAa;AAAA,YACb,MAAM,MAAM;AAAA,YACZ;AAAA,YACA,UAAU,KAAK,IAAI,IAAI;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAGA,YAAM,UAAU,MAAS,YAAS,UAAU,OAAO;AACnD,YAAM,aAAa,KAAK,cAAc,MAAM,MAAO;AAEnD,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,mCAAmC,MAAM,MAAM,EAAE;AAAA,MACnE;AAEA,YAAM,OAAO,WAAW,YAAY,OAAO;AAG3C,UAAI,UAAU;AACZ,aAAK,MAAM,IAAI,UAAU;AAAA,UACvB;AAAA,UACA,MAAM,MAAM,QAAQ;AAAA,UACpB,WAAW,KAAK,IAAI;AAAA,QACtB,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL;AAAA,QACA,WAAW;AAAA,QACX,aAAa;AAAA,QACb,MAAM,MAAM;AAAA,QACZ;AAAA,QACA,UAAU,KAAK,IAAI,IAAI;AAAA,MACzB;AAAA,IACF,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,2BAA2B,QAAW;AAAA,QACvD;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SACJ,MACA,SACc;AACd,UAAM,EAAE,WAAW,CAAC,MAAM,GAAG,WAAW,aAAa,MAAM,MAAM,IAAI,WAAW,CAAC;AAEjF,UAAM,UAAe,UAAK,KAAK,SAAS,IAAI;AAC5C,UAAM,QAAa,CAAC;AAEpB,QAAI;AAEF,YAAM,eAAe,SAAS;AAAA,QAAI,aAC3B,UAAK,SAAS,OAAO;AAAA,MAC5B;AAEA,iBAAW,WAAW,cAAc;AAClC,cAAM,QAAQ,MAAM,KAAK,SAAS;AAAA,UAChC,QAAQ,CAAC,sBAAsB,eAAe,aAAa;AAAA,UAC3D,OAAO;AAAA,QACT,CAAC;AAED,mBAAW,QAAQ,OAAO;AACxB,cAAI,SAAS,MAAM,UAAU,OAAO;AAClC;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,UAAU,MAAS,YAAS,MAAM,OAAO;AAC/C,kBAAM,SAAS,KAAK,aAAa,IAAI;AACrC,kBAAM,aAAa,KAAK,cAAc,MAAM;AAE5C,gBAAI,YAAY;AACd,oBAAM,OAAO,WAAW,YAAe,OAAO;AAC9C,oBAAM,KAAK,IAAI;AAAA,YACjB;AAAA,UACF,SAAS,OAAO;AACd,iBAAK,QAAQ,KAAK,uBAAuB;AAAA,cACvC;AAAA,cACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC9D,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,SAAS,MAAM,UAAU,OAAO;AAClC;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,uBAAuB,QAAW;AAAA,QACnD;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,MAAc,MAAgC;AACzD,UAAM,WAAW,MAAM,KAAK,SAAS,MAAM,IAAI;AAC/C,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,MAAM,KAAK,MAAc,MAA6C;AACpE,UAAM,WAAW,MAAM,KAAK,SAAS,MAAM,IAAI;AAE/C,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,MAAS,QAAK,QAAQ;AACpC,YAAM,UAAU,MAAS,YAAS,UAAU,OAAO;AACnD,YAAM,OAAO,KAAK,aAAa,OAAO;AACtC,YAAM,SAAS,KAAK,aAAa,QAAQ;AAEzC,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,YAAY,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,uBAAuB,QAAW;AAAA,QACnD;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,MAAiC;AAC1C,UAAM,UAAe,UAAK,KAAK,SAAS,IAAI;AAE5C,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,QAAQ;AAAA,QAC/B,KAAK;AAAA,QACL,QAAQ,CAAC,sBAAsB,eAAe,aAAa;AAAA,QAC3D,OAAO;AAAA,MACT,CAAC;AAED,aAAO,MAAM,IAAI,UAAQ;AACvB,cAAM,MAAW,aAAQ,IAAI;AAC7B,cAAMC,YAAgB,cAAS,MAAM,GAAG;AACxC,eAAOA;AAAA,MACT,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,kBAAkB,QAAW;AAAA,QAC9C;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,KACJ,MACA,MACA,MACA,SAC6B;AAC7B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,MAAM;AAAA,IACR,IAAI,WAAW,CAAC;AAEhB,QAAI;AAEF,YAAM,aAAa,KAAK,cAAc,MAAM;AAC5C,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,mCAAmC,MAAM,EAAE;AAAA,MAC7D;AAGA,YAAM,UAAe,UAAK,KAAK,SAAS,IAAI;AAC5C,YAAM,WAAW,GAAG,IAAI,GAAG,WAAW,aAAa,CAAC;AACpD,YAAM,WAAW,cAAmB,UAAK,SAAS,QAAQ;AAG1D,UAAI,CAAC,WAAW;AACd,YAAI;AACF,gBAAS,UAAO,QAAQ;AACxB,gBAAM,IAAI,MAAM,wBAAwB,QAAQ,EAAE;AAAA,QACpD,SAAS,OAAO;AAEd,cAAK,MAAgC,SAAS,UAAU;AACtD,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAGA,YAAS,SAAW,aAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAG1D,UAAI;AACJ,UAAI,QAAQ;AACV,YAAI;AACF,gBAAS,UAAO,QAAQ;AACxB,uBAAa,GAAG,QAAQ;AACxB,gBAAS,YAAS,UAAU,UAAU;AAAA,QACxC,QAAQ;AAAA,QAER;AAAA,MACF;AAGA,YAAM,UAAU,WAAW,UAAU,MAAM;AAAA,QACzC;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAGD,UAAI,QAAQ;AACV,cAAM,WAAW,GAAG,QAAQ;AAC5B,cAAS,aAAU,UAAU,SAAS,OAAO;AAC7C,cAAS,UAAO,UAAU,QAAQ;AAAA,MACpC,OAAO;AACL,cAAS,aAAU,UAAU,SAAS,OAAO;AAAA,MAC/C;AAKA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM;AAAA;AAAA,QAEN,MAAM,OAAO,WAAW,SAAS,OAAO;AAAA,QACxC;AAAA,QACA,UAAU,KAAK,IAAI,IAAI;AAAA,MACzB;AAAA,IACF,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,2BAA2B,QAAW;AAAA,QACvD;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SAAS,MAAc,MAAsC;AACzE,UAAM,UAAe,UAAK,KAAK,SAAS,IAAI;AAC5C,UAAM,aAAa,CAAC,SAAS,SAAS,QAAQ,OAAO,KAAK;AAE1D,eAAW,OAAO,YAAY;AAC5B,YAAM,WAAgB,UAAK,SAAS,GAAG,IAAI,GAAG,GAAG,EAAE;AAEnD,UAAI;AACF,cAAS,UAAO,QAAQ;AACxB,eAAO;AAAA,MACT,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,UAAkC;AACrD,UAAM,MAAW,aAAQ,QAAQ,EAAE,YAAY;AAE/C,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,QAAwD;AAC5E,WAAO,KAAK,YAAY,IAAI,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,SAAyB;AAC5C,UAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,UAAU,GAAG,EAAE;AAC/E,WAAO,IAAI,IAAI;AAAA,EACjB;AACF;;;ADhZO,IAAM,sBAAN,cAAkC,gBAAgB;AAAA,EAGvD,YAAY,QAAgC;AAC1C,UAAM,MAAM;AAIZ,QAAI,CAAC,OAAO,WAAW,OAAO,QAAQ,WAAW,GAAG;AAClD,YAAM,UAAU,OAAO,WAAW,QAAQ,IAAI;AAC9C,WAAK,eAAe,IAAI,iBAAiB,SAAS,KAAK,aAAa,KAAK,MAAM,CAAC;AAAA,IAClF;AAGA,QAAI,OAAO,OAAO;AAChB,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAA8B;AAClC,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,QAAQ,MAAM;AACzB,WAAK,UAAU;AAAA,IACjB;AAAA,EAEF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,UAAM,UAAU,KAAK,OAAO,WAAW,QAAQ,IAAI;AACnD,UAAM,EAAE,UAAU,CAAC,sBAAsB,aAAa,GAAG,aAAa,KAAK,IACzE,KAAK,OAAO,gBAAgB,CAAC;AAE/B,SAAK,UAAU,cAAc,SAAS;AAAA,MACpC;AAAA,MACA;AAAA,MACA,eAAe;AAAA,IACjB,CAAC;AAED,SAAK,QAAQ,GAAG,OAAO,OAAO,aAAa;AACzC,YAAM,KAAK,gBAAgB,SAAS,QAAQ;AAAA,IAC9C,CAAC;AAED,SAAK,QAAQ,GAAG,UAAU,OAAO,aAAa;AAC5C,YAAM,KAAK,gBAAgB,WAAW,QAAQ;AAAA,IAChD,CAAC;AAED,SAAK,QAAQ,GAAG,UAAU,OAAO,aAAa;AAC5C,YAAM,KAAK,gBAAgB,WAAW,QAAQ;AAAA,IAChD,CAAC;AAED,SAAK,OAAO,KAAK,wBAAwB,EAAE,QAAQ,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,gBACZ,WACA,UACe;AACf,UAAM,UAAU,KAAK,OAAO,WAAW,QAAQ,IAAI;AACnD,UAAM,eAAoB,eAAS,SAAS,QAAQ;AACpD,UAAM,QAAQ,aAAa,MAAW,SAAG;AAEzC,QAAI,MAAM,SAAS,GAAG;AACpB;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,WAAW,MAAM,MAAM,SAAS,CAAC;AACvC,UAAM,OAAY,eAAS,UAAe,cAAQ,QAAQ,CAAC;AAM3D,QAAI,OAAY;AAChB,QAAI,cAAc,WAAW;AAC3B,UAAI;AACF,eAAO,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE,UAAU,MAAM,CAAC;AAAA,MACxD,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,+BAA+B,QAAW;AAAA,UAC1D;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAA4B;AAAA,MAChC,MAAM;AAAA,MACN,cAAc;AAAA,MACd;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,eAAe,MAAM,KAAK;AAAA,EACjC;AACF;;;AEzHA,SAAS,mCAAmC;AAOrC,IAAM,iBAAN,MAAuC;AAAA,EAQ1C,YAAY,UAAiC,CAAC,GAAG;AAPjD,gBAAO;AACP,gBAAO;AACP,mBAAU;AAoBV,gBAAO,OAAO,QAAuB;AACjC,UAAI,OAAO,KAAK,iCAAiC,EAAE,MAAM,KAAK,QAAQ,WAAW,QAAQ,IAAI,EAAE,CAAC;AAIhG,UAAI,gBAAgB,YAAY,KAAK,OAAO;AAAA,IAChD;AAEA,iBAAQ,OAAO,QAAuB;AAClC,UAAI,OAAO,KAAK,qBAAqB;AAIrC,YAAM,gBAAgB,OAAO,KAAK,4BAA4B,KAAK,EAC9D,OAAO,SAAO,QAAQ,UAAU;AAErC,iBAAW,QAAQ,eAAe;AAC9B,YAAI;AAEA,gBAAM,QAAQ,MAAM,KAAK,QAAQ,SAAS,MAAM;AAAA,YAC5C,WAAW;AAAA,UACf,CAAC;AAED,cAAI,MAAM,SAAS,GAAG;AACjB,gBAAI,OAAO,KAAK,UAAU,MAAM,MAAM,IAAI,IAAI,EAAE;AAGhD,kBAAM,KAAK,IAAI,WAAW,UAAU;AACpC,gBAAI,MAAM,GAAG,UAAU;AACpB,oBAAM,QAAQ,CAAC,SAAc;AAEzB,sBAAM,WAAW,KAAK,KAAK,OAAO;AAUlC,oBAAI,eAAe;AACnB,oBAAI,SAAS,UAAW,gBAAe;AACvC,oBAAI,SAAS,OAAQ,gBAAe;AACpC,oBAAI,SAAS,UAAW,gBAAe;AACvC,oBAAI,SAAS,YAAa,gBAAe;AAEzC,mBAAG,SAAS,aAAa,cAAc,MAAM,QAAQ;AAAA,cACzD,CAAC;AAAA,YACJ;AAAA,UACL;AAAA,QACJ,SAAS,GAAQ;AAAA,QAGjB;AAAA,MACJ;AAAA,IACJ;AAtEI,SAAK,UAAU;AAAA,MACX,OAAO;AAAA,MACP,GAAG;AAAA,IACP;AAEA,UAAM,UAAU,KAAK,QAAQ,WAAW,QAAQ,IAAI;AAEpD,SAAK,UAAU,IAAI,oBAAoB;AAAA,MACnC;AAAA,MACA,OAAO,KAAK,QAAQ,SAAS;AAAA,MAC7B,SAAS,CAAC,QAAQ,QAAQ,cAAc,YAAY;AAAA,IACxD,CAAC;AAAA,EACL;AA2DJ;;;ACxEO,IAAM,eAAN,MAA6C;AAAA,EAA7C;AACL,SAAS,WAAmC;AAAA,MAC1C,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAGA;AAAA,SAAQ,UAAU,oBAAI,IAA8B;AAAA;AAAA,EAEpD,MAAM,KACJ,MACA,MACA,UAC6B;AAC7B,UAAM,YAAY,KAAK,QAAQ,IAAI,IAAI;AACvC,UAAM,OAAO,WAAW,IAAI,IAAI;AAEhC,QAAI,MAAM;AACR,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,KAAK;AAAA,EACtB;AAAA,EAEA,MAAM,SACJ,MACA,UACc;AACd,UAAM,YAAY,KAAK,QAAQ,IAAI,IAAI;AACvC,QAAI,CAAC,UAAW,QAAO,CAAC;AACxB,WAAO,MAAM,KAAK,UAAU,OAAO,CAAC;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,MAAc,MAAgC;AACzD,WAAO,KAAK,QAAQ,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;AAAA,EAC9C;AAAA,EAEA,MAAM,KAAK,MAAc,MAA6C;AACpE,QAAI,MAAM,KAAK,OAAO,MAAM,IAAI,GAAG;AACjC,aAAO;AAAA,QACL,MAAM;AAAA;AAAA,QACN,QAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC9B,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,MAAiC;AAC1C,UAAM,YAAY,KAAK,QAAQ,IAAI,IAAI;AACvC,QAAI,CAAC,UAAW,QAAO,CAAC;AACxB,WAAO,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,KACJ,MACA,MACA,MACA,UAC6B;AAC7B,QAAI,CAAC,KAAK,QAAQ,IAAI,IAAI,GAAG;AAC3B,WAAK,QAAQ,IAAI,MAAM,oBAAI,IAAI,CAAC;AAAA,IAClC;AAEA,SAAK,QAAQ,IAAI,IAAI,EAAG,IAAI,MAAM,IAAI;AAEtC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,YAAY,IAAI,IAAI,IAAI;AAAA,MAC9B,UAAU;AAAA,IACZ;AAAA,EACF;AACF;;;ACnFO,IAAM,eAAN,MAA6C;AAAA,EAYlD,YAAoB,SAAyB,WAAoB;AAA7C;AAAyB;AAX7C,SAAS,WAAmC;AAAA,MAC1C,MAAM;AAAA,MACN,UAAU;AAAA,MACV,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EAEkE;AAAA,EAElE,IAAY,UAAU;AACpB,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,GAAI,KAAK,YAAY,EAAE,eAAe,UAAU,KAAK,SAAS,GAAG,IAAI,CAAC;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,MAAM,KACJ,MACA,MACA,UAC6B;AAC7B,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;AAAA,QAC9D,QAAQ;AAAA,QACR,SAAS,KAAK;AAAA,MAChB,CAAC;AAED,UAAI,SAAS,WAAW,KAAK;AAC3B,eAAO,EAAE,MAAM,KAAK;AAAA,MACtB;AAEA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,uBAAuB,SAAS,UAAU,EAAE;AAAA,MAC9D;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,8BAA8B,IAAI,IAAI,IAAI,IAAI,KAAK;AACjE,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SACJ,MACA,UACc;AACd,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,CAAC;AAAA,IACV;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA,EAEA,MAAM,OAAO,MAAc,MAAgC;AACzD,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;AAAA,MAC9D,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,IAChB,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,MAAM,KAAK,MAAc,MAA6C;AAEpE,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;AAAA,MAC9D,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,WAAO;AAAA,MACL,MAAM,OAAO,SAAS,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AAAA,MACxD,OAAO,IAAI,KAAK,SAAS,QAAQ,IAAI,eAAe,KAAK,KAAK,IAAI,CAAC,EAAE,YAAY;AAAA,MACjF,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,MAAiC;AAC1C,UAAM,QAAQ,MAAM,KAAK,SAA2B,IAAI;AACxD,WAAO,MAAM,IAAI,OAAK,EAAE,IAAI;AAAA,EAC9B;AAAA,EAEA,MAAM,KACJ,MACA,MACA,MACA,UAC6B;AAC7B,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;AAAA,MAC9D,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,MACd,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,uBAAuB,SAAS,UAAU,EAAE;AAAA,IAC9D;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,GAAG,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI;AAAA,MACrC,UAAU;AAAA,IACZ;AAAA,EACF;AACF;;;AC3IA;AAAA;AAAA;AAAA;;;ACKO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAAoB,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EAE5C,MAAM,iBAAiB,WAA4C;AACjE,YAAQ,IAAI,wBAAwB,UAAU,IAAI,KAAK,UAAU,EAAE,GAAG;AAEtE,eAAW,MAAM,UAAU,YAAY;AACrC,UAAI;AACF,cAAM,KAAK,iBAAiB,EAAE;AAAA,MAChC,SAAS,GAAG;AACV,gBAAQ,MAAM,+BAA+B,GAAG,IAAI,KAAK,CAAC;AAC1D,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,IAA8C;AAC3E,YAAQ,GAAG,MAAM;AAAA,MACf,KAAK;AACH,gBAAQ,IAAI,sBAAsB,GAAG,OAAO,IAAI,EAAE;AAClD,cAAM,KAAK,OAAO,iBAAiB,GAAG,OAAO,MAAM,GAAG,MAAM;AAC5D;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,kBAAkB,GAAG,UAAU,IAAI,GAAG,SAAS,EAAE;AAC7D,cAAM,KAAK,OAAO,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,KAAK;AACjE;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,qBAAqB,GAAG,UAAU,IAAI,GAAG,SAAS,EAAE;AAChE,cAAM,KAAK,OAAO,WAAW,GAAG,YAAY,GAAG,SAAS;AACxD;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,sBAAsB,GAAG,UAAU,EAAE;AACjD,cAAM,KAAK,OAAO,eAAe,GAAG,UAAU;AAC9C;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,iBAAiB;AAC7B,cAAM,KAAK,OAAO,WAAW,GAAG,GAAG;AACnC;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,qBAAqB,GAAG,UAAU,IAAI,GAAG,SAAS,0BAA0B;AACzF;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,sBAAsB,GAAG,OAAO,OAAO,GAAG,OAAO,0BAA0B;AACxF;AAAA,MACF;AACE,cAAM,IAAI,MAAM,wBAAwB;AAAA,IAC5C;AAAA,EACF;AACF;","names":["path","basename"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/metadata",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Metadata loading, saving, and persistence for ObjectStack",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"glob": "^13.0.1",
|
|
29
29
|
"js-yaml": "^4.1.0",
|
|
30
30
|
"chokidar": "^5.0.0",
|
|
31
|
-
"zod": "^3.
|
|
32
|
-
"@objectstack/core": "2.0.
|
|
33
|
-
"@objectstack/spec": "2.0.
|
|
34
|
-
"@objectstack/types": "2.0.
|
|
31
|
+
"zod": "^4.3.6",
|
|
32
|
+
"@objectstack/core": "2.0.2",
|
|
33
|
+
"@objectstack/spec": "2.0.2",
|
|
34
|
+
"@objectstack/types": "2.0.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/js-yaml": "^4.0.9",
|
|
38
|
-
"@types/node": "^25.
|
|
38
|
+
"@types/node": "^25.2.2",
|
|
39
39
|
"typescript": "^5.0.0",
|
|
40
40
|
"vitest": "^4.0.18"
|
|
41
41
|
},
|
package/src/metadata-manager.ts
CHANGED
|
@@ -116,7 +116,12 @@ export class MetadataManager {
|
|
|
116
116
|
try {
|
|
117
117
|
const items = await loader.loadMany<T>(type, options);
|
|
118
118
|
for (const item of items) {
|
|
119
|
-
//
|
|
119
|
+
// Deduplicate: skip items whose 'name' already exists in results
|
|
120
|
+
const itemAny = item as any;
|
|
121
|
+
if (itemAny && typeof itemAny.name === 'string') {
|
|
122
|
+
const exists = results.some((r: any) => r && r.name === itemAny.name);
|
|
123
|
+
if (exists) continue;
|
|
124
|
+
}
|
|
120
125
|
results.push(item);
|
|
121
126
|
}
|
|
122
127
|
} catch (e) {
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
4
|
+
import { MetadataManager, type MetadataManagerOptions } from './metadata-manager';
|
|
5
|
+
import { MemoryLoader } from './loaders/memory-loader';
|
|
6
|
+
import type { MetadataLoader } from './loaders/loader-interface';
|
|
7
|
+
|
|
8
|
+
// Suppress logger output during tests
|
|
9
|
+
vi.mock('@objectstack/core', () => ({
|
|
10
|
+
createLogger: () => ({
|
|
11
|
+
info: vi.fn(),
|
|
12
|
+
warn: vi.fn(),
|
|
13
|
+
error: vi.fn(),
|
|
14
|
+
debug: vi.fn(),
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
// ---------- MetadataManager ----------
|
|
19
|
+
|
|
20
|
+
describe('MetadataManager', () => {
|
|
21
|
+
let manager: MetadataManager;
|
|
22
|
+
let memoryLoader: MemoryLoader;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
memoryLoader = new MemoryLoader();
|
|
26
|
+
manager = new MetadataManager({
|
|
27
|
+
formats: ['json'],
|
|
28
|
+
loaders: [memoryLoader],
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('load', () => {
|
|
33
|
+
it('should return null when item does not exist', async () => {
|
|
34
|
+
const result = await manager.load('object', 'nonexistent');
|
|
35
|
+
expect(result).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return data from a loader', async () => {
|
|
39
|
+
await memoryLoader.save('object', 'account', { name: 'account', label: 'Account' });
|
|
40
|
+
const result = await manager.load('object', 'account');
|
|
41
|
+
expect(result).toEqual({ name: 'account', label: 'Account' });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should try loaders in order and return first result', async () => {
|
|
45
|
+
const loader1 = createMockLoader('first', { name: 'from_first' });
|
|
46
|
+
const loader2 = createMockLoader('second', { name: 'from_second' });
|
|
47
|
+
|
|
48
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [loader1, loader2] });
|
|
49
|
+
const result = await m.load('object', 'test');
|
|
50
|
+
expect(result).toEqual({ name: 'from_first' });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should skip failing loaders and try the next', async () => {
|
|
54
|
+
const failingLoader = createMockLoader('failing', null, true);
|
|
55
|
+
const goodLoader = createMockLoader('good', { name: 'ok' });
|
|
56
|
+
|
|
57
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [failingLoader, goodLoader] });
|
|
58
|
+
const result = await m.load('object', 'test');
|
|
59
|
+
expect(result).toEqual({ name: 'ok' });
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('loadMany', () => {
|
|
64
|
+
it('should return empty array when nothing loaded', async () => {
|
|
65
|
+
const result = await manager.loadMany('object');
|
|
66
|
+
expect(result).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should return all items from a loader', async () => {
|
|
70
|
+
await memoryLoader.save('object', 'account', { name: 'account' });
|
|
71
|
+
await memoryLoader.save('object', 'contact', { name: 'contact' });
|
|
72
|
+
|
|
73
|
+
const result = await manager.loadMany('object');
|
|
74
|
+
expect(result).toHaveLength(2);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should deduplicate items by name across loaders', async () => {
|
|
78
|
+
const loader1 = createMockLoaderMany('first', [
|
|
79
|
+
{ name: 'account', label: 'Account V1' },
|
|
80
|
+
]);
|
|
81
|
+
const loader2 = createMockLoaderMany('second', [
|
|
82
|
+
{ name: 'account', label: 'Account V2' },
|
|
83
|
+
{ name: 'contact', label: 'Contact' },
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [loader1, loader2] });
|
|
87
|
+
const result = await m.loadMany<{ name: string; label: string }>('object');
|
|
88
|
+
expect(result).toHaveLength(2);
|
|
89
|
+
// First loader wins
|
|
90
|
+
expect(result.find(r => r.name === 'account')?.label).toBe('Account V1');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should skip failing loaders in loadMany', async () => {
|
|
94
|
+
const failingLoader = createMockLoaderMany('failing', [], true);
|
|
95
|
+
const goodLoader = createMockLoaderMany('good', [{ name: 'ok' }]);
|
|
96
|
+
|
|
97
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [failingLoader, goodLoader] });
|
|
98
|
+
const result = await m.loadMany('object');
|
|
99
|
+
expect(result).toHaveLength(1);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('save', () => {
|
|
104
|
+
it('should save to a writable loader', async () => {
|
|
105
|
+
await manager.save('object', 'account', { name: 'account' });
|
|
106
|
+
const result = await manager.load('object', 'account');
|
|
107
|
+
expect(result).toEqual({ name: 'account' });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should throw when no writable loader is available', async () => {
|
|
111
|
+
const readOnlyLoader: MetadataLoader = {
|
|
112
|
+
contract: { name: 'readonly', protocol: 'test', capabilities: { read: true, write: false, watch: false, list: true } },
|
|
113
|
+
load: vi.fn().mockResolvedValue({ data: null }),
|
|
114
|
+
loadMany: vi.fn().mockResolvedValue([]),
|
|
115
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
116
|
+
stat: vi.fn().mockResolvedValue(null),
|
|
117
|
+
list: vi.fn().mockResolvedValue([]),
|
|
118
|
+
// No save method
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [readOnlyLoader] });
|
|
122
|
+
await expect(m.save('object', 'test', {})).rejects.toThrow('No loader available');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should save to a specific named loader', async () => {
|
|
126
|
+
await manager.save('object', 'account', { name: 'account' }, { loader: 'memory' } as any);
|
|
127
|
+
const result = await manager.load('object', 'account');
|
|
128
|
+
expect(result).toEqual({ name: 'account' });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should throw when specified loader not found', async () => {
|
|
132
|
+
await expect(
|
|
133
|
+
manager.save('object', 'test', {}, { loader: 'nonexistent' } as any)
|
|
134
|
+
).rejects.toThrow('Loader not found');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('exists', () => {
|
|
139
|
+
it('should return false for non-existent items', async () => {
|
|
140
|
+
expect(await manager.exists('object', 'nope')).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should return true for existing items', async () => {
|
|
144
|
+
await memoryLoader.save('object', 'account', { name: 'account' });
|
|
145
|
+
expect(await manager.exists('object', 'account')).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('list', () => {
|
|
150
|
+
it('should return empty array for empty type', async () => {
|
|
151
|
+
const result = await manager.list('object');
|
|
152
|
+
expect(result).toEqual([]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should list all items of a type', async () => {
|
|
156
|
+
await memoryLoader.save('object', 'account', {});
|
|
157
|
+
await memoryLoader.save('object', 'contact', {});
|
|
158
|
+
const result = await manager.list('object');
|
|
159
|
+
expect(result).toHaveLength(2);
|
|
160
|
+
expect(result).toContain('account');
|
|
161
|
+
expect(result).toContain('contact');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should deduplicate across loaders', async () => {
|
|
165
|
+
const loader1: MetadataLoader = {
|
|
166
|
+
contract: { name: 'l1', protocol: 'test', capabilities: { read: true, write: false, watch: false, list: true } },
|
|
167
|
+
load: vi.fn().mockResolvedValue({ data: null }),
|
|
168
|
+
loadMany: vi.fn().mockResolvedValue([]),
|
|
169
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
170
|
+
stat: vi.fn().mockResolvedValue(null),
|
|
171
|
+
list: vi.fn().mockResolvedValue(['account', 'contact']),
|
|
172
|
+
};
|
|
173
|
+
const loader2: MetadataLoader = {
|
|
174
|
+
contract: { name: 'l2', protocol: 'test', capabilities: { read: true, write: false, watch: false, list: true } },
|
|
175
|
+
load: vi.fn().mockResolvedValue({ data: null }),
|
|
176
|
+
loadMany: vi.fn().mockResolvedValue([]),
|
|
177
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
178
|
+
stat: vi.fn().mockResolvedValue(null),
|
|
179
|
+
list: vi.fn().mockResolvedValue(['account', 'lead']),
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [loader1, loader2] });
|
|
183
|
+
const result = await m.list('object');
|
|
184
|
+
expect(result).toHaveLength(3);
|
|
185
|
+
expect(result).toContain('account');
|
|
186
|
+
expect(result).toContain('contact');
|
|
187
|
+
expect(result).toContain('lead');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('watch / unwatch', () => {
|
|
192
|
+
it('should register and invoke watch callbacks', () => {
|
|
193
|
+
const callback = vi.fn();
|
|
194
|
+
manager.watch('object', callback);
|
|
195
|
+
|
|
196
|
+
// Trigger via protected method — cast to access it
|
|
197
|
+
(manager as any).notifyWatchers('object', {
|
|
198
|
+
type: 'changed',
|
|
199
|
+
metadataType: 'object',
|
|
200
|
+
name: 'account',
|
|
201
|
+
path: '/fake',
|
|
202
|
+
timestamp: new Date(),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
expect(callback).toHaveBeenCalledOnce();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should unwatch callback', () => {
|
|
209
|
+
const callback = vi.fn();
|
|
210
|
+
manager.watch('object', callback);
|
|
211
|
+
manager.unwatch('object', callback);
|
|
212
|
+
|
|
213
|
+
(manager as any).notifyWatchers('object', {
|
|
214
|
+
type: 'changed',
|
|
215
|
+
metadataType: 'object',
|
|
216
|
+
name: 'account',
|
|
217
|
+
path: '/fake',
|
|
218
|
+
timestamp: new Date(),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(callback).not.toHaveBeenCalled();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should not throw when unwatching non-existent callback', () => {
|
|
225
|
+
expect(() => manager.unwatch('object', vi.fn())).not.toThrow();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('registerLoader', () => {
|
|
230
|
+
it('should register a new loader', async () => {
|
|
231
|
+
const newLoader = new MemoryLoader();
|
|
232
|
+
await newLoader.save('view', 'dashboard', { name: 'dashboard' });
|
|
233
|
+
|
|
234
|
+
manager.registerLoader(newLoader);
|
|
235
|
+
|
|
236
|
+
const result = await manager.load('view', 'dashboard');
|
|
237
|
+
expect(result).toEqual({ name: 'dashboard' });
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('serializer initialization', () => {
|
|
242
|
+
it('should initialize with default formats', () => {
|
|
243
|
+
const m = new MetadataManager({ loaders: [] });
|
|
244
|
+
// Default formats are typescript, json, yaml
|
|
245
|
+
expect((m as any).serializers.size).toBe(3);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should initialize with only requested formats', () => {
|
|
249
|
+
const m = new MetadataManager({ formats: ['json'], loaders: [] });
|
|
250
|
+
expect((m as any).serializers.size).toBe(1);
|
|
251
|
+
expect((m as any).serializers.has('json')).toBe(true);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should support javascript format', () => {
|
|
255
|
+
const m = new MetadataManager({ formats: ['javascript'], loaders: [] });
|
|
256
|
+
expect((m as any).serializers.has('javascript')).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// ---------- MemoryLoader ----------
|
|
262
|
+
|
|
263
|
+
describe('MemoryLoader', () => {
|
|
264
|
+
let loader: MemoryLoader;
|
|
265
|
+
|
|
266
|
+
beforeEach(() => {
|
|
267
|
+
loader = new MemoryLoader();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should have correct contract', () => {
|
|
271
|
+
expect(loader.contract.name).toBe('memory');
|
|
272
|
+
expect(loader.contract.protocol).toBe('memory');
|
|
273
|
+
expect(loader.contract.capabilities.read).toBe(true);
|
|
274
|
+
expect(loader.contract.capabilities.write).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should save and load items', async () => {
|
|
278
|
+
await loader.save('object', 'task', { name: 'task', label: 'Task' });
|
|
279
|
+
const result = await loader.load('object', 'task');
|
|
280
|
+
expect(result.data).toEqual({ name: 'task', label: 'Task' });
|
|
281
|
+
expect(result.source).toBe('memory');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should return null for missing items', async () => {
|
|
285
|
+
const result = await loader.load('object', 'missing');
|
|
286
|
+
expect(result.data).toBeNull();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should check existence', async () => {
|
|
290
|
+
expect(await loader.exists('object', 'task')).toBe(false);
|
|
291
|
+
await loader.save('object', 'task', {});
|
|
292
|
+
expect(await loader.exists('object', 'task')).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should list items', async () => {
|
|
296
|
+
await loader.save('object', 'a', {});
|
|
297
|
+
await loader.save('object', 'b', {});
|
|
298
|
+
const items = await loader.list('object');
|
|
299
|
+
expect(items).toEqual(['a', 'b']);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('should return empty list for unknown types', async () => {
|
|
303
|
+
expect(await loader.list('unknown')).toEqual([]);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should loadMany items', async () => {
|
|
307
|
+
await loader.save('object', 'a', { name: 'a' });
|
|
308
|
+
await loader.save('object', 'b', { name: 'b' });
|
|
309
|
+
const items = await loader.loadMany('object');
|
|
310
|
+
expect(items).toHaveLength(2);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should return stats for existing items', async () => {
|
|
314
|
+
await loader.save('object', 'task', {});
|
|
315
|
+
const stats = await loader.stat('object', 'task');
|
|
316
|
+
expect(stats).not.toBeNull();
|
|
317
|
+
expect(stats!.format).toBe('json');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('should return null stats for missing items', async () => {
|
|
321
|
+
const stats = await loader.stat('object', 'missing');
|
|
322
|
+
expect(stats).toBeNull();
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should return save result with path', async () => {
|
|
326
|
+
const result = await loader.save('object', 'task', {});
|
|
327
|
+
expect(result.success).toBe(true);
|
|
328
|
+
expect(result.path).toBe('memory://object/task');
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// ---------- MetadataPlugin ----------
|
|
333
|
+
|
|
334
|
+
describe('MetadataPlugin', () => {
|
|
335
|
+
// Plugin creates NodeMetadataManager which depends on node:path and chokidar.
|
|
336
|
+
// We mock NodeMetadataManager to avoid filesystem side effects.
|
|
337
|
+
vi.mock('./node-metadata-manager', () => {
|
|
338
|
+
const MockNodeMetadataManager = class {
|
|
339
|
+
loadMany = vi.fn().mockResolvedValue([]);
|
|
340
|
+
registerLoader = vi.fn();
|
|
341
|
+
stopWatching = vi.fn();
|
|
342
|
+
};
|
|
343
|
+
return { NodeMetadataManager: MockNodeMetadataManager };
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Mock the spec import
|
|
347
|
+
vi.mock('@objectstack/spec', () => ({
|
|
348
|
+
ObjectStackDefinitionSchema: {
|
|
349
|
+
shape: {
|
|
350
|
+
manifest: {},
|
|
351
|
+
objects: {},
|
|
352
|
+
apps: {},
|
|
353
|
+
views: {},
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
}));
|
|
357
|
+
|
|
358
|
+
it('should have correct plugin metadata', async () => {
|
|
359
|
+
const { MetadataPlugin } = await import('./plugin');
|
|
360
|
+
const plugin = new MetadataPlugin({ rootDir: '/tmp/test', watch: false });
|
|
361
|
+
expect(plugin.name).toBe('com.objectstack.metadata');
|
|
362
|
+
expect(plugin.version).toBe('1.0.0');
|
|
363
|
+
expect(plugin.type).toBe('standard');
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should call init and register metadata service', async () => {
|
|
367
|
+
const { MetadataPlugin } = await import('./plugin');
|
|
368
|
+
const plugin = new MetadataPlugin({ rootDir: '/tmp/test', watch: false });
|
|
369
|
+
|
|
370
|
+
const ctx = createMockPluginContext();
|
|
371
|
+
await plugin.init(ctx);
|
|
372
|
+
|
|
373
|
+
expect(ctx.registerService).toHaveBeenCalledWith('metadata', expect.anything());
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('should call start and attempt to load metadata types', async () => {
|
|
377
|
+
const { MetadataPlugin } = await import('./plugin');
|
|
378
|
+
const plugin = new MetadataPlugin({ rootDir: '/tmp/test', watch: false });
|
|
379
|
+
|
|
380
|
+
const ctx = createMockPluginContext();
|
|
381
|
+
await plugin.init(ctx);
|
|
382
|
+
await plugin.start(ctx);
|
|
383
|
+
|
|
384
|
+
// start should call logger.info at least once
|
|
385
|
+
expect(ctx.logger.info).toHaveBeenCalled();
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// ---------- Helpers ----------
|
|
390
|
+
|
|
391
|
+
function createMockLoader(name: string, data: any, shouldFail = false): MetadataLoader {
|
|
392
|
+
return {
|
|
393
|
+
contract: { name, protocol: 'test', capabilities: { read: true, write: false, watch: false, list: true } },
|
|
394
|
+
load: shouldFail
|
|
395
|
+
? vi.fn().mockRejectedValue(new Error('loader failed'))
|
|
396
|
+
: vi.fn().mockResolvedValue({ data }),
|
|
397
|
+
loadMany: vi.fn().mockResolvedValue([]),
|
|
398
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
399
|
+
stat: vi.fn().mockResolvedValue(null),
|
|
400
|
+
list: vi.fn().mockResolvedValue([]),
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function createMockLoaderMany(name: string, items: any[], shouldFail = false): MetadataLoader {
|
|
405
|
+
return {
|
|
406
|
+
contract: { name, protocol: 'test', capabilities: { read: true, write: false, watch: false, list: true } },
|
|
407
|
+
load: vi.fn().mockResolvedValue({ data: null }),
|
|
408
|
+
loadMany: shouldFail
|
|
409
|
+
? vi.fn().mockRejectedValue(new Error('loader failed'))
|
|
410
|
+
: vi.fn().mockResolvedValue(items),
|
|
411
|
+
exists: vi.fn().mockResolvedValue(false),
|
|
412
|
+
stat: vi.fn().mockResolvedValue(null),
|
|
413
|
+
list: vi.fn().mockResolvedValue([]),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function createMockPluginContext() {
|
|
418
|
+
return {
|
|
419
|
+
registerService: vi.fn(),
|
|
420
|
+
getService: vi.fn().mockReturnValue(null),
|
|
421
|
+
getServices: vi.fn().mockReturnValue(new Map()),
|
|
422
|
+
hook: vi.fn(),
|
|
423
|
+
trigger: vi.fn(),
|
|
424
|
+
logger: {
|
|
425
|
+
info: vi.fn(),
|
|
426
|
+
warn: vi.fn(),
|
|
427
|
+
error: vi.fn(),
|
|
428
|
+
debug: vi.fn(),
|
|
429
|
+
},
|
|
430
|
+
getKernel: vi.fn(),
|
|
431
|
+
};
|
|
432
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from 'vitest/config';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
resolve: {
|
|
8
|
+
alias: {
|
|
9
|
+
'@objectstack/core': path.resolve(__dirname, '../core/src/index.ts'),
|
|
10
|
+
'@objectstack/spec/system': path.resolve(__dirname, '../spec/src/system/index.ts'),
|
|
11
|
+
'@objectstack/spec': path.resolve(__dirname, '../spec/src/index.ts'),
|
|
12
|
+
'@objectstack/types': path.resolve(__dirname, '../types/src/index.ts'),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
test: {
|
|
16
|
+
globals: true,
|
|
17
|
+
environment: 'node',
|
|
18
|
+
include: ['src/**/*.test.ts'],
|
|
19
|
+
},
|
|
20
|
+
});
|