release: WRNexusJS 0.8.0
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
import console from "node:console";
|
||||
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import process from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
const failures = [];
|
||||
function check(name, condition, detail = "") {
|
||||
if (condition) {
|
||||
passed++;
|
||||
console.log(` ok ${name}`);
|
||||
return;
|
||||
}
|
||||
failed++;
|
||||
failures.push(detail ? `${name}: ${detail}` : name);
|
||||
console.error(` FAIL ${name}${detail ? ` — ${detail}` : ""}`);
|
||||
}
|
||||
function text(path) {
|
||||
return readFileSync(join(root, path), "utf8");
|
||||
}
|
||||
function has(path, value) {
|
||||
const source = text(path);
|
||||
return typeof value === "string" ? source.includes(value) : value.test(source);
|
||||
}
|
||||
|
||||
const rootManifest = JSON.parse(text("package.json"));
|
||||
check(
|
||||
"repository governance documents exist",
|
||||
["LICENSE", "SECURITY.md", "CONTRIBUTING.md", "CHANGELOG.md", "CODE_OF_CONDUCT.md"].every(
|
||||
(file) => existsSync(join(root, file)),
|
||||
),
|
||||
);
|
||||
const packageManifests = readdirSync(join(root, "packages"), { withFileTypes: true })
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.isDirectory() && existsSync(join(root, "packages", entry.name, "package.json")),
|
||||
)
|
||||
.map((entry) => JSON.parse(text(`packages/${entry.name}/package.json`)));
|
||||
const workspaceManifests = ["packages", "examples", "services"].flatMap((directory) =>
|
||||
readdirSync(join(root, directory), { withFileTypes: true })
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.isDirectory() && existsSync(join(root, directory, entry.name, "package.json")),
|
||||
)
|
||||
.map((entry) => JSON.parse(text(`${directory}/${entry.name}/package.json`))),
|
||||
);
|
||||
check(
|
||||
"package manifests avoid floating latest dependency ranges",
|
||||
![rootManifest, ...workspaceManifests].some((manifest) =>
|
||||
[manifest.dependencies, manifest.devDependencies, manifest.peerDependencies].some((group) =>
|
||||
Object.values(group ?? {}).includes("latest"),
|
||||
),
|
||||
),
|
||||
);
|
||||
check("root version is 0.8.0", rootManifest.version === "0.8.0");
|
||||
check(
|
||||
"all framework packages use 0.8.0",
|
||||
packageManifests.every((manifest) => manifest.version === "0.8.0"),
|
||||
);
|
||||
check(
|
||||
"standalone realtime package exists",
|
||||
existsSync(join(root, "packages/realtime/src/index.ts")) &&
|
||||
existsSync(join(root, "packages/realtime/components/RealtimeRoom.wrn")),
|
||||
);
|
||||
check(
|
||||
"auth provides helper and UI block kits",
|
||||
existsSync(join(root, "packages/auth/src/helpers.ts")) &&
|
||||
existsSync(join(root, "packages/auth/components/AuthShell.wrn")) &&
|
||||
has("packages/auth/package.json", '"@wrnexus/ui": "workspace:*"'),
|
||||
);
|
||||
check(
|
||||
"captcha provides helper and UI wrapper kits",
|
||||
existsSync(join(root, "packages/captcha/src/helpers.ts")) &&
|
||||
existsSync(join(root, "packages/captcha/components/CaptchaField.wrn")),
|
||||
);
|
||||
check(
|
||||
"database repository helpers exist",
|
||||
has("packages/db/src/helpers.ts", "createRepository") &&
|
||||
has("packages/db/src/helpers.ts", "retryTransaction"),
|
||||
);
|
||||
check(
|
||||
"database repositories use dialect-aware placeholders",
|
||||
has("packages/db/src/helpers.ts", 'dialect === "postgres" ? `$${index}` : "?"') &&
|
||||
has("packages/db/test/helpers.test.ts", "VALUES ($1)"),
|
||||
);
|
||||
check(
|
||||
"encrypted HTTP envelope is context and replay bound",
|
||||
has("packages/encryption/src/http.ts", "WRN-ENCRYPTION-HTTP-REPLAY") &&
|
||||
has("packages/encryption/src/http.ts", "payload.path !== normalizePath"),
|
||||
);
|
||||
check(
|
||||
"encrypted responses are request-id bound and application errors propagate",
|
||||
has("packages/encryption/src/http.ts", "expectedRequestId: requestId") &&
|
||||
has("packages/encryption/src/http.ts", "const response = await next();"),
|
||||
);
|
||||
check(
|
||||
"encryption documentation preserves HTTPS boundary",
|
||||
has("packages/encryption/README.md", /TLS|HTTPS/) &&
|
||||
has("packages/encryption/README.md", /browser|end user/i),
|
||||
);
|
||||
check(
|
||||
"JWT access, refresh, scope, cookie, and pair helpers exist",
|
||||
[
|
||||
"createAccessToken",
|
||||
"createRefreshToken",
|
||||
"requireScopes",
|
||||
"jwtCookie",
|
||||
"readJwtCookie",
|
||||
"createTokenPair",
|
||||
].every((name) => has("packages/jwt/src/helpers.ts", name)),
|
||||
);
|
||||
check(
|
||||
"i18n supports nested locales and quality negotiation",
|
||||
has("packages/i18n/src/index.ts", "localeFiles") &&
|
||||
has("packages/i18n/src/index.ts", "parseAcceptLanguage"),
|
||||
);
|
||||
check(
|
||||
"i18n safely resolves namespace collisions and wildcard language ranges",
|
||||
has("packages/i18n/src/index.ts", 'tag?.trim() === "*"') &&
|
||||
has("packages/i18n/test/package-kit.test.ts", "primitive namespace collisions"),
|
||||
);
|
||||
check(
|
||||
"i18n runtime data is injected into rendered documents",
|
||||
has("packages/dev-server/src/runtime.ts", "renderI18nData(deps.i18n, language)") &&
|
||||
has("packages/dev-server/src/runtime.ts", "deps.i18n.cookie.name"),
|
||||
);
|
||||
check(
|
||||
"image package provides picture, loaders, placeholder, and preload helpers",
|
||||
["createPicture", "createCdnImageLoader", "createBlurPlaceholder", "imagePreload"].every((name) =>
|
||||
has("packages/image/src/index.ts", name),
|
||||
),
|
||||
);
|
||||
check(
|
||||
"image helpers validate finite dimensions and preserve URL fragments",
|
||||
has("packages/image/src/index.ts", "Image width bounds must be finite") &&
|
||||
has("packages/image/test/package-kit.test.ts", "URL fragments"),
|
||||
);
|
||||
check(
|
||||
"realtime messages are size, room, type, and payload bounded",
|
||||
has("packages/realtime/src/messages.ts", "maxBytes") &&
|
||||
has("packages/realtime/src/messages.ts", "Unsafe realtime payload key"),
|
||||
);
|
||||
check(
|
||||
"auth shell uses statically discoverable Tailwind width classes",
|
||||
!has("packages/auth/components/AuthShell.wrn", "max-w-{maxWidth}") &&
|
||||
has("packages/auth/components/AuthShell.wrn", "class:max-w-md"),
|
||||
);
|
||||
check(
|
||||
"uploader package provides UI blocks and helpers",
|
||||
existsSync(join(root, "packages/uploader/components/UploadDropzone.wrn")) &&
|
||||
existsSync(join(root, "packages/uploader/src/helpers.ts")),
|
||||
);
|
||||
check(
|
||||
"validation package provides UI blocks and helpers",
|
||||
existsSync(join(root, "packages/validation/components/ValidationSummary.wrn")) &&
|
||||
existsSync(join(root, "packages/validation/src/helpers.ts")),
|
||||
);
|
||||
check(
|
||||
"validation schemas infer helper output types",
|
||||
has("packages/validation/src/index.ts", "export type InferSchema") &&
|
||||
has("packages/validation/src/helpers.ts", "schema: ObjectSchema<T>") &&
|
||||
has("packages/validation/test/helpers.test.ts", "const email: string = value.email"),
|
||||
);
|
||||
check(
|
||||
"validation oneOf preserves literal union types",
|
||||
has("packages/validation/src/index.ts", "class StringSchema<TValue extends string") &&
|
||||
has("packages/validation/src/index.ts", "TValues extends readonly [string, ...string[]]") &&
|
||||
has("packages/validation/test/helpers.test.ts", "const schema: ObjectSchema<ContactInput>"),
|
||||
);
|
||||
check("0.8 migration exists", has("packages/cli/src/update.ts", 'id: "0.8.0-01-package-kits"'));
|
||||
check(
|
||||
"package kit audit exists",
|
||||
existsSync(join(root, "scripts/audit-package-kits.mjs")) &&
|
||||
rootManifest.scripts?.["audit:packages"] === "node scripts/audit-package-kits.mjs",
|
||||
);
|
||||
check(
|
||||
"audit validators are read-only and reports use explicit generators",
|
||||
rootManifest.scripts?.["security:framework"] === "node scripts/security-performance-audit.mjs" &&
|
||||
rootManifest.scripts?.["generate:security-report"] ===
|
||||
"node scripts/security-performance-audit.mjs --write" &&
|
||||
rootManifest.scripts?.["generate:package-audit"] ===
|
||||
"node scripts/audit-package-kits.mjs --write" &&
|
||||
has("scripts/security-performance-audit.mjs", 'process.argv.includes("--write")') &&
|
||||
has("scripts/audit-package-kits.mjs", 'process.argv.includes("--write")'),
|
||||
);
|
||||
const publicApi = spawnSync(process.execPath, ["scripts/check-public-api.mjs"], {
|
||||
cwd: root,
|
||||
encoding: "utf8",
|
||||
});
|
||||
if (publicApi.stdout) process.stdout.write(publicApi.stdout);
|
||||
if (publicApi.stderr) process.stderr.write(publicApi.stderr);
|
||||
check(
|
||||
"public package exports match the reviewed API baseline",
|
||||
publicApi.status === 0 && existsSync(join(root, "docs/public-api-0.8.json")),
|
||||
);
|
||||
const audit = spawnSync(process.execPath, ["scripts/audit-package-kits.mjs"], {
|
||||
cwd: root,
|
||||
encoding: "utf8",
|
||||
});
|
||||
if (audit.stdout) process.stdout.write(audit.stdout);
|
||||
if (audit.stderr) process.stderr.write(audit.stderr);
|
||||
check("all package kits pass the executable audit", audit.status === 0);
|
||||
const runtimeProbe = spawnSync(
|
||||
process.execPath,
|
||||
["--experimental-transform-types", "scripts/test-package-kits.mjs"],
|
||||
{ cwd: root, encoding: "utf8" },
|
||||
);
|
||||
if (runtimeProbe.stdout) process.stdout.write(runtimeProbe.stdout);
|
||||
if (runtimeProbe.stderr) process.stderr.write(runtimeProbe.stderr);
|
||||
check("package helper runtime probes pass", runtimeProbe.status === 0);
|
||||
check(
|
||||
"package helper APIs have dedicated tests",
|
||||
[
|
||||
"packages/encryption/test/http.test.ts",
|
||||
"packages/jwt/test/helpers.test.ts",
|
||||
"packages/db/test/helpers.test.ts",
|
||||
"packages/i18n/test/package-kit.test.ts",
|
||||
"packages/image/test/package-kit.test.ts",
|
||||
"packages/captcha/test/helpers.test.ts",
|
||||
"packages/uploader/test/helpers.test.ts",
|
||||
"packages/validation/test/helpers.test.ts",
|
||||
"packages/realtime/test/realtime.test.ts",
|
||||
"packages/auth/test/package-components.test.ts",
|
||||
].every((path) => existsSync(join(root, path))),
|
||||
);
|
||||
console.log(`\n${passed} passed`);
|
||||
console.log(`${failed} failed`);
|
||||
if (failed) {
|
||||
console.error("\nFailures:");
|
||||
for (const value of failures) console.error(`- ${value}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user