@bold-ai/create-product
Version:
CLI tool to create new products with Company Auth pre-configured
336 lines (331 loc) • 12.8 kB
JavaScript
import {
createProduct
} from "./chunk-7BZTDGOC.mjs";
// src/index.ts
import { Command } from "commander";
import inquirer from "inquirer";
import chalk2 from "chalk";
import ora2 from "ora";
import { execSync as execSync2 } from "child_process";
// src/register-product.ts
async function registerProduct(options) {
const { name, slug, description, authServiceUrl, adminToken } = options;
const response = await fetch(`${authServiceUrl}/api/admin/products`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Admin-Key": adminToken
},
body: JSON.stringify({
name,
slug,
description,
status: "development"
})
});
if (!response.ok) {
const error = await response.json().catch(() => ({ error: "Unknown error" }));
throw new Error(error.error || `Failed to register product: ${response.status}`);
}
const data = await response.json();
return {
productId: data.product.id,
apiKey: data.product.api_key
};
}
// src/download-packages.ts
import fs from "fs-extra";
import path from "path";
import { execSync } from "child_process";
import ora from "ora";
import chalk from "chalk";
var DEFAULT_PACKAGES = ["agents", "auth-sdk", "logger", "subscriptions"];
var GITHUB_REPO = "Bold-AI-Inc/bold-os-re";
var GITHUB_BRANCH = "main";
async function downloadAndBuildPackages(options) {
const { workspaceRoot, githubToken, packages = DEFAULT_PACKAGES } = options;
const packagesDir = path.join(workspaceRoot, "packages");
await fs.mkdir(packagesDir, { recursive: true });
console.log(chalk.cyan("\n\u{1F4E6} Downloading packages from GitHub...\n"));
for (const pkg of packages) {
const spinner2 = ora(`Downloading @bold/${pkg}...`).start();
try {
await downloadPackage(pkg, packagesDir, githubToken);
spinner2.succeed(`Downloaded @bold/${pkg}`);
} catch (error) {
spinner2.fail(`Failed to download @bold/${pkg}`);
throw new Error(`Failed to download ${pkg}: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
console.log(chalk.green("\n\u2705 All packages downloaded!\n"));
console.log(chalk.cyan("\u{1F4E6} Installing workspace dependencies...\n"));
const spinner = ora("Running pnpm install...").start();
try {
execSync("pnpm install", {
cwd: workspaceRoot,
stdio: "pipe",
encoding: "utf-8"
});
spinner.succeed("Workspace dependencies installed!");
} catch (error) {
spinner.fail("Failed to install workspace dependencies");
const errorMsg = error.stderr?.toString() || error.stdout?.toString() || error.message;
console.log(chalk.yellow(`
\u26A0\uFE0F You can try running 'pnpm install' manually
`));
console.log(chalk.dim(`Error: ${errorMsg.slice(0, 200)}`));
}
console.log(chalk.green("\n\u2705 Workspace setup complete!\n"));
}
async function downloadPackage(packageName, packagesDir, githubToken) {
const packagePath = path.join(packagesDir, packageName);
await fs.mkdir(packagePath, { recursive: true });
const apiUrl = `https://api.github.com/repos/${GITHUB_REPO}/contents/packages/${packageName}?ref=${GITHUB_BRANCH}`;
const response = await fetch(apiUrl, {
headers: {
"Authorization": `token ${githubToken}`,
"Accept": "application/vnd.github.v3+json",
"User-Agent": "bold-create-product-cli"
}
});
if (!response.ok) {
if (response.status === 401) {
throw new Error("Invalid GitHub token. Make sure you have access to the repository.");
}
if (response.status === 404) {
throw new Error(`Package not found. Make sure ${packageName} exists in the repository.`);
}
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
const contents = await response.json();
if (!Array.isArray(contents)) {
throw new Error(`Expected directory contents but got: ${typeof contents}`);
}
await downloadContents(contents, packagePath, githubToken);
}
async function downloadContents(contents, targetPath, githubToken) {
for (const item of contents) {
const itemPath = path.join(targetPath, item.name);
if (item.type === "file") {
const fileResponse = await fetch(item.download_url, {
headers: {
"Authorization": `token ${githubToken}`,
"User-Agent": "bold-create-product-cli"
}
});
if (!fileResponse.ok) {
throw new Error(`Failed to download ${item.name}`);
}
const fileContent = await fileResponse.text();
await fs.writeFile(itemPath, fileContent, "utf-8");
} else if (item.type === "dir") {
await fs.mkdir(itemPath, { recursive: true });
const dirResponse = await fetch(item.url, {
headers: {
"Authorization": `token ${githubToken}`,
"Accept": "application/vnd.github.v3+json",
"User-Agent": "bold-create-product-cli"
}
});
if (!dirResponse.ok) {
throw new Error(`Failed to fetch directory ${item.name}`);
}
const dirContents = await dirResponse.json();
await downloadContents(dirContents, itemPath, githubToken);
}
}
}
// src/index.ts
var program = new Command();
function checkPnpm() {
try {
execSync2("pnpm --version", { stdio: "pipe" });
return true;
} catch {
return false;
}
}
program.name("create-bold-product").description("Create a new product with Bold Auth pre-configured").version("0.2.1");
program.argument("[project-name]", "name of the project").option("-t, --template <type>", "template to use", "default").option("--skip-install", "skip installing dependencies").option("--skip-register", "skip registering product with auth service").action(async (projectName, options) => {
console.log(chalk2.bold.blue("\n\u{1F680} Bold Product Creator\n"));
if (!checkPnpm()) {
console.log(chalk2.red("\u274C pnpm is required but not installed!\n"));
console.log(chalk2.yellow("This CLI creates a pnpm workspace with multiple packages."));
console.log(chalk2.yellow("Please install pnpm first:\n"));
console.log(chalk2.cyan(" npm install -g pnpm"));
console.log(chalk2.dim(" or"));
console.log(chalk2.cyan(" curl -fsSL https://get.pnpm.io/install.sh | sh -\n"));
console.log(chalk2.dim("Learn more: https://pnpm.io/installation\n"));
process.exit(1);
}
let answers = {};
if (!projectName) {
const nameAnswer = await inquirer.prompt([
{
type: "input",
name: "projectName",
message: "What is your project name?",
default: "my-product",
validate: (input) => {
if (!/^[a-z0-9-]+$/.test(input)) {
return "Project name must be lowercase with hyphens only";
}
return true;
}
}
]);
projectName = nameAnswer.projectName;
}
answers = await inquirer.prompt([
{
type: "input",
name: "displayName",
message: "Display name for your product:",
default: projectName?.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ")
},
{
type: "input",
name: "description",
message: "Short description:",
default: `A product built with Company Auth`
},
{
type: "input",
name: "authServiceUrl",
message: "Company Auth Service URL:",
default: "http://localhost:3000"
},
{
type: "input",
name: "supabaseUrl",
message: "Supabase URL (leave empty to set later):",
default: ""
},
{
type: "input",
name: "supabaseAnonKey",
message: "Supabase Anon Key (leave empty to set later):",
default: ""
},
{
type: "confirm",
name: "installPackages",
message: "Download and install Bold packages from GitHub (agents, auth-sdk, logger)?",
default: true
},
{
type: "password",
name: "githubToken",
message: "GitHub Personal Access Token (for template and packages):",
validate: (input) => {
if (!input || input.length === 0) {
return "GitHub token is required to download the template from the repository";
}
return true;
}
},
{
type: "confirm",
name: "registerProduct",
message: "Register product with Auth Service now?",
default: !options.skipRegister,
when: () => !options.skipRegister
}
]);
const spinner = ora2("Creating product...").start();
try {
const result = await createProduct({
projectName,
displayName: answers.displayName,
description: answers.description,
authServiceUrl: answers.authServiceUrl,
supabaseUrl: answers.supabaseUrl,
supabaseAnonKey: answers.supabaseAnonKey,
skipInstall: options.skipInstall,
githubToken: answers.githubToken
});
spinner.succeed("Product created successfully!");
if (answers.installPackages && answers.githubToken) {
console.log("");
try {
await downloadAndBuildPackages({
workspaceRoot: result.workspaceRoot,
githubToken: answers.githubToken
});
} catch (error) {
console.log(chalk2.red("\n\u274C Failed to download packages:"));
console.log(chalk2.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
console.log(chalk2.yellow("\n\u{1F4A1} You can download packages manually from the repository"));
console.log(chalk2.dim(" Or run the CLI again with a valid GitHub token\n"));
}
} else if (answers.installPackages && !answers.githubToken) {
console.log(chalk2.yellow("\n\u26A0\uFE0F Skipped package installation (no token provided)\n"));
}
if (answers.registerProduct) {
const registrationAnswers = await inquirer.prompt([
{
type: "input",
name: "adminToken",
message: "Auth Service admin API key (from ADMIN_API_KEY env):"
}
]);
spinner.start("Registering product with Auth Service...");
try {
const registration = await registerProduct({
name: answers.displayName,
slug: projectName,
description: answers.description,
authServiceUrl: answers.authServiceUrl,
adminToken: registrationAnswers.adminToken
});
spinner.succeed("Product registered!");
spinner.start("Updating .env.local with credentials...");
const { updateEnvWithCredentials } = await import("./create-product-AQCGMPYG.mjs");
await updateEnvWithCredentials(
result.appDir,
registration.productId,
registration.apiKey,
registrationAnswers.adminToken
// Save admin token for server-side operations
);
spinner.succeed(".env.local updated with real credentials!");
console.log(chalk2.green("\n\u2705 Product ID: ") + chalk2.bold(registration.productId));
console.log(chalk2.green("\u2705 API Key: ") + chalk2.bold(registration.apiKey));
console.log(chalk2.green("\u2705 Credentials saved to .env.local\n"));
} catch (error) {
spinner.warn("Product registration failed. You can register manually later.");
console.log(chalk2.red(`
Error: ${error instanceof Error ? error.message : "Unknown error"}
`));
console.log(chalk2.yellow("\n\u26A0\uFE0F Your .env.local has placeholder values. Update them after manual registration.\n"));
}
} else {
console.log(chalk2.yellow("\n\u26A0\uFE0F Product not registered. Your .env.local has placeholder values.\n"));
console.log(chalk2.dim("To register later, visit the admin dashboard or use the API.\n"));
}
console.log(chalk2.bold.green("\n\u2728 All done!\n"));
console.log(chalk2.bold("Your pnpm workspace is ready! \u{1F389}\n"));
console.log("Next steps:");
console.log(chalk2.cyan(` cd ${projectName}`));
if (!answers.installPackages) {
console.log(chalk2.cyan(" pnpm install # Install workspace dependencies"));
}
if (!answers.registerProduct) {
console.log(chalk2.yellow(" # Update AGENCY_AUTH_PRODUCT_ID and AGENCY_AUTH_API_KEY in apps/${projectName}/.env.local"));
}
if (!answers.supabaseUrl || !answers.supabaseAnonKey) {
console.log(chalk2.yellow(" # Update Supabase credentials in apps/${projectName}/.env.local"));
}
console.log(chalk2.cyan(" pnpm dev # Start your app"));
console.log("");
console.log(chalk2.dim("Your app is in apps/" + projectName + "/"));
console.log(chalk2.dim("Packages are in packages/"));
console.log("");
} catch (error) {
spinner.fail("Failed to create product");
console.error(chalk2.red("\nError:"), error instanceof Error ? error.message : error);
process.exit(1);
}
});
program.parse();