* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix * fix: track native source modules with root-anchored runtime ignores
81 lines
6.3 KiB
JavaScript
81 lines
6.3 KiB
JavaScript
import { readFileSync, readdirSync, existsSync } from 'fs';
|
|
import { resolve, extname, relative } from 'path';
|
|
import { spawnSync } from 'child_process';
|
|
|
|
const root = resolve(new URL('..', import.meta.url).pathname);
|
|
const failures = [];
|
|
const summary = { js_files: 0, json_files: 0, html_ids: 0, css_blocks: 0, nav_targets: 0, extension_packages: 0 };
|
|
function walk(dir) {
|
|
return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
const full = resolve(dir, entry.name);
|
|
if (entry.isDirectory()) return ['node_modules', '.git', 'uploads'].includes(entry.name) ? [] : walk(full);
|
|
return [full];
|
|
});
|
|
}
|
|
for (const file of walk(root)) {
|
|
const ext = extname(file).toLowerCase();
|
|
if (['.js', '.mjs'].includes(ext)) {
|
|
summary.js_files += 1;
|
|
const result = spawnSync(process.execPath, ['--check', file], { encoding: 'utf8' });
|
|
if (result.status !== 0) failures.push(`${relative(root, file)}: ${result.stderr.trim()}`);
|
|
}
|
|
if (ext === '.json') {
|
|
summary.json_files += 1;
|
|
try { JSON.parse(readFileSync(file, 'utf8').replace(/^\uFEFF/, '')); }
|
|
catch (error) { failures.push(`${relative(root, file)}: ungültiges JSON (${error.message})`); }
|
|
}
|
|
}
|
|
const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
|
|
const html = readFileSync(resolve(root, 'public/index.html'), 'utf8');
|
|
const app = readFileSync(resolve(root, 'public/app.js'), 'utf8');
|
|
const css = readFileSync(resolve(root, 'public/style.css'), 'utf8');
|
|
const server = readFileSync(resolve(root, 'server.mjs'), 'utf8');
|
|
const db = readFileSync(resolve(root, 'lib/db.mjs'), 'utf8');
|
|
const publishing = readFileSync(resolve(root, 'lib/publishing-jobs.mjs'), 'utf8');
|
|
const ebay = readFileSync(resolve(root, 'lib/ebay-api.mjs'), 'utf8');
|
|
const etsy = readFileSync(resolve(root, 'lib/etsy-api.mjs'), 'utf8');
|
|
if (pkg.version !== '1.29.0') failures.push(`package.json-Version ist ${pkg.version}`);
|
|
for (const marker of ['content="1.29.0"', 'style.css?v=1.29.0', 'app.js?v=1.29.0']) if (!html.includes(marker)) failures.push(`Build-Marker fehlt: ${marker}`);
|
|
if (!app.startsWith("const VENDOO_UI_BUILD = '1.29.0';")) failures.push('UI-Build ist nicht 1.29.0');
|
|
const ids = [...html.matchAll(/\bid="([^"]+)"/g)].map(match => match[1]);
|
|
summary.html_ids = ids.length;
|
|
const duplicateIds = [...new Set(ids.filter((id, index) => ids.indexOf(id) !== index))];
|
|
if (duplicateIds.length) failures.push(`Doppelte HTML-IDs: ${duplicateIds.join(', ')}`);
|
|
const sections = new Set([...html.matchAll(/<section\s+id="([^"]+)"/g)].map(match => match[1]));
|
|
const navTargets = [...html.matchAll(/class="[^"]*nav-item[^"]*"[^>]*data-tab="([^"]+)"/g)].map(match => match[1]);
|
|
summary.nav_targets = navTargets.length;
|
|
for (const target of navTargets) if (!sections.has(target)) failures.push(`Navigation ohne Zielsektion: ${target}`);
|
|
summary.css_blocks = (css.match(/{/g) || []).length;
|
|
if (summary.css_blocks !== (css.match(/}/g) || []).length) failures.push('CSS-Klammern unausgeglichen');
|
|
for (const marker of ['data-publish-view="queue"','data-publish-view="errors"','id="publish-error-count"','Zur Publishing-Queue']) if (!html.includes(marker)) failures.push(`Publishing-Hardening-UI fehlt: ${marker}`);
|
|
for (const marker of ['loadPublishingQueueData','renderPublishingErrorsWorkspace','runPublishingJobAction','deleteSelectedPublishingJobs','publishingStatusLabel']) if (!app.includes(marker)) failures.push(`Publishing-Hardening-JavaScript fehlt: ${marker}`);
|
|
for (const marker of ["app.get('/api/publishing/jobs'", "app.post('/api/publishing/jobs'", "app.post('/api/publishing/jobs/:id/retry'", "app.post('/api/publishing/jobs/:id/action'", "app.get('/api/publishing/events'", "app.post('/api/extension/publishing/:id/complete'"]) if (!server.includes(marker)) failures.push(`Publishing-Hardening-API fehlt: ${marker}`);
|
|
for (const marker of ['CREATE TABLE IF NOT EXISTS publishing_jobs','CREATE TABLE IF NOT EXISTS publishing_events','ALTER TABLE publish_log ADD COLUMN']) if (!db.includes(marker)) failures.push(`Publishing-Datenbank fehlt: ${marker}`);
|
|
for (const marker of ['enqueuePublishingJob','DUPLICATE_PUBLISH','retry_wait','recoverPublishingJobs','claimExtensionJob','completeExtensionJob','idempotency_key']) if (!publishing.includes(marker)) failures.push(`Publishing-Modul-Vertrag fehlt: ${marker}`);
|
|
for (const marker of ['getOffer','updateOffer','withdrawOffer']) if (!ebay.includes(`function ${marker}`)) failures.push(`eBay-Hardening fehlt: ${marker}`);
|
|
if (!etsy.includes('function getEtsyListing')) failures.push('Etsy-Statusabgleich fehlt');
|
|
for (const marker of ['5 / Seite','10 / Seite','15 / Seite','Publishing-Queue','Fehlerzentrale']) if (!app.includes(marker) && !html.includes(marker)) failures.push(`Queue-UX fehlt: ${marker}`);
|
|
for (const path of ['lib/publishing-jobs.mjs','docs/SLICE_34_PUBLISHING_HARDENING.md','local-ai/workflows/vendoo_flux_schnell_api.json']) if (!existsSync(resolve(root, path))) failures.push(`Pflichtdatei fehlt: ${path}`);
|
|
for (const browser of ['chrome','edge','firefox','safari']) {
|
|
const pkgPath = resolve(root, 'extensions/packages', `vendoo-link-${browser}-1.8.0.zip`);
|
|
if (!existsSync(pkgPath)) failures.push(`Extension-Paket fehlt: ${relative(root,pkgPath)}`); else summary.extension_packages += 1;
|
|
}
|
|
const dbResult = spawnSync('python', [resolve(root, 'tools/verify-db-migrations.py')], { encoding: 'utf8' });
|
|
if (dbResult.status !== 0) failures.push(`DB-Migration: ${dbResult.stderr || dbResult.stdout}`);
|
|
const uiResult = spawnSync(process.execPath, [resolve(root, 'tools/verify-ui-contracts-1.26.1.mjs')], { encoding: 'utf8' });
|
|
if (uiResult.status !== 0) failures.push(`UI-Verträge: ${uiResult.stderr || uiResult.stdout}`);
|
|
const workflow = readFileSync(resolve(root, 'local-ai/workflows/vendoo_flux_schnell_api.json'), 'utf8');
|
|
if (workflow.includes('LoadImage')) failures.push('Freier FLUX-Workflow enthält LoadImage');
|
|
if (/FASHN|virtual_tryon/i.test(server + app)) failures.push('Entfernte VTO/FASHN-Logik wieder aktiv');
|
|
if (failures.length) { console.error(JSON.stringify({ ok:false, failures, summary }, null, 2)); process.exit(1); }
|
|
console.log(JSON.stringify({
|
|
ok:true, version:pkg.version, ...summary,
|
|
persistent_publishing_queue:true,
|
|
duplicate_publish_guard:true,
|
|
automatic_retry:true,
|
|
restart_recovery:true,
|
|
extension_completion:true,
|
|
ebay_sync_update_end:true,
|
|
etsy_sync:true,
|
|
}, null, 2));
|