Files
vendoo/app/kernel/module-contract.mjs
T
Masterluke77andGitHub 40071f718e Vendoo 1.43.0 – Production Update
Manifestbasierter Production-Updater 3.3, Modulnavigation, optionales Produktbild Studio, Listing-Studio-Aktionsleiste sowie plattformübergreifende Windows-/Linux-Release-Gates.
2026-07-10 13:16:21 +02:00

49 lines
3.0 KiB
JavaScript

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);
}