release: WRNexusJS 0.7.0

This commit is contained in:
2026-08-01 10:04:42 +05:30
parent c54144f2e4
commit 87507edf59
207 changed files with 12607 additions and 679 deletions
+120
View File
@@ -563,6 +563,71 @@ function writeMigrationReport(ctx: MigrationCtx): void {
* Versioned, idempotent upgrade steps. Each MUST be safe to re-run. Source
* migrations must preserve semantics and are protected by update backups.
*/
function updateV070Config(ctx: MigrationCtx): void {
const candidates = ["wrnexus.config.ts", "wrnexus.config.js", "wrnexus.config.mjs"];
const file = candidates.map((name) => join(ctx.appRoot, name)).find(existsSync);
if (!file) return;
const current = readFileSync(file, "utf8");
const additions: string[] = [];
if (!/\bnavigation\s*:/.test(current)) {
additions.push(` navigation: {
mode: "auto",
}`);
}
if (!/\bsecurity\s*:/.test(current)) {
additions.push(` security: {
headers: true,
requestLimits: {
maxUrlLength: 8192,
maxHeaderCount: 100,
maxHeaderBytes: 32768,
maxQueryParameters: 100,
maxBodyBytes: 10485760,
timeoutMs: 30000,
maxConcurrent: 1000,
fetchMetadata: true,
},
contentSecurityPolicy: { enabled: true, useDefaults: true },
trustedTypes: { enabled: true, requireForScript: true },
hsts: { enabled: true, maxAge: 63072000, includeSubDomains: true, preload: true },
}`);
}
if (!/\bperformance\s*:/.test(current)) {
additions.push(` performance: {
enforcement: "warn",
analyze: true,
budgets: {
routeJsBytes: 51200,
routeCssBytes: 25600,
htmlBytes: 204800,
hydrationMs: 200,
serverRenderMs: 500,
lcpMs: 2500,
inpMs: 200,
cls: 0.1,
ttfbMs: 800,
},
}`);
}
if (!/\bobservability\s*:/.test(current)) {
additions.push(` observability: {
enabled: true,
serverTiming: true,
sampleRate: 0.1,
exporter: "none",
webVitals: true,
}`);
}
if (!additions.length) return;
const index = current.lastIndexOf("}");
if (index < 0) return;
const before = current.slice(0, index).replace(/,?\s*$/, "");
const next = `${before},\n${additions.join(",\n")}\n${current.slice(index)}`;
ctx.log(`~ ${file.slice(ctx.appRoot.length + 1)}: security/performance production defaults`);
if (!ctx.dryRun) writeFileSync(file, next, "utf8");
}
const MIGRATIONS: Migration[] = [
{
version: "0.2.8",
@@ -1737,6 +1802,61 @@ const MIGRATIONS: Migration[] = [
writeMigrationReport(ctx);
},
},
{
version: "0.7.0",
id: "0.7.0-01-security-performance-foundation",
description:
"Adds secure-by-default request limits, caching, image optimization, observability, benchmarks, and production hardening packages.",
apply(ctx) {
const file = join(ctx.appRoot, "package.json");
if (existsSync(file)) {
const pkg = JSON.parse(readFileSync(file, "utf8")) as Record<string, any>;
const dependencies = (pkg.dependencies ??= {});
const devDependencies = (pkg.devDependencies ??= {});
const added: string[] = [];
for (const name of [
"@wrnexus/security",
"@wrnexus/cache",
"@wrnexus/image",
"@wrnexus/observability",
]) {
if (dependencies[name] === `^${ctx.to}`) continue;
dependencies[name] = `^${ctx.to}`;
added.push(name);
}
if (devDependencies["@wrnexus/benchmark"] !== `^${ctx.to}`) {
devDependencies["@wrnexus/benchmark"] = `^${ctx.to}`;
added.push("@wrnexus/benchmark (dev)");
}
if (added.length) {
ctx.log(`+ security/performance dependencies: ${added.join(", ")}`);
if (!ctx.dryRun) writeFileSync(file, JSON.stringify(pkg, null, 2) + "\n", "utf8");
}
}
updateV070Config(ctx);
const gitignore = join(ctx.appRoot, ".gitignore");
const currentIgnore = existsSync(gitignore) ? readFileSync(gitignore, "utf8") : "";
const ignoreEntries = [".env", ".env.*", "!.env.example", "!.env.*.example"];
const knownIgnore = new Set(currentIgnore.split(/\r?\n/).map((line) => line.trim()));
const missingIgnore = ignoreEntries.filter((entry) => !knownIgnore.has(entry));
if (missingIgnore.length) {
ctx.log(`+ .gitignore secure environment templates: ${missingIgnore.join(", ")}`);
if (!ctx.dryRun) {
writeFileSync(
gitignore,
`${currentIgnore.replace(/\s*$/, "")}\n${missingIgnore.join("\n")}\n`.replace(
/^\n+/,
"",
),
"utf8",
);
}
}
const review =
"Review WRNexusJS 0.7 security policy, CSP allowlists, tenant authorization, upload scanners, cache adapters, and production performance budgets.";
if (!ctx.report.needsReview.includes(review)) ctx.report.needsReview.push(review);
},
},
];
/** Release tooling uses this to require an explicit migration entry per version. */