Files
Rental-operations-platform/scripts/validate-phase14-integrations.mjs
2026-06-25 20:08:39 -04:00

73 lines
2.5 KiB
JavaScript

import { readFile, stat } from 'node:fs/promises';
import path from 'node:path';
import { fail, pass, repositoryRoot } from './lib.mjs';
const failures = [];
const requiredFiles = [
'src/app/api/demo/route.ts',
'src/components/integrations/DemoDialogHost.tsx',
'src/lib/demo/schema.ts',
'src/lib/demo/service.ts',
'src/lib/demo/idempotency.ts',
'src/lib/demo/adapters/types.ts',
'src/lib/demo/adapters/local.ts',
'src/lib/demo/adapters/blocked.ts',
'src/lib/integrations/destinations.ts',
'src/lib/integrations/environment.ts',
'src/lib/integrations/feature-flags.ts',
'src/lib/analytics/events.ts',
'src/lib/analytics/client.ts',
'docs/phase14/INTEGRATION_TRACEABILITY_MATRIX_v1.0.csv',
'docs/phase14/DATA_FLOW_INVENTORY_v1.0.csv',
'docs/phase14/RELEASE_GATE_MATRIX_v1.0.csv',
];
for (const file of requiredFiles) {
try {
const details = await stat(path.join(repositoryRoot, file));
if (!details.isFile()) failures.push(`${file}: not a file.`);
} catch {
failures.push(`${file}: missing.`);
}
}
const schema = await readFile(path.join(repositoryRoot, 'src/lib/demo/schema.ts'), 'utf8');
for (const field of ['fullName', 'workEmail', 'company', 'fleetSize', 'idempotencyKey', 'source']) {
if (!schema.includes(`${field}:`)) failures.push(`Demo schema is missing ${field}.`);
}
if (!schema.includes('.strict()'))
failures.push('Demo transport schemas must reject unknown fields.');
if (schema.includes('phone:'))
failures.push('Unapproved phone field was added to the demo contract.');
const destinations = await readFile(
path.join(repositoryRoot, 'src/lib/integrations/destinations.ts'),
'utf8',
);
for (const issue of ['P9-002', 'P9-003', 'P9-004', 'P9-008', 'P9-012', 'P9-014', 'P9-015']) {
if (!destinations.includes(issue))
failures.push(`Destination registry does not preserve ${issue}.`);
}
if (/href:\s*['"]https?:\/\//.test(destinations)) {
failures.push('Destination registry contains an unapproved hard-coded external URL.');
}
for (const locale of ['en', 'fr', 'ar']) {
const catalog = JSON.parse(
await readFile(
path.join(repositoryRoot, `src/content/locales/${locale}/homepage.json`),
'utf8',
),
);
if (!catalog.form || catalog.form.fleetOptions?.length !== 7) {
failures.push(
`${locale}: demo form fleet options do not match the approved six-value contract.`,
);
}
}
if (failures.length) fail(failures);
else
pass(
'Phase 14 integration structure, form contract, destinations, and locale resources are present.',
);