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,17 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
{
|
||||
files: ["src/**/*.js", "test/**/*.js"],
|
||||
languageOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
globals: { ...globals.node },
|
||||
},
|
||||
rules: {
|
||||
"no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
||||
},
|
||||
},
|
||||
];
|
||||
Generated
+2429
File diff suppressed because it is too large
Load Diff
+18
-16
@@ -4,25 +4,27 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node src/server.js",
|
||||
"dev": "node --watch src/server.js",
|
||||
"test": "node --test",
|
||||
"lint": "eslint src --ext .js"
|
||||
"dev": "node --watch src/server.js",
|
||||
"test": "node --test",
|
||||
"lint": "eslint src test"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"express-rate-limit": "^7.4.0",
|
||||
"helmet": "^7.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"pg": "^8.13.3",
|
||||
"pino": "^9.0.0",
|
||||
"pino-http": "^10.0.0",
|
||||
"pino-pretty": "^13.0.0"
|
||||
"bcryptjs": "^3.0.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.6",
|
||||
"dotenv": "^17.4.2",
|
||||
"express": "^5.2.1",
|
||||
"express-rate-limit": "^8.7.0",
|
||||
"helmet": "^8.3.0",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"pg": "^8.23.0",
|
||||
"pino": "^10.3.1",
|
||||
"pino-http": "^11.0.0",
|
||||
"pino-pretty": "^13.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.57.0"
|
||||
"@eslint/js": "^10.0.1",
|
||||
"eslint": "^10.9.1",
|
||||
"globals": "^17.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ app.use("/api/data", dataRouter);
|
||||
app.use("/api/users", usersRouter);
|
||||
|
||||
// ── 404 voor overige /api/* ───────────────────────────────────────────────────
|
||||
app.use("/api/*", (_req, res) => res.status(404).json({ error: "Endpoint niet gevonden." }));
|
||||
// Zonder pad-patroon met wildcard: Express 5 vereist benoemde wildcards
|
||||
// (/api/*splat), en een prefix-mount doet hier precies hetzelfde.
|
||||
app.use("/api", (_req, res) => res.status(404).json({ error: "Endpoint niet gevonden." }));
|
||||
|
||||
// ── Frontend (Vite build) ─────────────────────────────────────────────────────
|
||||
const indexHtml = join(config.STATIC_DIR, "index.html");
|
||||
@@ -82,8 +84,10 @@ if (servesFrontend) {
|
||||
},
|
||||
}));
|
||||
|
||||
// SPA-fallback: alle overige GET-routes naar index.html.
|
||||
app.get("*", (_req, res) => {
|
||||
// SPA-fallback: alle overige GET-routes naar index.html. Pathloze middleware
|
||||
// in plaats van app.get("*") — dat patroon is in Express 5 ongeldig.
|
||||
app.use((req, res, next) => {
|
||||
if (req.method !== "GET" && req.method !== "HEAD") return next();
|
||||
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
res.sendFile(indexHtml);
|
||||
});
|
||||
|
||||
@@ -105,13 +105,18 @@ describe("Security headers", () => {
|
||||
assert.doesNotMatch(csp, /upgrade-insecure-requests/);
|
||||
});
|
||||
|
||||
// express-rate-limit gebruikt per RFC-draft andere headernamen
|
||||
// (RateLimit-Limit vs. RateLimit); daarom op de hele familie testen.
|
||||
const heeftRateLimitHeaders = (res) =>
|
||||
[...res.headers.keys()].some((naam) => naam.startsWith("ratelimit"));
|
||||
|
||||
it("statische bestanden krijgen geen rate-limit headers", async () => {
|
||||
const res = await fetch(`${basis}/assets/index-abc12345.js`);
|
||||
assert.equal(res.headers.get("ratelimit-limit"), null);
|
||||
assert.equal(heeftRateLimitHeaders(res), false);
|
||||
});
|
||||
|
||||
it("de API krijgt wel rate-limit headers", async () => {
|
||||
const res = await fetch(`${basis}/api/health`);
|
||||
assert.notEqual(res.headers.get("ratelimit-limit"), null);
|
||||
assert.equal(heeftRateLimitHeaders(res), true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user