UNPKG

puter-cli

Version:

Command line interface for Puter cloud platform

220 lines (198 loc) 8.57 kB
import chalk from 'chalk'; import fetch from 'node-fetch'; import Table from 'cli-table3'; import { getCurrentUserName, getCurrentDirectory } from './auth.js'; import { API_BASE, getHeaders, generateAppName, resolvePath, isValidAppName } from '../commons.js'; import { displayNonNullValues, formatDate, isValidAppUuid } from '../utils.js'; import { getSubdomains, createSubdomain, deleteSubdomain } from './subdomains.js'; import { ErrorAPI } from '../modules/ErrorModule.js'; /** * Listing subdomains */ export async function listSites(args = {}, context) { try { const data = await getSubdomains(args); if (!data.success || !Array.isArray(data.result)) { throw new Error('Failed to fetch subdomains'); } // Create table instance const table = new Table({ head: [ chalk.cyan('#'), chalk.cyan('UID'), chalk.cyan('Subdomain'), chalk.cyan('Created'), chalk.cyan('Protected'), // chalk.cyan('Owner'), chalk.cyan('Directory') ], wordWrap: false }); // Format and add data to table let i = 0; data.result.forEach(domain => { let appDir = domain?.root_dir?.path.split('/').pop().split('-'); table.push([ i++, domain.uid, chalk.green(`${chalk.dim(domain.subdomain)}.puter.site`), formatDate(domain.created_at).split(',')[0], domain.protected ? chalk.red('Yes') : chalk.green('No'), // domain.owner['username'], appDir && (isValidAppUuid(appDir.join('-'))?`${appDir[0]}-...-${appDir.slice(-1)}`:appDir.join('-')) ]); }); // Print table if (data.result.length === 0) { console.log(chalk.yellow('No subdomains found')); } else { console.log(chalk.bold('\nYour Sites:')); console.log(table.toString()); console.log(chalk.dim(`Total Sites: ${data.result.length}`)); } } catch (error) { context.events.emit('error', { error }); console.error(chalk.red('Error listing sites:'), error.message); throw error; } } /** * Get Site info * @param {any[]} args Array of site uuid */ export async function infoSite(args = []) { if (args.length < 1){ console.log(chalk.red('Usage: site <siteUID>')); return; } for (const subdomainId of args) try { const response = await fetch(`${API_BASE}/drivers/call`, { method: 'POST', headers: getHeaders(), body: JSON.stringify({ interface: 'puter-subdomains', method: 'read', args: { uid: subdomainId } }) }); if (!response.ok) { throw new Error('Failed to fetch subdomains.'); } const data = await response.json(); if (!data.success || !data.result) { throw new Error(`Failed to get site info: ${data.error?.message}`); } displayNonNullValues(data.result); } catch (error) { console.error(chalk.red('Error getting site info:'), error.message); } } /** * Delete hosted web site * @param {any[]} args Array of site uuid */ export async function deleteSite(args = []) { if (args.length < 1){ console.log(chalk.red('Usage: site:delete <siteUUID>')); return false; } for (const uuid of args) try { // The uuid must be prefixed with: 'subdomainObj-' const response = await fetch(`${API_BASE}/delete-site`, { headers: getHeaders(), method: 'POST', body: JSON.stringify({ site_uuid: uuid }) }); if (!response.ok) { throw new Error(`Failed to delete site (Status: ${response.status})`); } const data = await response.json(); if (Object.keys(data).length==0) { console.log(chalk.green(`Site ID: "${uuid}" has been deleted.`)); return; } console.log(chalk.yellow(`Site ID: "${uuid}" should be deleted.`)); } catch (error) { console.error(chalk.red('Error deleting site:'), error.message); return false; } return true; } /** * Create a static web app from the current directory to Puter cloud. * @param {string[]} args - Command-line arguments (e.g., [name, --subdomain=<subdomain>]). */ export async function createSite(args = []) { if (args.length < 1 || !isValidAppName(args[0])) { console.log(chalk.red('Usage: site:create <valid_name_app> [<remote_dir>] [--subdomain=<subdomain>]')); console.log(chalk.yellow('Example: site:create mysite')); console.log(chalk.yellow('Example: site:create mysite ./mysite')); console.log(chalk.yellow('Example: site:create mysite --subdomain=mysite')); return; } const appName = args[0]; // Site name (required) const subdomainOption = args.find(arg => arg.toLocaleLowerCase().startsWith('--subdomain='))?.split('=')[1]; // Optional subdomain // Use the current directory as the root directory if none specified const remoteDir = resolvePath(getCurrentDirectory(), (args[1] && !args[1].startsWith('--'))?args[1]:'.'); console.log(chalk.dim(`Creating site ${chalk.green(appName)} from: ${chalk.green(remoteDir)}...\n`)); try { // Step 1: Determine the subdomain let subdomain; if (subdomainOption) { subdomain = subdomainOption; // Use the provided subdomain } else { subdomain = appName; // Default to the app name as the subdomain } // Step 2: Check if the subdomain already exists const data = await getSubdomains(); if (!data.success || !Array.isArray(data.result)) { throw new Error('Failed to fetch subdomains'); } const subdomains = data.result; const subdomainObj = subdomains.find(sd => sd.subdomain === subdomain); if (subdomainObj) { console.error(chalk.cyan(`The subdomain "${subdomain}" is already in use and owned by: "${subdomainObj.owner['username']}"`)); if (subdomainObj.owner['username'] === getCurrentUserName()){ console.log(chalk.green(`It's yours, and linked to: ${subdomainObj.root_dir?.path}`)); if (subdomainObj.root_dir?.path === remoteDir){ console.log(chalk.cyan(`Which is already the selected directory, and created at:`)); console.log(chalk.green(`https://${subdomain}.puter.site`)); return; } else { console.log(chalk.yellow(`However, It's linked to different directory at: ${subdomainObj.root_dir?.path}`)); console.log(chalk.cyan(`We'll try to unlink this subdomain from that directory...`)); const result = await deleteSubdomain([subdomainObj?.uid]); if (result) { console.log(chalk.green('Looks like this subdomain is free again, please try again.')); return; } else { console.log(chalk.red('Could not release this subdomain.')); } } } } // else { // console.log(chalk.yellow(`The subdomain: "${subdomain}" is already taken, so let's generate a new random one:`)); // subdomain = generateAppName(); // Generate a random subdomain // console.log(chalk.cyan(`New generated subdomain: "${subdomain}" will be used.`)); // } // Use the chosen "subdomain" console.log(chalk.cyan(`New generated subdomain: "${subdomain}" will be used if its not already in use.`)); // Step 3: Host the current directory under the subdomain console.log(chalk.cyan(`Hosting app "${appName}" under subdomain "${subdomain}"...`)); const site = await createSubdomain(subdomain, remoteDir); if (!site){ console.error(chalk.red(`Failed to create subdomain: "${chalk.red(subdomain)}"`)); return; } console.log(chalk.green(`App ${chalk.dim(appName)} created successfully and accessible at:`)); console.log(chalk.cyan(`https://${site.subdomain}.puter.site`)); } catch (error) { console.error(chalk.red('Failed to create site.')); console.error(chalk.red(`Error: ${error.message}`)); } }