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
JavaScript
/**
* 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
};