UNPKG

spaps

Version:

Sweet Potato Authentication & Payment Service CLI - Zero-config local development with built-in admin middleware and permission utilities

490 lines (443 loc) • 13.5 kB
/** * SPAPS CLI Interactive Help System * Decision trees and structured guidance for developers */ const chalk = require('chalk'); const prompts = require('prompts'); const { DEFAULT_PORT } = require('./config'); const HELP_TREE = { root: { question: 'What would you like to do?', options: [ { title: 'šŸš€ Start developing locally', value: 'local-dev', description: 'Run SPAPS on your machine' }, { title: 'šŸ“¦ Set up a new project', value: 'new-project', description: 'Create a new app with SPAPS' }, { title: 'šŸ”§ Add SPAPS to existing project', value: 'existing-project', description: 'Integrate SPAPS into your app' }, { title: 'šŸ› Debug an issue', value: 'debug', description: 'Troubleshoot problems' }, { title: 'šŸ“š Learn about SPAPS', value: 'learn', description: 'Understand concepts and features' } ] }, 'local-dev': { question: 'How do you want to run SPAPS locally?', options: [ { title: 'Quick start (default settings)', value: 'quick-start', command: 'npx spaps local', description: `Start on port ${DEFAULT_PORT}` }, { title: 'Custom port', value: 'custom-port', command: `npx spaps local --port ${DEFAULT_PORT + 1}`, description: 'Choose your own port' }, { title: 'Open browser automatically', value: 'auto-open', command: 'npx spaps local --open', description: 'Opens docs in browser' }, { title: 'JSON mode (for CI/CD)', value: 'json-mode', command: 'npx spaps local --json', description: 'Machine-readable output' } ] }, 'new-project': { question: 'What type of project?', options: [ { title: 'Next.js App', value: 'nextjs', command: 'npx spaps create my-app --template nextjs', description: 'Full-stack React framework', available: 'v0.3.0' }, { title: 'React + Vite', value: 'react', command: 'npx spaps create my-app --template react', description: 'Fast, modern React setup', available: 'v0.3.0' }, { title: 'Node.js API', value: 'node', command: 'npx spaps create my-api --template node', description: 'Express.js backend', available: 'v0.3.0' }, { title: 'Vanilla JavaScript', value: 'vanilla', command: 'npx spaps create my-app --template vanilla', description: 'No framework, just JS', available: 'v0.3.0' } ] }, 'existing-project': { question: 'What framework are you using?', options: [ { title: 'Next.js', value: 'integrate-nextjs', steps: [ 'npm install spaps-sdk', 'npx spaps init', 'Add to your app:', '', '// app/providers.tsx', 'import { SPAPSClient } from "spaps-sdk"', 'const spaps = new SPAPSClient()' ] }, { title: 'React', value: 'integrate-react', steps: [ 'npm install spaps-sdk', 'npx spaps init', 'Create a context:', '', '// src/contexts/SpapsContext.tsx', 'import { SPAPSClient } from "spaps-sdk"', 'const spaps = new SPAPSClient()', 'export const SpapsContext = React.createContext(spaps)' ] }, { title: 'Node.js/Express', value: 'integrate-node', steps: [ 'npm install spaps-sdk', 'npx spaps init', 'Add middleware:', '', '// server.js', 'const { SPAPSClient } = require("spaps-sdk")', 'const spaps = new SPAPSClient()', '', 'app.use(async (req, res, next) => {', ' req.spaps = spaps', ' next()', '})' ] }, { title: 'Other/Vanilla', value: 'integrate-other', steps: [ 'npm install spaps-sdk', 'npx spaps init', 'Import in your code:', '', '// Using ES6 modules', 'import { SPAPSClient } from "spaps-sdk"', '', '// Using CommonJS', 'const { SPAPSClient } = require("spaps-sdk")', '', '// Using CDN', '<script src="https://unpkg.com/spaps-sdk"></script>' ] } ] }, 'debug': { question: 'What issue are you experiencing?', options: [ { title: 'Port already in use', value: 'port-error', solution: { commands: [ 'npx spaps local --port 3301', 'lsof -ti:3300 | xargs kill -9', 'npx spaps local --port 0' ], explanation: 'Another process is using port 3300. Either use a different port or kill the existing process.' } }, { title: 'Module not found', value: 'module-error', solution: { commands: [ 'npm install', 'rm -rf node_modules package-lock.json && npm install', 'npm install spaps-sdk' ], explanation: 'Dependencies are missing. Reinstall packages to fix this.' } }, { title: 'CORS errors', value: 'cors-error', solution: { commands: [ 'npx spaps local', 'Check your API URL: process.env.SPAPS_API_URL' ], explanation: 'CORS is automatically handled in local mode. Make sure your client is pointing to the local server.' } }, { title: 'Authentication failing', value: 'auth-error', solution: { commands: [ 'curl http://localhost:3300/health', 'npx spaps local --port 3300' ], explanation: 'In local mode, authentication is automatic. Make sure the local server is running.' } } ] }, 'learn': { question: 'What would you like to learn about?', options: [ { title: 'How SPAPS works', value: 'how-it-works', content: ` SPAPS (Sweet Potato Authentication & Payment Service) provides: 1. **Authentication**: Email/password, magic links, and wallet-based auth 2. **Payments**: Stripe subscriptions and wallet-based payments 3. **Local Development**: Zero-config local mode with auto-auth 4. **Type Safety**: Full TypeScript support with generated types 5. **Multi-tenant**: API key-based app isolation In local mode, everything is mocked so you can develop without: - API keys - Database setup - External services - Configuration files ` }, { title: 'Local vs Production', value: 'environments', content: ` **Local Mode** (http://localhost:3300): - No API key required - Auto-authentication - Mocked responses - CORS disabled - Perfect for development **Production Mode** (https://api.yourapp.com): - API key required - Real authentication - Database persistence - Stripe integration - Rate limiting The SDK auto-detects which mode to use based on the URL! ` }, { title: 'Authentication methods', value: 'auth-methods', content: ` SPAPS supports multiple authentication methods: **Traditional Auth**: - Email/password login - Magic link (passwordless) - Social logins (coming soon) **Wallet Auth**: - Solana wallets - Ethereum wallets - Bitcoin (coming soon) - Base chain (coming soon) **Code Examples**: \`\`\`javascript // Email/password await spaps.login(email, password) // Wallet await spaps.walletSignIn(address, signature, message, 'solana') \`\`\` ` }, { title: 'Payment integration', value: 'payments', content: ` SPAPS handles two payment types: **Stripe Subscriptions**: - Monthly/annual plans - Usage-based billing - Customer portal - Webhook handling **Wallet Payments**: - Direct crypto payments - Usage credits - Instant settlement - Multi-chain support **Code Example**: \`\`\`javascript // Create Stripe checkout const session = await spaps.createCheckoutSession(priceId, successUrl) // Check subscription const sub = await spaps.getSubscription() \`\`\` ` } ] } }; async function showInteractiveHelp() { console.log(chalk.yellow('\nšŸ  SPAPS Interactive Help\n')); let currentNode = 'root'; const history = []; while (true) { const node = HELP_TREE[currentNode]; if (!node) { // Leaf node - show result break; } const choices = node.options.map(opt => ({ title: opt.title, description: opt.description || '', value: opt.value })); // Add back option if not at root if (currentNode !== 'root') { choices.push({ title: chalk.gray('← Back'), value: '__back__' }); } choices.push({ title: chalk.gray('āœ• Exit'), value: '__exit__' }); const response = await prompts({ type: 'select', name: 'choice', message: node.question, choices: choices }); if (!response.choice || response.choice === '__exit__') { console.log(chalk.gray('\nGoodbye! šŸ‘‹\n')); process.exit(0); } if (response.choice === '__back__') { currentNode = history.pop() || 'root'; continue; } // Find the selected option const selected = node.options.find(opt => opt.value === response.choice); if (selected) { // Show immediate result if available if (selected.command) { console.log(chalk.green('\n✨ Run this command:\n')); console.log(chalk.bgBlack.white(` $ ${selected.command}`)); if (selected.available) { console.log(chalk.yellow(`\n āš ļø Available in ${selected.available}`)); } console.log(); } if (selected.steps) { console.log(chalk.green('\nšŸ“ Follow these steps:\n')); selected.steps.forEach((step, i) => { if (step.startsWith('//') || step.startsWith('#')) { console.log(chalk.gray(step)); } else if (step === '') { console.log(); } else if (step.includes('npm') || step.includes('npx')) { console.log(chalk.bgBlack.white(` $ ${step}`)); } else { console.log(` ${step}`); } }); console.log(); } if (selected.solution) { console.log(chalk.green('\nšŸ’” Solution:\n')); console.log(chalk.white(selected.solution.explanation)); console.log(chalk.green('\nTry these commands:\n')); selected.solution.commands.forEach(cmd => { console.log(chalk.bgBlack.white(` $ ${cmd}`)); }); console.log(); } if (selected.content) { console.log(chalk.green('\nšŸ“š Information:\n')); console.log(selected.content); } // Navigate to next level if exists if (HELP_TREE[response.choice]) { history.push(currentNode); currentNode = response.choice; } else { // Ask to continue or exit const cont = await prompts({ type: 'confirm', name: 'continue', message: 'Continue exploring help?', initial: true }); if (!cont.continue) { console.log(chalk.gray('\nGoodbye! šŸ‘‹\n')); process.exit(0); } // Go back to previous menu currentNode = history.pop() || 'root'; } } } } function showQuickHelp() { console.log(chalk.yellow('\nšŸ  SPAPS Quick Reference\n')); console.log(chalk.green('Common Commands:')); console.log(' npx spaps local ' + chalk.gray('# Start local server')); console.log(' npx spaps init ' + chalk.gray('# Initialize in project')); console.log(' npx spaps create <name> ' + chalk.gray('# Create new project (v0.3.0)')); console.log(' npx spaps types ' + chalk.gray('# Generate types (v0.4.0)')); console.log(); console.log(chalk.green('Local Development:')); console.log(' npx spaps local --port 3001 ' + chalk.gray('# Custom port')); console.log(' npx spaps local --open ' + chalk.gray('# Open browser')); console.log(' npx spaps local --json ' + chalk.gray('# JSON output')); console.log(); console.log(chalk.green('SDK Usage:')); console.log(' npm install spaps-sdk ' + chalk.gray('# Install SDK')); console.log(); console.log(chalk.gray(' import { SPAPSClient } from "spaps-sdk"')); console.log(chalk.gray(' const spaps = new SPAPSClient()')); console.log(chalk.gray(' await spaps.login(email, password)')); console.log(); console.log(chalk.green('Debugging:')); console.log(' curl http://localhost:3300/health ' + chalk.gray('# Check server')); console.log(' npx spaps help --interactive ' + chalk.gray('# Interactive help')); console.log(); console.log(chalk.blue('šŸ“š Docs: https://sweetpotato.dev')); console.log(chalk.blue('šŸ’¬ Discord: https://discord.gg/sweetpotato')); console.log(); } module.exports = { showInteractiveHelp, showQuickHelp, HELP_TREE };