import { PlatformError } from './errors.mjs'; const MODULE_ID = /^vendoo\.[a-z][a-z0-9-]*$/; const SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; const CAPABILITY = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)+$/; const TYPES = new Set(['core', 'feature', 'adapter', 'extension-host']); const STATUSES = new Set(['native', 'legacy-bridge', 'disabled']); function uniqueStrings(values, label, pattern = CAPABILITY) { if (!Array.isArray(values)) throw new PlatformError(`${label} muss ein Array sein.`, { code: 'MODULE_MANIFEST_INVALID' }); const normalized = values.map(value => String(value || '').trim()); if (normalized.some(value => !pattern.test(value))) { throw new PlatformError(`${label} enthält einen ungültigen Eintrag.`, { code: 'MODULE_MANIFEST_INVALID' }); } if (new Set(normalized).size !== normalized.length) { throw new PlatformError(`${label} enthält Duplikate.`, { code: 'MODULE_MANIFEST_INVALID' }); } return normalized; } export function validateModuleManifest(manifest) { if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) { throw new PlatformError('Modulmanifest fehlt oder ist ungültig.', { code: 'MODULE_MANIFEST_INVALID' }); } const normalized = { schemaVersion: Number(manifest.schemaVersion || 1), id: String(manifest.id || '').trim(), name: String(manifest.name || '').trim(), version: String(manifest.version || '').trim(), type: String(manifest.type || '').trim(), status: String(manifest.status || 'native').trim(), defaultEnabled: manifest.defaultEnabled !== false, description: String(manifest.description || '').trim(), requires: Object.freeze(uniqueStrings(manifest.requires || [], 'requires', MODULE_ID)), permissions: Object.freeze(uniqueStrings(manifest.permissions || [], 'permissions')), provides: Object.freeze(uniqueStrings(manifest.provides || [], 'provides')), consumes: Object.freeze(uniqueStrings(manifest.consumes || [], 'consumes')), owns: Object.freeze(uniqueStrings(manifest.owns || [], 'owns')), }; if (normalized.schemaVersion !== 1) throw new PlatformError('Nicht unterstützte Manifestversion.', { code: 'MODULE_MANIFEST_VERSION' }); if (!MODULE_ID.test(normalized.id)) throw new PlatformError(`Ungültige Modul-ID: ${normalized.id}`, { code: 'MODULE_ID_INVALID' }); if (!normalized.name) throw new PlatformError(`Modulname fehlt: ${normalized.id}`, { code: 'MODULE_NAME_REQUIRED' }); if (!SEMVER.test(normalized.version)) throw new PlatformError(`Ungültige Modulversion: ${normalized.id}`, { code: 'MODULE_VERSION_INVALID' }); if (!TYPES.has(normalized.type)) throw new PlatformError(`Ungültiger Modultyp: ${normalized.id}`, { code: 'MODULE_TYPE_INVALID' }); if (!STATUSES.has(normalized.status)) throw new PlatformError(`Ungültiger Modulstatus: ${normalized.id}`, { code: 'MODULE_STATUS_INVALID' }); if (normalized.requires.includes(normalized.id)) throw new PlatformError(`Modul darf sich nicht selbst benötigen: ${normalized.id}`, { code: 'MODULE_SELF_DEPENDENCY' }); return Object.freeze(normalized); }