import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { spawn } from "node:child_process"; import { fileURLToPath } from "node:url"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const packagesRoot = path.join(repoRoot, "packages"); const tempPrefix = path.join(os.tmpdir(), "cadence-ui-package-consumer-"); const keepArtifacts = process.env.CADENCE_KEEP_PACKAGE_SMOKE === "1"; const skipBuild = process.env.CADENCE_SKIP_PACKAGE_BUILD === "1"; const pnpmCommand = process.platform === "win32" ? "pnpm.cmd" : "pnpm"; function toPosixPath(value) { return value.split(path.sep).join(path.posix.sep); } async function readJson(filePath) { return JSON.parse(await fs.readFile(filePath, "utf8")); } function formatCommand(command, args) { return [command, ...args].join(" "); } async function run(command, args, options = {}) { await new Promise((resolve, reject) => { const child = spawn(command, args, { cwd: options.cwd ?? repoRoot, env: { ...process.env, ...(options.env ?? {}) }, stdio: "inherit" }); child.once("error", reject); child.once("exit", (code, signal) => { if (code === 0) { resolve(); return; } reject( new Error( `${formatCommand(command, args)} failed with code ${code ?? "null"} and signal ${ signal ?? "null" }.` ) ); }); }); } async function packPackage(packageDir, outputDir) { const before = new Set(await fs.readdir(outputDir)); await run( pnpmCommand, ["pack", "--pack-destination", outputDir], { cwd: packageDir, env: { CI: "1" } } ); const after = await fs.readdir(outputDir); const created = after.filter((entry) => !before.has(entry) && entry.endsWith(".tgz")); if (created.length !== 1) { throw new Error( `Expected exactly one tarball from ${packageDir}, received ${created.length}.` ); } return path.join(outputDir, created[0]); } function toFileDependency(projectDir, absolutePath) { let relativePath = toPosixPath(path.relative(projectDir, absolutePath)); if (!relativePath.startsWith(".")) { relativePath = `./${relativePath}`; } return `file:${relativePath}`; } async function writeConsumerFixture({ projectDir, tokensTarball, uiTarball, rootPackage, uiPackage }) { const packageJson = { name: "cadence-ui-package-consumer-smoke", private: true, type: "module", dependencies: { "@ai-ui/tokens": toFileDependency(projectDir, tokensTarball), "@ai-ui/ui": toFileDependency(projectDir, uiTarball), react: uiPackage.devDependencies.react, "react-dom": uiPackage.devDependencies["react-dom"] }, devDependencies: { "@tailwindcss/vite": rootPackage.devDependencies["@tailwindcss/vite"], "@types/react": rootPackage.devDependencies["@types/react"], "@types/react-dom": rootPackage.devDependencies["@types/react-dom"], tailwindcss: rootPackage.devDependencies.tailwindcss, typescript: rootPackage.devDependencies.typescript, vite: rootPackage.devDependencies.vite }, pnpm: { overrides: { "@ai-ui/tokens": toFileDependency(projectDir, tokensTarball) } } }; const tsconfig = { compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "Bundler", jsx: "react-jsx", strict: true, esModuleInterop: true, skipLibCheck: true, noEmit: true, types: ["react", "react-dom"] }, include: ["src", "vite.config.ts"] }; const viteConfig = `import { defineConfig } from "vite"; import tailwindcss from "@tailwindcss/vite"; export default defineConfig({ plugins: [tailwindcss()] }); `; const indexHtml = ` Cadence UI Package Smoke
`; const stylesSource = `@import "tailwindcss"; @import "@ai-ui/ui/styles.css"; @source "../node_modules/@ai-ui/ui/src"; `; const mainSource = `import { createRoot } from "react-dom/client"; import { Button, Dialog, DialogContent, DialogDescription, DialogTitle, DialogTrigger, Input } from "@ai-ui/ui"; import { setTheme } from "@ai-ui/tokens"; import "./styles.css"; setTheme("light"); function App() { return (

Cadence UI package smoke

Package consumer Verifies published package exports typecheck and build in a consumer app.
); } const root = document.getElementById("root"); if (!root) { throw new Error("Missing root element."); } createRoot(root).render(); `; await fs.mkdir(path.join(projectDir, "src"), { recursive: true }); await fs.writeFile(path.join(projectDir, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`); await fs.writeFile(path.join(projectDir, "tsconfig.json"), `${JSON.stringify(tsconfig, null, 2)}\n`); await fs.writeFile(path.join(projectDir, "vite.config.ts"), viteConfig); await fs.writeFile(path.join(projectDir, "index.html"), indexHtml); await fs.writeFile(path.join(projectDir, "src", "global.d.ts"), 'declare module "*.css";\n'); await fs.writeFile(path.join(projectDir, "src", "styles.css"), stylesSource); await fs.writeFile(path.join(projectDir, "src", "main.tsx"), mainSource); } async function main() { const [rootPackage, uiPackage, tokensPackage] = await Promise.all([ readJson(path.join(repoRoot, "package.json")), readJson(path.join(packagesRoot, "ui", "package.json")), readJson(path.join(packagesRoot, "tokens", "package.json")) ]); if (uiPackage.version !== tokensPackage.version) { throw new Error( `Expected @ai-ui/ui and @ai-ui/tokens to share a version. Received ${uiPackage.version} and ${tokensPackage.version}.` ); } const projectDir = await fs.mkdtemp(tempPrefix); const packDir = path.join(projectDir, "packed"); let succeeded = false; const cleanup = async () => { if (!succeeded || keepArtifacts) { console.log(`Keeping package smoke fixture at ${projectDir}`); return; } await fs.rm(projectDir, { force: true, recursive: true }); }; try { if (!skipBuild) { console.log("Building workspace packages for package smoke"); await run(pnpmCommand, ["build"], { cwd: repoRoot, env: { CI: "1" } }); } await fs.mkdir(packDir, { recursive: true }); console.log("Packing @ai-ui/tokens"); const tokensTarball = await packPackage(path.join(packagesRoot, "tokens"), packDir); console.log("Packing @ai-ui/ui"); const uiTarball = await packPackage(path.join(packagesRoot, "ui"), packDir); console.log(`Creating package consumer fixture in ${projectDir}`); await writeConsumerFixture({ projectDir, tokensTarball, uiTarball, rootPackage, uiPackage }); console.log("Installing package consumer dependencies"); await run(pnpmCommand, ["install", "--ignore-workspace"], { cwd: projectDir, env: { CI: "1" } }); console.log("Verifying CommonJS package entrypoints"); await run(process.execPath, ["-e", 'const ui=require("@ai-ui/ui"); const tokens=require("@ai-ui/tokens"); if(!ui.Button||!tokens.setTheme){throw new Error("Missing CommonJS export.");}'], { cwd: projectDir }); console.log("Verifying ESM package entrypoints"); await run(process.execPath, ["--input-type=module", "-e", 'const ui=await import("@ai-ui/ui"); const tokens=await import("@ai-ui/tokens"); if(!ui.Button||!tokens.setTheme){throw new Error("Missing ESM export.");}'], { cwd: projectDir }); console.log("Typechecking the package consumer fixture"); await run(pnpmCommand, ["exec", "tsc", "-p", "tsconfig.json", "--noEmit"], { cwd: projectDir }); console.log("Building the package consumer fixture"); await run(pnpmCommand, ["exec", "vite", "build"], { cwd: projectDir, env: { CI: "1" } }); succeeded = true; console.log("Package consumer smoke test passed."); } catch (error) { console.error(`Package consumer smoke test failed. Fixture preserved at ${projectDir}`); throw error; } finally { await cleanup(); } } await main();