UNPKG

@moontra/moonui-cli

Version:

CLI tool for MoonUI component library

1,420 lines (1,402 loc) 151 kB
#!/usr/bin/env node "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // package.json var require_package = __commonJS({ "package.json"(exports, module2) { module2.exports = { name: "@moontra/moonui-cli", version: "2.6.8", description: "CLI tool for MoonUI component library", main: "dist/index.js", types: "dist/index.d.ts", bin: { moonui: "./dist/index.js" }, files: [ "dist", "src/postcss", "src/vite", "src/theme-presets.ts", "src/utils/theme-generator.ts" ], exports: { ".": { types: "./dist/index.d.ts", import: "./dist/index.js", require: "./dist/index.cjs" }, "./postcss/moonui-theme-plugin": { types: "./src/postcss/moonui-theme-plugin.d.ts", require: "./src/postcss/moonui-theme-plugin.js" }, "./vite/moonui-theme-plugin": { types: "./dist/vite/moonui-theme-plugin.d.ts", import: "./dist/vite/moonui-theme-plugin.js" } }, scripts: { build: "tsup src/index.ts --format cjs,esm --dts", dev: "tsup src/index.ts --format cjs,esm --dts --watch --sourcemap", clean: "rm -rf dist", lint: 'eslint "src/**/*.ts*"', test: "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", prepublishOnly: "npm run clean && npm run build", pub: "npm version patch && npm run build && npm publish --access=public", "pub:minor": "npm version minor && npm run build && npm publish --access=public", "pub:major": "npm version major && npm run build && npm publish --access=public" }, keywords: [ "ui", "components", "cli", "moonui" ], author: "MoonUI", license: "MIT", dependencies: { "@radix-ui/react-primitive": "^2.1.3", "@types/jsonwebtoken": "^9.0.10", "@types/node-fetch": "^2.6.12", "@types/react-syntax-highlighter": "^15.5.13", chalk: "^4.1.2", "class-variance-authority": "^0.7.1", clsx: "^2.1.1", commander: "^10.0.1", figlet: "^1.6.0", "fs-extra": "^11.1.1", jsonwebtoken: "^9.0.2", "node-fetch": "^3.3.2", open: "^8.4.2", ora: "^5.4.1", prompts: "^2.4.2", "react-syntax-highlighter": "^15.6.1", "tailwind-merge": "^3.3.1", "ts-morph": "^18.0.0" }, devDependencies: { "@next/bundle-analyzer": "^15.4.6", "@sentry/nextjs": "^10.3.0", "@svgr/webpack": "^8.1.0", "@types/figlet": "^1.7.0", "@types/fs-extra": "^11.0.4", "@types/node": "^18.16.0", "@types/ora": "^3.1.0", "@types/prompts": "^2.4.9", autoprefixer: "^10.4.21", eslint: "^8.39.0", jest: "^29.5.0", postcss: "^8.5.6", tailwindcss: "^4.1.11", tsup: "^6.7.0", typescript: "^5.0.4" } }; } }); // src/services/device.service.ts var import_os, import_crypto, import_os2, DeviceService; var init_device_service = __esm({ "src/services/device.service.ts"() { "use strict"; import_os = __toESM(require("os")); import_crypto = __toESM(require("crypto")); import_os2 = require("os"); DeviceService = class { /** * Generate a unique device fingerprint based on system attributes */ static getDeviceFingerprint() { const deviceInfo = this.getDeviceInfo(); const fingerprintData = [ deviceInfo.hostname, deviceInfo.username, deviceInfo.platform, deviceInfo.arch, deviceInfo.cpuModel, deviceInfo.cpuCount.toString(), deviceInfo.macAddress || "no-mac" ].join("|"); return import_crypto.default.createHash("sha256").update(fingerprintData).digest("hex"); } /** * Get detailed device information */ static getDeviceInfo() { const cpus = import_os.default.cpus(); const macAddress = this.getMacAddress(); const packageJson = require_package(); const cliVersion = packageJson.version || "unknown"; return { hostname: import_os.default.hostname(), username: import_os.default.userInfo().username, platform: import_os.default.platform(), arch: import_os.default.arch(), cpuModel: cpus[0]?.model || "unknown", cpuCount: cpus.length, totalMemory: import_os.default.totalmem(), nodeVersion: process.version, cliVersion, macAddress }; } /** * Get the primary MAC address of the device */ static getMacAddress() { const interfaces = (0, import_os2.networkInterfaces)(); for (const name of Object.keys(interfaces)) { const iface = interfaces[name]; if (!iface) continue; for (const details of iface) { if (!details.internal && details.mac && details.mac !== "00:00:00:00:00:00") { return details.mac; } } } for (const name of Object.keys(interfaces)) { const iface = interfaces[name]; if (!iface) continue; for (const details of iface) { if (details.mac && details.mac !== "00:00:00:00:00:00") { return details.mac; } } } return void 0; } /** * Validate device against API */ static async validateDevice(apiKey, deviceId) { try { const API_BASE3 = "https://moonui.dev"; const response = await fetch(`${API_BASE3}/api/device/validate`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}`, "X-Device-ID": deviceId }, body: JSON.stringify({ deviceId, deviceInfo: this.getDeviceInfo() }) }); return response.ok; } catch (error) { console.error("Device validation error:", error); return false; } } /** * Register a new device */ static async registerDevice(apiKey) { try { const deviceId = this.getDeviceFingerprint(); const deviceInfo = this.getDeviceInfo(); const API_BASE3 = "https://moonui.dev"; const response = await fetch(`${API_BASE3}/api/device/register`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` }, body: JSON.stringify({ deviceId, deviceInfo }) }); if (response.ok) { return { success: true, deviceId }; } else { const error = await response.json(); return { success: false, error: error.message || "Failed to register device" }; } } catch (error) { return { success: false, error: error.message || "Device registration failed" }; } } /** * List all registered devices for the user */ static async listDevices(apiKey) { try { const API_BASE3 = "https://moonui.dev"; const response = await fetch(`${API_BASE3}/api/device/list`, { headers: { "Authorization": `Bearer ${apiKey}` } }); if (response.ok) { const data = await response.json(); return data.devices || []; } return []; } catch (error) { console.error("Failed to list devices:", error); return []; } } /** * Revoke a device */ static async revokeDevice(apiKey, deviceId) { try { const API_BASE3 = "https://moonui.dev"; const response = await fetch(`${API_BASE3}/api/device/revoke`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` }, body: JSON.stringify({ deviceId }) }); return response.ok; } catch (error) { console.error("Failed to revoke device:", error); return false; } } /** * Get current device status */ static async getDeviceStatus(apiKey) { try { const deviceId = this.getDeviceFingerprint(); const API_BASE3 = "https://moonui.dev"; const response = await fetch(`${API_BASE3}/api/device/status`, { headers: { "Authorization": `Bearer ${apiKey}`, "X-Device-ID": deviceId } }); if (response.ok) { return await response.json(); } return null; } catch (error) { console.error("Failed to get device status:", error); return null; } } }; } }); // src/services/auth-service.ts var auth_service_exports = {}; __export(auth_service_exports, { AuthService: () => AuthService }); var import_fs_extra4, import_path4, import_os3, import_crypto2, import_chalk2, API_BASE, CACHE_DURATION, REFRESH_THRESHOLD, AuthService; var init_auth_service = __esm({ "src/services/auth-service.ts"() { "use strict"; import_fs_extra4 = __toESM(require("fs-extra")); import_path4 = __toESM(require("path")); import_os3 = __toESM(require("os")); import_crypto2 = __toESM(require("crypto")); import_chalk2 = __toESM(require("chalk")); init_device_service(); API_BASE = "https://moonui.dev"; CACHE_DURATION = 24 * 60 * 60 * 1e3; REFRESH_THRESHOLD = 60 * 60 * 1e3; AuthService = class { constructor() { const configDir = import_path4.default.join(import_os3.default.homedir(), ".moonui"); this.authPath = import_path4.default.join(configDir, "auth.encrypted"); this.encryptionKey = this.getEncryptionKey(); } getDeviceFingerprint() { return DeviceService.getDeviceFingerprint(); } getEncryptionKey() { return import_crypto2.default.createHash("sha256").update(this.getDeviceFingerprint()).digest(); } encrypt(data) { const iv = import_crypto2.default.randomBytes(16); const cipher = import_crypto2.default.createCipheriv("aes-256-cbc", this.encryptionKey, iv); let encrypted = cipher.update(data, "utf8", "hex"); encrypted += cipher.final("hex"); return iv.toString("hex") + ":" + encrypted; } decrypt(data) { const parts = data.split(":"); const iv = Buffer.from(parts[0], "hex"); const encrypted = parts[1]; const decipher = import_crypto2.default.createDecipheriv("aes-256-cbc", this.encryptionKey, iv); let decrypted = decipher.update(encrypted, "hex", "utf8"); decrypted += decipher.final("utf8"); return decrypted; } generateSignature(token) { const data = JSON.stringify({ accessToken: token.accessToken, userId: token.user.id, plan: token.user.plan, expiresAt: token.expiresAt }); return import_crypto2.default.createHmac("sha256", this.encryptionKey).update(data).digest("hex"); } verifySignature(token) { if (!token.signature) return false; const expectedSignature = this.generateSignature(token); return token.signature === expectedSignature; } async saveAuth(token) { try { token.signature = this.generateSignature(token); token.lastVerified = (/* @__PURE__ */ new Date()).toISOString(); const deviceFingerprint = DeviceService.getDeviceFingerprint(); token.deviceId = deviceFingerprint; const cache = { token, deviceId: deviceFingerprint, machineId: deviceFingerprint, encryptedAt: (/* @__PURE__ */ new Date()).toISOString() }; const encrypted = this.encrypt(JSON.stringify(cache)); const hmac = import_crypto2.default.createHmac("sha256", this.encryptionKey); const [iv, encryptedData] = encrypted.split(":"); hmac.update(encryptedData); const signature = hmac.digest("hex"); const finalData = `${iv}.${encryptedData}.${signature}`; const configDir = import_path4.default.dirname(this.authPath); await import_fs_extra4.default.ensureDir(configDir); await import_fs_extra4.default.writeFile(this.authPath, finalData, "utf8"); await import_fs_extra4.default.chmod(this.authPath, 384); } catch (error) { throw new Error(`Failed to save auth: ${error.message}`); } } async clearAuth() { try { if (await import_fs_extra4.default.pathExists(this.authPath)) { await import_fs_extra4.default.remove(this.authPath); } } catch (error) { throw new Error(`Failed to clear auth: ${error.message}`); } } async getAuth() { try { if (!await import_fs_extra4.default.pathExists(this.authPath)) { return null; } const fileContent = await import_fs_extra4.default.readFile(this.authPath, "utf8"); const parts = fileContent.split("."); if (parts.length !== 3) { return null; } const [iv, encryptedData, signature] = parts; const hmac = import_crypto2.default.createHmac("sha256", this.encryptionKey); hmac.update(encryptedData); const computedSignature = hmac.digest("hex"); if (computedSignature !== signature) { return null; } const encrypted = `${iv}:${encryptedData}`; const decrypted = this.decrypt(encrypted); const cache = JSON.parse(decrypted); const currentDeviceId = DeviceService.getDeviceFingerprint(); if (cache.deviceId && cache.deviceId !== currentDeviceId) { console.warn(import_chalk2.default.red("\u26A0\uFE0F This license is registered to a different device")); console.warn(import_chalk2.default.yellow(" MoonUI Pro licenses are device-specific")); console.warn(import_chalk2.default.yellow(" Please login again or contact support for multi-device access")); await this.clearAuth(); return null; } if (!cache.token.deviceId) { cache.token.deviceId = currentDeviceId; } if (!this.verifySignature(cache.token)) { console.warn(import_chalk2.default.red("Auth token signature verification failed")); await this.clearAuth(); return null; } const expiresAt = new Date(cache.token.expiresAt); const now = /* @__PURE__ */ new Date(); if (expiresAt < now) { if (cache.token.refreshToken) { try { const newToken = await this.refreshToken(cache.token.refreshToken); await this.saveAuth(newToken); return newToken; } catch (error) { return null; } } return null; } const lastVerified = new Date(cache.token.lastVerified); if (now.getTime() - lastVerified.getTime() > REFRESH_THRESHOLD) { this.backgroundRefresh(cache.token); } return cache.token; } catch (error) { await this.clearAuth(); return null; } } async backgroundRefresh(token) { try { const response = await fetch(`${API_BASE}/api/auth/verify`, { method: "POST", headers: { "Authorization": `Bearer ${token.accessToken}`, "Content-Type": "application/json" } }); if (response.ok) { const data = await response.json(); token.user = data.user; token.lastVerified = (/* @__PURE__ */ new Date()).toISOString(); token.signature = this.generateSignature(token); await this.saveAuth(token); } } catch { } } async refreshToken(refreshToken) { const response = await fetch(`${API_BASE}/api/auth/refresh`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ refresh_token: refreshToken, grant_type: "refresh_token" }) }); if (!response.ok) { throw new Error("Token refresh failed"); } const data = await response.json(); return { accessToken: data.access_token, refreshToken: data.refresh_token, expiresAt: data.expires_at, user: data.user, lastVerified: (/* @__PURE__ */ new Date()).toISOString() }; } async isAuthenticated(skipServerValidation = false) { const auth = await this.getAuth(); if (!auth) return false; if (skipServerValidation) { return true; } const isValid = await this.validateTokenWithServer(auth.accessToken); if (!isValid) { await this.clearAuth(); return false; } return true; } async requireAuth() { const auth = await this.getAuth(); if (!auth) { console.log(import_chalk2.default.yellow("\n\u{1F510} Authentication required")); console.log(import_chalk2.default.gray("Please login to continue:")); console.log(import_chalk2.default.cyan(" moonui login\n")); process.exit(1); } const isValid = await this.validateTokenWithServer(auth.accessToken); if (!isValid) { console.log(import_chalk2.default.red("\n\u274C Your session has been revoked")); console.log(import_chalk2.default.yellow("Please login again:")); console.log(import_chalk2.default.cyan(" moonui login\n")); await this.clearAuth(); process.exit(1); } return auth; } async validateTokenWithServer(token) { try { const deviceId = DeviceService.getDeviceFingerprint(); const response = await fetch(`${API_BASE}/api/device/validate`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}`, "X-Device-ID": deviceId }, body: JSON.stringify({ deviceId }) }); if (!response.ok) { try { const errorData = await response.json(); if (response.status === 401 && (errorData.error?.includes("revoked") || errorData.error?.includes("Device session revoked"))) { return false; } } catch { if (response.status === 401) { return false; } } } return response.ok; } catch (error) { console.log(import_chalk2.default.gray("\n\u26A0\uFE0F Could not validate session (offline mode)")); return true; } } async checkProAccess(component) { const auth = await this.getAuth(); if (!auth) { return false; } if (auth.user.hasLifetimeAccess === true) { return true; } if (auth.user.plan === "pro_lifetime" || auth.user.plan === "lifetime") { return true; } if (component && this.isCriticalComponent(component)) { try { const response = await fetch(`${API_BASE}/api/license/verify`, { method: "POST", headers: { "Authorization": `Bearer ${auth.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify({ component, plan: auth.user.plan }) }); if (!response.ok) { return false; } const data = await response.json(); if (data.user?.hasLifetimeAccess === true) { return true; } return data.hasAccess && auth.user.plan !== "free"; } catch { } } if (auth.user.hasProAccess === true) { return true; } return auth.user.plan !== "free"; } isCriticalComponent(component) { const criticalComponents = [ "data-table", "advanced-chart", "dashboard", "kanban", "calendar" ]; return criticalComponents.includes(component); } async getUserInfo() { const auth = await this.getAuth(); return auth?.user || null; } async makeAuthenticatedRequest(url, options = {}) { const auth = await this.requireAuth(); const deviceId = DeviceService.getDeviceFingerprint(); return fetch(url, { ...options, headers: { ...options.headers, "Authorization": `Bearer ${auth.accessToken}`, "X-Device-ID": deviceId, "X-Machine-ID": deviceId } }); } async validateDevice() { try { const auth = await this.getAuth(); if (!auth) { return { valid: false, error: "Not authenticated" }; } const deviceId = DeviceService.getDeviceFingerprint(); const deviceInfo = DeviceService.getDeviceInfo(); const response = await fetch(`${API_BASE}/api/device/validate`, { method: "POST", headers: { "Authorization": `Bearer ${auth.accessToken}`, "X-Device-ID": deviceId, "Content-Type": "application/json" }, body: JSON.stringify({ deviceInfo }) }); if (response.ok) { const data = await response.json(); return { valid: data.valid }; } else { const error = await response.json(); return { valid: false, error: error.error || "Device validation failed" }; } } catch (error) { return { valid: false, error: "Failed to validate device" }; } } async registerDevice() { try { const auth = await this.getAuth(); if (!auth) { return { success: false, error: "Not authenticated" }; } const deviceId = DeviceService.getDeviceFingerprint(); const deviceInfo = DeviceService.getDeviceInfo(); const response = await fetch(`${API_BASE}/api/device/register`, { method: "POST", headers: { "Authorization": `Bearer ${auth.accessToken}`, "X-Device-ID": deviceId, "Content-Type": "application/json" }, body: JSON.stringify({ deviceId, deviceInfo }) }); if (response.ok) { const data = await response.json(); auth.deviceId = deviceId; auth.deviceValidated = true; await this.saveAuth(auth); return { success: true }; } else { const error = await response.json(); if (error.error === "Device limit exceeded") { console.log(import_chalk2.default.red("\n\u274C Device limit exceeded")); console.log(import_chalk2.default.yellow(` You have ${error.currentDevices}/${error.maxDevices} devices registered`)); console.log(import_chalk2.default.blue(" Manage your devices at: https://moonui.dev/dashboard/devices")); } return { success: false, error: error.error }; } } catch (error) { return { success: false, error: "Failed to register device" }; } } }; } }); // src/index.ts var import_commander3 = require("commander"); var import_chalk11 = __toESM(require("chalk")); var import_figlet = __toESM(require("figlet")); // src/commands/init.ts var import_fs_extra = __toESM(require("fs-extra")); var import_path = __toESM(require("path")); var import_chalk = __toESM(require("chalk")); var import_ora = __toESM(require("ora")); var import_child_process = require("child_process"); async function initCommand(options = {}) { const spinner = (0, import_ora.default)("Initializing MoonUI in your project...").start(); try { const cwd = process.cwd(); const packageJsonPath = import_path.default.join(cwd, "package.json"); if (!import_fs_extra.default.existsSync(packageJsonPath)) { spinner.fail(import_chalk.default.red("No package.json found in the current directory.")); console.log(import_chalk.default.yellow("Please run this command in a JavaScript/TypeScript project root.")); return; } const configFileName = "moonui.config.js"; const configPath = import_path.default.join(cwd, configFileName); if (import_fs_extra.default.existsSync(configPath) && !options.force) { spinner.fail(import_chalk.default.red(`${configFileName} already exists.`)); console.log(import_chalk.default.yellow(`Use --force to overwrite the existing configuration.`)); return; } const configContent = `module.exports = { // MoonUI Theme Configuration theme: { // Option 1: Use a preset theme preset: 'default', // 'default' | 'corporate' | 'creative' | 'nature' | 'minimal' | 'ocean' // Option 2: Define custom theme (uncomment to use) // custom: { // colors: { // background: "0 0% 100%", // foreground: "222.2 84% 4.9%", // primary: "222.2 47.4% 11.2%", // "primary-foreground": "210 40% 98%", // secondary: "210 40% 96.1%", // "secondary-foreground": "222.2 47.4% 11.2%", // accent: "210 40% 96.1%", // "accent-foreground": "222.2 47.4% 11.2%", // destructive: "0 84.2% 60.2%", // "destructive-foreground": "210 40% 98%", // muted: "210 40% 96.1%", // "muted-foreground": "215.4 16.3% 46.9%", // border: "214.3 31.8% 91.4%", // input: "214.3 31.8% 91.4%", // ring: "222.2 84% 4.9%", // card: "0 0% 100%", // "card-foreground": "222.2 84% 4.9%", // popover: "0 0% 100%", // "popover-foreground": "222.2 84% 4.9%", // }, // darkMode: { // background: "222.2 84% 4.9%", // foreground: "210 40% 98%", // primary: "210 40% 98%", // "primary-foreground": "222.2 47.4% 11.2%", // // ... other dark mode colors // }, // radius: 0.5, // Border radius in rem // }, }, // Tailwind CSS configuration tailwind: { content: ['./src/**/*.{js,jsx,ts,tsx}'], darkMode: 'class', // or 'media' }, // Component default settings components: { // Configure default props and variants for components Button: { defaultVariant: 'default', defaultSize: 'md', }, Card: { defaultVariant: 'default', }, // Add more component defaults as needed }, // Path settings paths: { // Where to output the components components: './src/components/ui', // Where to output the utilities utils: './src/lib', // Where to output the generated theme CSS styles: './src/styles', }, // Build settings build: { // Automatically generate theme CSS on build generateThemeCSS: true, // CSS output file name themeCSSFile: 'moonui-theme.css', }, }`; import_fs_extra.default.writeFileSync(configPath, configContent); const componentsDir = import_path.default.join(cwd, "src", "components", "ui"); const libDir = import_path.default.join(cwd, "src", "lib"); import_fs_extra.default.ensureDirSync(componentsDir); import_fs_extra.default.ensureDirSync(libDir); const utilsPath = import_path.default.join(libDir, "utils.ts"); const utilsContent = `import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; /** * A utility function to merge Tailwind CSS classes conditionally */ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }`; import_fs_extra.default.writeFileSync(utilsPath, utilsContent); spinner.text = "Installing required dependencies..."; const dependencies = [ "@moontra/moonui@latest", // Her zaman en son versiyon "clsx", "tailwind-merge", "class-variance-authority" ]; const devDependencies = [ "tailwindcss", "postcss", "autoprefixer" ]; try { const hasYarnLock = import_fs_extra.default.existsSync(import_path.default.join(cwd, "yarn.lock")); const packageManager = hasYarnLock ? "yarn" : "npm"; if (packageManager === "yarn") { (0, import_child_process.execSync)(`yarn add ${dependencies.join(" ")}`, { stdio: "ignore" }); (0, import_child_process.execSync)(`yarn add -D ${devDependencies.join(" ")}`, { stdio: "ignore" }); } else { (0, import_child_process.execSync)(`npm install --save ${dependencies.join(" ")}`, { stdio: "ignore" }); (0, import_child_process.execSync)(`npm install --save-dev ${devDependencies.join(" ")}`, { stdio: "ignore" }); } } catch (error) { spinner.warn(import_chalk.default.yellow("Failed to automatically install dependencies.")); console.log(import_chalk.default.yellow("Please install the following dependencies manually:")); console.log(import_chalk.default.cyan(` Dependencies: - ${dependencies.join("\n- ")}`)); console.log(import_chalk.default.cyan(` Dev Dependencies: - ${devDependencies.join("\n- ")}`)); } spinner.succeed(import_chalk.default.green("MoonUI initialized successfully!")); console.log("\nNext steps:"); console.log(import_chalk.default.cyan("1. Add components: ") + "moonui add button card input"); console.log(import_chalk.default.cyan("2. Configure your theme: ") + "Edit moonui.config.js"); console.log(import_chalk.default.cyan("3. Check documentation: ") + "https://moonui.dev/docs"); } catch (error) { spinner.fail(import_chalk.default.red("Failed to initialize MoonUI.")); console.error(error); } } // src/commands/add.ts var import_fs_extra7 = __toESM(require("fs-extra")); var import_path7 = __toESM(require("path")); var import_chalk5 = __toESM(require("chalk")); var import_ora2 = __toESM(require("ora")); var import_prompts2 = __toESM(require("prompts")); var import_os4 = __toESM(require("os")); // src/utils/components.ts async function getComponentCategories() { return [ { name: "Form", description: "Components for user input and forms", components: [ { id: "button", name: "Button", description: "A button component with various styles, sizes, and states", dependencies: [] }, { id: "input", name: "Input", description: "A text input component with validation and state handling", dependencies: [] }, { id: "checkbox", name: "Checkbox", description: "A checkbox input component for boolean selections", dependencies: [] }, { id: "switch", name: "Switch", description: "A toggle switch component for boolean state", dependencies: [] }, { id: "select", name: "Select", description: "A dropdown select component for choosing from options", dependencies: [] }, { id: "radio-group", name: "RadioGroup", description: "A group of radio buttons for selecting one option", dependencies: ["radio"] }, { id: "textarea", name: "Textarea", description: "A multi-line text input area", dependencies: [] }, { id: "label", name: "Label", description: "A form label component", dependencies: [] } ] }, { name: "Layout", description: "Components for page layout and structure", components: [ { id: "card", name: "Card", description: "A container component with header, content, and footer sections", dependencies: [] }, { id: "dialog", name: "Dialog", description: "A modal dialog component for displaying content over the page", dependencies: [] }, { id: "accordion", name: "Accordion", description: "A collapsible content panel", dependencies: [] }, { id: "sheet", name: "Sheet", description: "A slide-out panel from any edge of the screen", dependencies: [] }, { id: "popover", name: "Popover", description: "A small overlay that appears on user interaction", dependencies: [] }, { id: "hover-card", name: "HoverCard", description: "A card that appears when hovering over a trigger element", dependencies: [] }, { id: "separator", name: "Separator", description: "A horizontal or vertical separator line", dependencies: [] }, { id: "aspect-ratio", name: "AspectRatio", description: "A component to maintain a specific aspect ratio", dependencies: [] } ] }, { name: "Navigation", description: "Components for navigation and menus", components: [ { id: "tabs", name: "Tabs", description: "A tabbed interface for switching between content sections", dependencies: [] }, { id: "breadcrumb", name: "Breadcrumb", description: "A breadcrumb navigation component", dependencies: [] }, { id: "dropdown-menu", name: "DropdownMenu", description: "A dropdown menu component for navigation or actions", dependencies: [] }, { id: "navigation-menu", name: "NavigationMenu", description: "A responsive navigation menu component", dependencies: [] }, { id: "menubar", name: "Menubar", description: "A horizontal menu bar component", dependencies: [] }, { id: "pagination", name: "Pagination", description: "A component for paginating through content", dependencies: [] } ] }, { name: "Data Display", description: "Components for displaying data", components: [ { id: "badge", name: "Badge", description: "A badge component for labels and counts", dependencies: [] }, { id: "table", name: "Table", description: "A table component for displaying data in rows and columns", dependencies: [] }, { id: "avatar", name: "Avatar", description: "An avatar component for user or entity representation", dependencies: [] }, { id: "progress", name: "Progress", description: "A progress indicator component", dependencies: [] }, { id: "skeleton", name: "Skeleton", description: "A placeholder loading state component", dependencies: [] }, { id: "alert", name: "Alert", description: "An alert component for important messages", dependencies: [] }, { id: "toast", name: "Toast", description: "A toast notification component", dependencies: [] }, { id: "tooltip", name: "Tooltip", description: "A tooltip component for displaying information on hover", dependencies: [] } ] }, { name: "Premium", description: "Premium components available with MoonUI Pro", components: [ { id: "data-table", name: "DataTable", description: "Advanced data table with sorting, filtering, and pagination", dependencies: ["@tanstack/react-table"] }, { id: "advanced-chart", name: "AdvancedChart", description: "Interactive charts with multiple types and customization options", dependencies: ["recharts"] }, { id: "file-upload", name: "FileUpload", description: "Advanced file upload component with drag-and-drop support", dependencies: [] }, { id: "rich-text-editor", name: "RichTextEditor", description: "Rich text editor with formatting toolbar and customization", dependencies: [] }, { id: "calendar", name: "Calendar", description: "Interactive calendar component with event management", dependencies: [] }, { id: "kanban", name: "Kanban", description: "Drag-and-drop kanban board for project management", dependencies: [] }, { id: "timeline", name: "Timeline", description: "Timeline component for displaying chronological events", dependencies: [] }, { id: "dashboard", name: "Dashboard", description: "Dashboard component with metrics and widgets", dependencies: [] } ] } ]; } // src/utils/config.ts var import_fs_extra2 = __toESM(require("fs-extra")); var import_path2 = __toESM(require("path")); async function getConfig(projectPath) { try { const configPath = import_path2.default.join(projectPath, "moonui.config.js"); if (!import_fs_extra2.default.existsSync(configPath)) { return null; } return { tailwind: { content: ["./src/**/*.{js,jsx,ts,tsx}"], darkMode: "class" }, theme: { extend: { colors: { primary: "hsl(var(--primary))", secondary: "hsl(var(--secondary))" } } }, components: { Button: { defaultVariant: "default", defaultSize: "md" } }, paths: { components: "./src/components/ui", utils: "./src/lib" } }; } catch (error) { console.error("Error reading MoonUI config:", error); return null; } } // src/utils/license.ts var PRO_COMPONENTS = [ { id: "data-table", name: "Data Table", category: "data", tier: "pro", description: "Advanced data table with sorting, filtering, pagination, and export", dependencies: ["@tanstack/react-table"], tags: ["table", "data", "sorting", "filtering", "pagination"] }, { id: "advanced-chart", name: "Advanced Chart", category: "visualization", tier: "pro", description: "Interactive charts with multiple types and customization options", dependencies: ["recharts"], tags: ["chart", "visualization", "analytics", "graph"] }, { id: "dashboard", name: "Dashboard", category: "layout", tier: "pro", description: "Complete dashboard layout with widgets and responsive design", dependencies: ["framer-motion"], tags: ["dashboard", "layout", "widgets", "analytics"] }, { id: "file-upload", name: "File Upload", category: "input", tier: "pro", description: "Advanced file upload with drag-and-drop, preview, and progress", dependencies: ["react-dropzone"], tags: ["upload", "file", "drag-drop", "preview"] }, { id: "rich-text-editor", name: "Rich Text Editor", category: "input", tier: "pro", description: "WYSIWYG rich text editor with formatting and media support", dependencies: ["@tiptap/react"], tags: ["editor", "text", "wysiwyg", "formatting"] }, { id: "calendar", name: "Calendar", category: "input", tier: "pro", description: "Interactive calendar with event management and date selection", dependencies: ["date-fns"], tags: ["calendar", "date", "events", "scheduling"] }, { id: "kanban", name: "Kanban Board", category: "layout", tier: "pro", description: "Drag-and-drop kanban board for project management", dependencies: ["@dnd-kit/core"], tags: ["kanban", "board", "drag-drop", "project"] }, { id: "timeline", name: "Timeline", category: "visualization", tier: "pro", description: "Interactive timeline component for displaying chronological data", dependencies: [], tags: ["timeline", "chronological", "events", "history"] } ]; function isProComponent(componentId) { return PRO_COMPONENTS.some((comp) => comp.id === componentId); } // src/utils/registry-client.ts var import_fs_extra5 = __toESM(require("fs-extra")); var import_path5 = __toESM(require("path")); var import_chalk3 = __toESM(require("chalk")); // src/utils/component-source-reader.ts var import_fs_extra3 = __toESM(require("fs-extra")); var import_path3 = __toESM(require("path")); function transformImportPaths(content, componentName) { let transformed = content.replace(/from ["']\.\.\/\.\.\/lib\/utils["']/g, 'from "@/lib/utils"').replace(/from ["']\.\.\/ui\/([^"']+)["']/g, 'from "@/components/ui/$1"').replace(/from ["']\.\/([^"']+)["']/g, (match, component) => { if (component.endsWith(".css") || component.endsWith(".tsx") || component.endsWith(".ts")) { return match; } return `from "@/components/ui/${component}"`; }); transformed = transformed.replace(/from ["'](@\/[^"']+)\.tsx["']/g, 'from "$1"'); return transformed; } async function readComponentFromPackage(componentName, isProComponent2 = false) { try { const packageName = isProComponent2 ? "@moontra/moonui-pro" : "@moontra/moonui"; let componentPath; let content = null; try { const cwd = process.cwd(); const localPackagePath = isProComponent2 ? import_path3.default.join(cwd, "packages", "moonui-pro") : import_path3.default.join(cwd, "packages", "moonui"); let packageRoot; if (import_fs_extra3.default.existsSync(import_path3.default.join(localPackagePath, "package.json"))) { packageRoot = localPackagePath; console.log(`\u2713 Using local development package: ${packageRoot}`); } else { const packagePath = require.resolve(packageName); const packageDir = import_path3.default.dirname(packagePath); packageRoot = packageDir; while (!import_fs_extra3.default.existsSync(import_path3.default.join(packageRoot, "package.json")) && packageRoot !== "/") { packageRoot = import_path3.default.dirname(packageRoot); } console.log(`\u2713 Using NPM package: ${packageRoot}`); } const srcPath = import_path3.default.join(packageRoot, "src", "components", "ui", `${componentName}.tsx`); const srcProPath = import_path3.default.join(packageRoot, "src", "components", componentName, "index.tsx"); if (!isProComponent2 && import_fs_extra3.default.existsSync(srcPath)) { componentPath = srcPath; content = await import_fs_extra3.default.readFile(srcPath, "utf8"); console.log(`\u2713 Read component from source: ${srcPath}`); } else if (isProComponent2 && import_fs_extra3.default.existsSync(srcProPath)) { componentPath = srcProPath; content = await import_fs_extra3.default.readFile(srcProPath, "utf8"); console.log(`\u2713 Read pro component from source: ${srcProPath}`); } else { const distPath = import_path3.default.join(packageRoot, "dist", "components", "ui", `${componentName}.mjs`); const distProPath = import_path3.default.join(packageRoot, "dist", "components", componentName, "index.mjs"); if (!isProComponent2 && import_fs_extra3.default.existsSync(distPath)) { console.log(`Warning: Reading from built file, source may be minified: ${distPath}`); return null; } } } catch (error) { console.log(`Failed to resolve package: ${packageName}`, error); return null; } if (!content) { console.log(`Component source not found in package: ${componentName}`); return null; } const transformedContent = transformImportPaths(content, componentName); const dependencies = []; const importRegex = /from ["']([^"']+)["']/g; let match; while ((match = importRegex.exec(transformedContent)) !== null) { const importPath = match[1]; if (importPath.startsWith("@/components/ui/")) { const componentName2 = importPath.replace("@/components/ui/", ""); dependencies.push(componentName2); } } const componentData = { id: componentName, name: componentName.charAt(0).toUpperCase() + componentName.slice(1), description: `${componentName} component from ${packageName}`, dependencies: [...new Set(dependencies)], // Remove duplicates files: [{ name: `${componentName}.tsx`, content: transformedContent }], category: isProComponent2 ? "pro" : "free" }; return componentData; } catch (error) { console.log(`Failed to read component from package: ${componentName}`, error); return null; } } // src/utils/registry-client.ts init_device_service(); var fetch2 = (url, options) => import("node-fetch").then(({ default: fetch4 }) => fetch4(url, options)); var RegistryClient = class { constructor() { this.cache = /* @__PURE__ */ new Map(); this.baseUrl = "https://moonui.dev/api/registry"; } /** * Fetch component from registry */ async fetchComponent(componentId, license) { const cacheKey = `${componentId}-${license?.user?.plan || "free"}`; if (this.cache.has(cacheKey)) { return this.cache.get(cacheKey); } try { const isProComponent2 = this.isProComponent(componentId); const isPattern = componentId.includes("/"); let endpoint; let url; if (isProComponent2 || isPattern) { endpoint = `${this.baseUrl}/pro`; const componentPath = isPattern ? componentId : `components/${componentId}`; url = `${endpoint}?component=${encodeURIComponent(componentPath)}`; } else { endpoint = `${this.baseUrl}/free`; url = `${endpoint}?component=${componentId}`; } const deviceId = DeviceService.getDeviceFingerprint(); const requestOptions = { method: "GET", headers: { "Content-Type": "application/json", "X-Device-ID": deviceId } }; if ((isProComponent2 || isPattern) && license) { requestOptions.headers["Authorization"] = `Bearer ${license.accessToken}`; } const response = await fetch2(url, requestOptions); if (!response.ok) { const errorData = await response.json().catch(() => ({})); if (response.status === 401 && errorData.error?.includes("revoked")) { console.error(import_chalk3.default.red("\n\u274C Your device has been revoked")); console.log(import_chalk3.default.yellow("Please login again to continue:")); console.log(import_chalk3.default.cyan(" moonui login\n")); const { AuthService: AuthService2 } = await Promise.resolve().then(() => (init_auth_service(), auth