#!/usr/bin/env node /** * Check if npm packages are at least 2 weeks old before installation * Usage: node scripts/check-package-age.js */ const https = require('https'); const fs = require('fs'); const path = require('path'); const TWO_WEEKS_MS = 14 * 24 * 60 * 60 * 1000; function getPackageInfo(packageName, version) { return new Promise((resolve, reject) => { // Remove version prefixes like ^, ~, >= const cleanVersion = version.replace(/^[\^~>=]+/, ''); const url = `https://registry.npmjs.org/${packageName}/${cleanVersion}`; https.get(url, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const info = JSON.parse(data); resolve({ name: packageName, version: cleanVersion, published: info.time || info._time, error: null }); } catch (err) { reject(new Error(`Failed to parse response for ${packageName}@${cleanVersion}`)); } }); }).on('error', (err) => { reject(err); }); }); } async function checkPackageAge() { const packageJsonPath = path.join(__dirname, '../frontend/package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies }; console.log('Checking package ages (must be at least 2 weeks old)...\n'); const tooNew = []; const errors = []; for (const [name, version] of Object.entries(allDeps)) { try { const info = await getPackageInfo(name, version); const publishDate = new Date(info.published); const age = Date.now() - publishDate.getTime(); const ageInDays = Math.floor(age / (24 * 60 * 60 * 1000)); if (age < TWO_WEEKS_MS) { tooNew.push({ name, version: info.version, age: ageInDays, published: publishDate.toISOString().split('T')[0] }); console.log(`❌ ${name}@${info.version} - ${ageInDays} days old (published ${publishDate.toISOString().split('T')[0]})`); } else { console.log(`✓ ${name}@${info.version} - ${ageInDays} days old`); } } catch (err) { errors.push({ name, version, error: err.message }); console.log(`⚠️ ${name}@${version} - Could not check: ${err.message}`); } } console.log('\n' + '='.repeat(80)); if (tooNew.length > 0) { console.log(`\n❌ FAILED: ${tooNew.length} package(s) are newer than 2 weeks:\n`); tooNew.forEach(pkg => { console.log(` - ${pkg.name}@${pkg.version} (${pkg.age} days old, published ${pkg.published})`); }); process.exit(1); } else if (errors.length > 0) { console.log(`\n⚠️ WARNING: Could not verify ${errors.length} package(s)`); process.exit(0); } else { console.log('\n✓ SUCCESS: All packages are at least 2 weeks old'); process.exit(0); } } checkPackageAge();