156 lines
5.8 KiB
JavaScript
156 lines
5.8 KiB
JavaScript
import console from "node:console";
|
|
import {
|
|
existsSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
readdirSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import process from "node:process";
|
|
|
|
const root = resolve(import.meta.dirname, "..");
|
|
const stageRoot = join(root, ".publish");
|
|
const bun = process.env.WRNEXUS_BUN_BINARY || "bun";
|
|
const npmCli = join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
if (!existsSync(npmCli)) throw new Error(`Unable to locate the npm CLI at ${npmCli}.`);
|
|
const integrityPath = join(stageRoot, "PACKAGE-INTEGRITY.json");
|
|
if (!existsSync(integrityPath)) {
|
|
throw new Error("No staged packages found. Run the package staging command first.");
|
|
}
|
|
const integrity = JSON.parse(readFileSync(integrityPath, "utf8"));
|
|
const expectedPackageNames = new Set(
|
|
(Array.isArray(integrity.packages) ? integrity.packages : []).map((entry) => entry.name),
|
|
);
|
|
|
|
const packages = readdirSync(stageRoot, { withFileTypes: true })
|
|
.filter((entry) => entry.isDirectory() && existsSync(join(stageRoot, entry.name, "package.json")))
|
|
.map((entry) => ({
|
|
directory: entry.name,
|
|
manifest: JSON.parse(readFileSync(join(stageRoot, entry.name, "package.json"), "utf8")),
|
|
}))
|
|
.sort((left, right) => left.manifest.name.localeCompare(right.manifest.name));
|
|
|
|
const stagedPackageNames = new Set(packages.map((pkg) => pkg.manifest.name));
|
|
const missingPackages = [...expectedPackageNames].filter((name) => !stagedPackageNames.has(name));
|
|
const unexpectedPackages = [...stagedPackageNames].filter(
|
|
(name) => !expectedPackageNames.has(name),
|
|
);
|
|
if (
|
|
expectedPackageNames.size === 0 ||
|
|
packages.length !== expectedPackageNames.size ||
|
|
missingPackages.length > 0 ||
|
|
unexpectedPackages.length > 0
|
|
) {
|
|
throw new Error(
|
|
`Staged package set does not match PACKAGE-INTEGRITY.json (expected ${expectedPackageNames.size}, received ${packages.length}, missing: ${missingPackages.join(", ") || "none"}, unexpected: ${unexpectedPackages.join(", ") || "none"}).`,
|
|
);
|
|
}
|
|
|
|
const consumer = mkdtempSync(join(tmpdir(), "wrnexus-staged-consumer-"));
|
|
try {
|
|
const tarballRoot = join(consumer, "tarballs");
|
|
mkdirSync(tarballRoot, { recursive: true });
|
|
const dependencies = {};
|
|
for (const pkg of packages) {
|
|
const packed = spawnSync(
|
|
process.execPath,
|
|
[npmCli, "pack", join(stageRoot, pkg.directory), "--pack-destination", tarballRoot, "--json"],
|
|
{ cwd: consumer, encoding: "utf8" },
|
|
);
|
|
if (packed.status !== 0) {
|
|
throw new Error(
|
|
`Unable to pack ${pkg.manifest.name}:\n${packed.error?.message || packed.stderr || packed.stdout || `exit ${packed.status}`}`,
|
|
);
|
|
}
|
|
const result = JSON.parse(packed.stdout);
|
|
const filename = result[0]?.filename;
|
|
if (typeof filename !== "string") {
|
|
throw new Error(`npm pack returned no tarball for ${pkg.manifest.name}.`);
|
|
}
|
|
dependencies[pkg.manifest.name] = `file:${join(tarballRoot, filename).replace(/\\/g, "/")}`;
|
|
}
|
|
writeFileSync(
|
|
join(consumer, "package.json"),
|
|
JSON.stringify(
|
|
{ name: "wrnexus-staged-consumer", private: true, type: "module", dependencies },
|
|
null,
|
|
2,
|
|
) + "\n",
|
|
);
|
|
const install = spawnSync(
|
|
process.execPath,
|
|
[npmCli, "install", "--ignore-scripts", "--no-audit", "--no-fund"],
|
|
{
|
|
cwd: consumer,
|
|
encoding: "utf8",
|
|
env: { ...process.env, NO_COLOR: "1" },
|
|
},
|
|
);
|
|
if (install.status !== 0) {
|
|
throw new Error(
|
|
`Unable to install staged package tarballs:\n${install.stderr || install.stdout}`,
|
|
);
|
|
}
|
|
|
|
const importable = packages.filter((pkg) => pkg.manifest.name !== "@wrnexus/cli");
|
|
writeFileSync(
|
|
join(consumer, "probe.mjs"),
|
|
`${importable
|
|
.map(
|
|
(pkg) =>
|
|
`if (!await import(${JSON.stringify(pkg.manifest.name)})) throw new Error(${JSON.stringify(`Unable to import ${pkg.manifest.name}`)});`,
|
|
)
|
|
.join(
|
|
"\n",
|
|
)}\nconsole.log(${JSON.stringify(`Imported ${importable.length} staged package roots.`)});\n`,
|
|
);
|
|
const probe = spawnSync(bun, ["probe.mjs"], {
|
|
cwd: consumer,
|
|
encoding: "utf8",
|
|
env: { ...process.env, NO_COLOR: "1" },
|
|
});
|
|
if (probe.status !== 0)
|
|
throw new Error(`Staged package import probe failed:\n${probe.stderr || probe.stdout}`);
|
|
if (probe.stdout) process.stdout.write(probe.stdout);
|
|
|
|
const browserPackages = ["@wrnexus/csr", "@wrnexus/reactive"].filter((name) =>
|
|
existsSync(join(consumer, "node_modules", ...name.split("/"))),
|
|
);
|
|
if (browserPackages.length > 0) {
|
|
writeFileSync(
|
|
join(consumer, "browser-probe.js"),
|
|
browserPackages.map((name) => `import ${JSON.stringify(name)};`).join("\n") + "\n",
|
|
);
|
|
const browser = spawnSync(
|
|
bun,
|
|
["build", "browser-probe.js", "--target=browser", "--outfile=browser-probe.bundle.js"],
|
|
{ cwd: consumer, encoding: "utf8", env: { ...process.env, NO_COLOR: "1" } },
|
|
);
|
|
if (browser.status !== 0 || !existsSync(join(consumer, "browser-probe.bundle.js"))) {
|
|
throw new Error(`Staged browser package build failed:\n${browser.stderr || browser.stdout}`);
|
|
}
|
|
}
|
|
|
|
const cliPath = join(consumer, "node_modules", "@wrnexus", "cli", "dist", "index.js");
|
|
if (existsSync(cliPath)) {
|
|
const cli = spawnSync(bun, [cliPath, "--help"], {
|
|
cwd: consumer,
|
|
encoding: "utf8",
|
|
env: { ...process.env, NO_COLOR: "1" },
|
|
});
|
|
if (cli.status !== 0 || !/wrnexus/i.test(`${cli.stdout}\n${cli.stderr}`)) {
|
|
throw new Error(`Staged CLI smoke test failed:\n${cli.stderr || cli.stdout}`);
|
|
}
|
|
}
|
|
console.log(
|
|
"Staged package tarballs, browser runtime bundle, and CLI passed their isolated consumer smoke tests.",
|
|
);
|
|
} finally {
|
|
rmSync(consumer, { recursive: true, force: true });
|
|
}
|