Problem: Need to ensure all npm packages are at least 2 weeks old before use Solution: - Created check-package-age.js script to verify package publish dates - Added .npmrc to enforce exact version installation - Created pin-old-versions.sh helper script - Documented complete workflow in NPM-PACKAGE-AGE-POLICY.md Usage: node scripts/check-package-age.js # Verify all packages ≥ 2 weeks old npm ci # Install exact versions from lock file 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
103 lines
2.9 KiB
JavaScript
Executable File
103 lines
2.9 KiB
JavaScript
Executable File
#!/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();
|