spaps
Version:
Sweet Potato Authentication & Payment Service CLI - Zero-config local development and project scaffolding
337 lines (298 loc) โข 10.7 kB
JavaScript
/**
* SPAPS CLI - Sweet Potato Authentication & Payment Service
*
* This is a minimal implementation to secure the npm package name.
* Full implementation coming soon!
*/
const chalk = require('chalk');
const { program } = require('commander');
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const { handleError } = require('../src/error-handler');
const { showInteractiveHelp, showQuickHelp } = require('../src/help-system');
const { showInteractiveDocs, showQuickReference, searchDocs } = require('../src/docs-system');
const { getQuickStartInstructions, getServerStatus, runQuickTest } = require('../src/ai-helper');
const version = require('../package.json').version;
// ASCII Art Logo
const logo = `
${chalk.yellow('๐ SPAPS')} - Sweet Potato Authentication & Payment Service
`;
program
.name('spaps')
.description('CLI for Sweet Potato Authentication & Payment Service')
.version(version)
.option('--json', 'Output in JSON format for machine parsing');
// Local command - Start local development server
program
.command('local')
.description('Start local SPAPS server (no API keys required!)')
.option('-p, --port <port>', 'Port to run on', '3300')
.option('-o, --open', 'Open browser automatically', false)
.option('--json', 'Output in JSON format')
.action(async (options, command) => {
const isJson = options.json || command.parent.opts().json;
if (!isJson) {
console.log(logo);
}
try {
// Import and start the local server
const LocalServer = require('../src/local-server.js');
const server = new LocalServer({ port: options.port, json: isJson });
if (isJson) {
// For JSON output, start server and return immediately
await server.start();
console.log(JSON.stringify({
success: true,
command: 'local',
server: {
url: `http://localhost:${options.port}`,
docs: `http://localhost:${options.port}/docs`,
mode: 'local-development',
port: parseInt(options.port),
features: {
autoAuth: true,
corsEnabled: true,
testUsers: ['user', 'admin', 'premium'],
apiKeyRequired: false
}
}
}));
} else {
await server.start();
// Open browser if requested
if (options.open) {
const { exec } = require('child_process');
const url = `http://localhost:${options.port}/docs`;
const start = process.platform === 'darwin' ? 'open' :
process.platform === 'win32' ? 'start' : 'xdg-open';
exec(`${start} ${url}`);
}
}
// Keep process running
process.on('SIGINT', () => {
if (!isJson) {
console.log(chalk.yellow('\n๐ Shutting down SPAPS local server...'));
}
process.exit(0);
});
} catch (error) {
handleError(error, { port: options.port, command: 'local' }, { json: isJson });
}
});
// Quickstart command - For AI agents
program
.command('quickstart')
.description('Get quick start instructions (for AI agents)')
.option('-p, --port <port>', 'Port to check', '3300')
.option('--json', 'Output in JSON format')
.action(async (options) => {
const instructions = getQuickStartInstructions(options.port);
if (options.json === true) {
console.log(JSON.stringify(instructions, null, 2));
process.exit(0);
} else {
console.log(chalk.yellow('\n๐ SPAPS Quick Start Instructions\n'));
console.log('1. Install SDK: npm install spaps-sdk');
console.log('2. Create test file with the code above');
console.log('3. Run: node test-spaps.js');
console.log('\nFor JSON output: npx spaps quickstart --json');
}
});
// Status command - Check if server is running
program
.command('status')
.description('Check if SPAPS server is running')
.option('-p, --port <port>', 'Port to check', '3300')
.option('--json', 'Output in JSON format')
.action(async (options) => {
const status = await getServerStatus(options.port);
if (options.json) {
console.log(JSON.stringify(status));
} else {
if (status.running) {
console.log(chalk.green(`โ
SPAPS is running on port ${options.port}`));
console.log(chalk.blue(` URL: ${status.url}`));
console.log(chalk.blue(` Docs: ${status.docs}`));
} else {
console.log(chalk.red(`โ SPAPS is not running on port ${options.port}`));
console.log(chalk.yellow(` Start with: ${status.start_command}`));
}
}
});
// Test command - Run quick tests
program
.command('test')
.description('Run quick tests to verify SPAPS is working')
.option('-p, --port <port>', 'Port to test', '3300')
.option('--json', 'Output in JSON format')
.action(async (options) => {
const results = await runQuickTest(options.port);
if (options.json) {
console.log(JSON.stringify(results, null, 2));
} else {
console.log(chalk.yellow('\n๐งช Running SPAPS Tests...\n'));
results.results.forEach(result => {
const icon = result.success ? 'โ
' : 'โ';
console.log(`${icon} ${result.test}`);
if (!result.success && result.fix) {
console.log(chalk.yellow(` Fix: ${result.fix}`));
}
});
console.log();
console.log(results.success ?
chalk.green(`โจ ${results.summary}`) :
chalk.red(`โ ๏ธ ${results.summary}`)
);
if (results.next_steps) {
console.log('\nNext steps:');
results.next_steps.forEach(step => {
console.log(` โข ${step}`);
});
}
}
});
// Init command - Initialize SPAPS in existing project
program
.command('init')
.description('Initialize SPAPS in your project')
.option('--json', 'Output in JSON format')
.action((options, command) => {
const isJson = options.json || command.parent.opts().json;
if (!isJson) {
console.log(logo);
console.log(chalk.green('๐ง Initializing SPAPS...'));
console.log();
}
// Create minimal .env.local
const envContent = `# SPAPS Local Development Configuration
# No API keys needed for local development!
SPAPS_API_URL=http://localhost:3300
NODE_ENV=development
# When you're ready for production:
# SPAPS_API_KEY=your-api-key-here
`;
const result = {
success: true,
command: 'init',
files_created: [],
files_skipped: [],
next_steps: [
'npx spaps local',
'npm install @spaps/sdk',
'Start coding!'
]
};
if (!fs.existsSync('.env.local')) {
fs.writeFileSync('.env.local', envContent);
result.files_created.push('.env.local');
if (!isJson) {
console.log(chalk.green('โ
Created .env.local'));
}
} else {
result.files_skipped.push('.env.local');
result.message = '.env.local already exists';
if (!isJson) {
console.log(chalk.yellow('โ ๏ธ .env.local already exists'));
}
}
if (isJson) {
console.log(JSON.stringify(result));
} else {
console.log();
console.log(chalk.green('โจ SPAPS initialized!'));
console.log();
console.log('Next steps:');
console.log(chalk.cyan(' 1. Run: npx spaps local'));
console.log(chalk.cyan(' 2. Install SDK: npm install @spaps/sdk'));
console.log(chalk.cyan(' 3. Start coding!'));
}
});
// Create command (placeholder)
program
.command('create <name>')
.description('Create a new project with SPAPS (coming soon)')
.action((name) => {
console.log(logo);
console.log(chalk.yellow(`๐ง 'spaps create' coming in v0.3.0!`));
console.log();
console.log('For now, check out our examples:');
console.log(chalk.cyan(' https://github.com/yourusername/sweet-potato/tree/main/examples'));
});
// Types command (placeholder)
program
.command('types')
.description('Generate TypeScript types (coming soon)')
.action(() => {
console.log(logo);
console.log(chalk.yellow(`๐ง 'spaps types' coming in v0.4.0!`));
});
// Help command - Interactive help system
program
.command('help')
.description('Show help and guides')
.option('-i, --interactive', 'Interactive help mode')
.option('-q, --quick', 'Quick reference')
.action(async (options) => {
if (options.interactive) {
await showInteractiveHelp();
} else if (options.quick) {
showQuickHelp();
} else {
// Default to quick help
showQuickHelp();
}
});
// Docs command - SDK documentation
program
.command('docs')
.description('Browse SDK documentation')
.option('-i, --interactive', 'Interactive documentation browser')
.option('-s, --search <query>', 'Search documentation')
.option('--json', 'Output in JSON format')
.action(async (options) => {
if (options.search) {
const results = searchDocs(options.search);
if (options.json) {
console.log(JSON.stringify({ results }, null, 2));
} else {
console.log(chalk.yellow(`\n๐ Search results for "${options.search}":\n`));
if (results.length === 0) {
console.log(chalk.gray(' No results found'));
} else {
results.forEach((result, i) => {
console.log(chalk.green(` ${i + 1}. ${result.title}`));
console.log(chalk.gray(` ${result.preview}`));
console.log();
});
}
console.log(chalk.blue(' Run: npx spaps docs --interactive'));
console.log(chalk.blue(' to browse full documentation\n'));
}
} else if (options.interactive) {
await showInteractiveDocs();
} else {
// Default to quick reference
showQuickReference();
}
});
// Help command enhancement
program.on('--help', () => {
console.log();
console.log('Examples:');
console.log();
console.log(' $ spaps local # Start local dev server');
console.log(' $ spaps init # Initialize in current project');
console.log(' $ spaps create my-app # Create new project (soon)');
console.log();
console.log('Learn more at https://sweetpotato.dev');
});
// Show help if no command provided
if (!process.argv.slice(2).length) {
console.log(logo);
program.outputHelp();
console.log();
console.log(chalk.yellow('๐ก Try: npx spaps help --interactive'));
}
program.parse(process.argv);