Dependencies naar de nieuwste versies + update-check in de testsuite
Upgrades
- Frontend: React 19.2, Vite 8.2, @vitejs/plugin-react 6.1, ESLint 9.39
- Backend: Express 5.2, Helmet 8.3, express-rate-limit 8.7, pino 10.3,
pino-http 11, pg 8.23, dotenv 17.4, bcryptjs 3.0, ESLint 10.9
- Lockfiles opnieuw gegenereerd (backend had er geen)
Breaking changes opgevangen
- Express 5 laat kale wildcards in routes niet toe: app.use("/api/*") is een
prefix-mount geworden en app.get("*") pad-loze middleware
- Vite 8 bundelt met Rolldown, dat de object-vorm van manualChunks niet kent;
omgezet naar build.rollupOptions.output.advancedChunks
- Rate-limit headers verschillen per RFC-draft; de test kijkt nu naar de hele
RateLimit-headerfamilie in plaats van naar RateLimit-Limit
- ESLint blijft in de frontend op 9: eslint-plugin-react ondersteunt nog geen
ESLint 10 (peer <= ^9.7)
Update-check bij het testen
- docker/check-updates.mjs vergelijkt beide package.json's met het
npm-register; werkt zonder node_modules en zonder npm install
- test.ps1 draait dit als stap 1 van 4, met -Strict (falen) en -SkipDeps
(offline). Ook informatief in de Test-stage van de pipeline
- Bewuste uitzonderingen met reden in docker/update-exceptions.json
- dev.ps1 up gebruikt --renew-anon-volumes, anders houdt de dev-container de
oude node_modules na een upgrade
Overig
- ESLint flat configs voor beide packages; npm run lint werkte niet omdat er
geen configuratie was. Beide draaien nu groen (alleen waarschuwingen over
bestaande ongebruikte variabelen)
- README.md, BEHEER.md en Changelog.md bijgewerkt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bfec3a25f3
commit
1c0eed61f6
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Controleert of de dependencies in package.json op de laatste versie staan.
|
||||
*
|
||||
* Vergelijkt de versie in package.json met "latest" in het npm-register. Werkt
|
||||
* zonder node_modules en zonder npm install, dus geschikt als snelle check in
|
||||
* de testsuite.
|
||||
*
|
||||
* Gebruik: node docker/check-updates.mjs [map ...]
|
||||
* node docker/check-updates.mjs frontend backend
|
||||
*
|
||||
* Exit 0 = alles actueel (of alleen waarschuwingen)
|
||||
* Exit 1 = achterstand gevonden én --strict meegegeven
|
||||
*/
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const strict = args.includes("--strict");
|
||||
const mappen = args.filter((a) => !a.startsWith("--"));
|
||||
const doelen = mappen.length ? mappen : ["frontend", "backend"];
|
||||
|
||||
/** "^1.2.3" → [1,2,3] */
|
||||
function ontleed(versie) {
|
||||
const schoon = String(versie).replace(/^[\^~>=<\s]*/, "").split("-")[0];
|
||||
const delen = schoon.split(".").map((n) => parseInt(n, 10) || 0);
|
||||
return [delen[0] ?? 0, delen[1] ?? 0, delen[2] ?? 0];
|
||||
}
|
||||
|
||||
/** Vergelijkt twee versies: -1 kleiner, 0 gelijk, 1 groter */
|
||||
function vergelijk(a, b) {
|
||||
const va = ontleed(a), vb = ontleed(b);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (va[i] !== vb[i]) return va[i] < vb[i] ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Welk deel van het versienummer verschilt */
|
||||
function soort(huidig, laatste) {
|
||||
const va = ontleed(huidig), vb = ontleed(laatste);
|
||||
if (va[0] !== vb[0]) return "major";
|
||||
if (va[1] !== vb[1]) return "minor";
|
||||
return "patch";
|
||||
}
|
||||
|
||||
async function laatsteVersie(naam) {
|
||||
const url = `https://registry.npmjs.org/${naam.replace("/", "%2F")}/latest`;
|
||||
const res = await fetch(url, { signal: AbortSignal.timeout(10000) });
|
||||
if (!res.ok) throw new Error(`register gaf ${res.status}`);
|
||||
return (await res.json()).version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bewuste uitzonderingen: dependencies die om een reden achterblijven.
|
||||
* Staan in docker/update-exceptions.json en laten de check niet falen.
|
||||
*/
|
||||
async function leesUitzonderingen() {
|
||||
try {
|
||||
const ruw = await readFile(join(process.cwd(), "docker", "update-exceptions.json"), "utf8");
|
||||
return JSON.parse(ruw);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
const uitzonderingen = await leesUitzonderingen();
|
||||
|
||||
let achterstand = 0;
|
||||
let mislukt = 0;
|
||||
|
||||
for (const map of doelen) {
|
||||
const pad = join(process.cwd(), map, "package.json");
|
||||
let pkg;
|
||||
try {
|
||||
pkg = JSON.parse(await readFile(pad, "utf8"));
|
||||
} catch {
|
||||
console.log(`\n${map}/package.json niet gevonden — overgeslagen`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
|
||||
const namen = Object.keys(deps).sort();
|
||||
|
||||
console.log(`\n${map}/package.json (${namen.length} dependencies)`);
|
||||
|
||||
const resultaten = await Promise.all(namen.map(async (naam) => {
|
||||
const huidig = deps[naam];
|
||||
// Alleen echte versienummers vergelijken (geen git/file/workspace ranges)
|
||||
if (!/^[\^~]?\d/.test(huidig)) return { naam, huidig, status: "overgeslagen" };
|
||||
try {
|
||||
const laatste = await laatsteVersie(naam);
|
||||
return vergelijk(huidig, laatste) < 0
|
||||
? { naam, huidig, laatste, status: "verouderd", soort: soort(huidig, laatste) }
|
||||
: { naam, huidig, laatste, status: "actueel" };
|
||||
} catch (err) {
|
||||
return { naam, huidig, status: "onbekend", fout: err.message };
|
||||
}
|
||||
}));
|
||||
|
||||
const verouderd = resultaten.filter((r) => r.status === "verouderd" && !(uitzonderingen[map]?.[r.naam]));
|
||||
const vastgezet = resultaten.filter((r) => r.status === "verouderd" && uitzonderingen[map]?.[r.naam]);
|
||||
const onbekend = resultaten.filter((r) => r.status === "onbekend");
|
||||
|
||||
for (const r of verouderd) {
|
||||
console.log(` [${r.soort.padEnd(5)}] ${r.naam.padEnd(24)} ${r.huidig.padEnd(12)} → ${r.laatste}`);
|
||||
}
|
||||
for (const r of vastgezet) {
|
||||
console.log(` [vast ] ${r.naam.padEnd(24)} ${r.huidig.padEnd(12)} → ${String(r.laatste).padEnd(10)} ${uitzonderingen[map][r.naam]}`);
|
||||
}
|
||||
for (const r of onbekend) {
|
||||
console.log(` [? ] ${r.naam.padEnd(24)} kon niet worden opgezocht (${r.fout})`);
|
||||
}
|
||||
if (!verouderd.length && !vastgezet.length && !onbekend.length) {
|
||||
console.log(" alles actueel");
|
||||
} else if (!verouderd.length && !onbekend.length) {
|
||||
console.log(" actueel op de vastgezette versies na");
|
||||
}
|
||||
|
||||
achterstand += verouderd.length;
|
||||
mislukt += onbekend.length;
|
||||
}
|
||||
|
||||
console.log("");
|
||||
if (achterstand === 0) {
|
||||
console.log(mislukt ? `Geen achterstand gevonden (${mislukt} niet opgezocht).` : "Alle dependencies staan op de laatste versie.");
|
||||
} else {
|
||||
console.log(`${achterstand} dependency(s) niet op de laatste versie.`);
|
||||
console.log("Bijwerken: pas package.json aan en herschrijf de lockfile:");
|
||||
console.log(" docker run --rm -v ${PWD}/<map>:/w -w /w node:22-alpine npm install --package-lock-only");
|
||||
}
|
||||
|
||||
process.exit(achterstand > 0 && strict ? 1 : 0);
|
||||
Reference in New Issue
Block a user