UNPKG

quallaa-cli

Version:

Sets up core infrastructure services for AI-assisted development

256 lines • 9.56 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setupResend = setupResend; exports.sendTestEmail = sendTestEmail; const chalk_1 = __importDefault(require("chalk")); const inquirer_1 = __importDefault(require("inquirer")); const axios_1 = __importDefault(require("axios")); const credentials_1 = require("../storage/credentials"); const RESEND_API_BASE = 'https://api.resend.com'; async function setupResend() { try { console.log(chalk_1.default.gray('\nResend provides transactional email infrastructure.')); console.log(chalk_1.default.gray('You\'ll need a Resend account (free tier: 3,000 emails/month).\n')); const existing = await (0, credentials_1.getCredentials)('resend'); if (existing) { const { useExisting } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'useExisting', message: 'Existing Resend credentials found. Use them?', default: true, }, ]); if (useExisting) { return { success: true, service: 'resend', message: 'Using existing credentials' }; } } console.log(chalk_1.default.yellow('\nšŸ“ Resend API Key Setup')); console.log(chalk_1.default.gray('1. Go to: https://resend.com/api-keys')); console.log(chalk_1.default.gray('2. Create a new API key with "Full Access" permission')); console.log(chalk_1.default.gray('3. Copy the key and paste it below\n')); const { apiKey } = await inquirer_1.default.prompt([ { type: 'password', name: 'apiKey', message: 'Resend API key:', validate: (input) => { if (!input.startsWith('re_')) { return 'Invalid API key format. Should start with "re_"'; } return true; }, }, ]); const isValid = await verifyApiKey(apiKey); if (!isValid) { throw new Error('Invalid API key'); } console.log(chalk_1.default.green('āœ“ API key verified')); const { setupDomain } = await inquirer_1.default.prompt([ { type: 'confirm', name: 'setupDomain', message: 'Would you like to set up a custom domain for sending?', default: false, }, ]); let domain; if (setupDomain) { domain = await configureDomain(apiKey); } const credentials = { apiKey, domain }; await (0, credentials_1.saveCredentials)('resend', credentials); await addToEnvFile(apiKey); return { success: true, service: 'resend', credentials: { resend: credentials }, }; } catch (error) { return { success: false, service: 'resend', message: error instanceof Error ? error.message : 'Setup failed', error: error, }; } } async function verifyApiKey(apiKey) { try { const response = await axios_1.default.get(`${RESEND_API_BASE}/api-keys`, { headers: { Authorization: `Bearer ${apiKey}`, }, }); return response.status === 200; } catch { return false; } } async function configureDomain(apiKey) { const { domainChoice } = await inquirer_1.default.prompt([ { type: 'list', name: 'domainChoice', message: 'Domain setup:', choices: [ { name: 'Add a new domain', value: 'new' }, { name: 'Use an existing domain', value: 'existing' }, ], }, ]); if (domainChoice === 'new') { return await addNewDomain(apiKey); } else { return await selectExistingDomain(apiKey); } } async function addNewDomain(apiKey) { const { domain } = await inquirer_1.default.prompt([ { type: 'input', name: 'domain', message: 'Enter your domain (e.g., example.com):', validate: (input) => { const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/; if (!domainRegex.test(input)) { return 'Invalid domain format'; } return true; }, }, ]); try { const response = await axios_1.default.post(`${RESEND_API_BASE}/domains`, { name: domain }, { headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, }); console.log(chalk_1.default.yellow('\nšŸ“‹ DNS Records to add:')); console.log(chalk_1.default.gray('Add these records to your domain\'s DNS settings:\n')); const records = response.data.records; records.forEach((record) => { console.log(chalk_1.default.cyan(`Type: ${record.type}`)); console.log(chalk_1.default.gray(`Name: ${record.name}`)); console.log(chalk_1.default.gray(`Value: ${record.value}`)); console.log(chalk_1.default.gray('---')); }); console.log(chalk_1.default.yellow('\nAfter adding these records, domain verification may take up to 72 hours.')); return domain; } catch (error) { console.error(chalk_1.default.red('Failed to add domain')); throw error; } } async function selectExistingDomain(apiKey) { try { const response = await axios_1.default.get(`${RESEND_API_BASE}/domains`, { headers: { Authorization: `Bearer ${apiKey}`, }, }); const domains = response.data.data.filter((d) => d.status === 'verified'); if (domains.length === 0) { console.log(chalk_1.default.yellow('No verified domains found. Using default resend.dev domain.')); return 'resend.dev'; } const { selectedDomain } = await inquirer_1.default.prompt([ { type: 'list', name: 'selectedDomain', message: 'Select a domain:', choices: domains.map((d) => ({ name: `${d.name} (${d.status})`, value: d.name, })), }, ]); return selectedDomain; } catch { return 'resend.dev'; } } async function addToEnvFile(apiKey) { const envContent = ` # Resend RESEND_API_KEY=${apiKey} `; const fs = await Promise.resolve().then(() => __importStar(require('fs/promises'))); try { await fs.access('.env.local'); await fs.appendFile('.env.local', envContent); } catch { await fs.writeFile('.env.local', envContent); } console.log(chalk_1.default.green('āœ“ Environment variable added to .env.local')); } async function sendTestEmail(to, from) { const credentials = await (0, credentials_1.getCredentials)('resend'); if (!credentials?.apiKey) { throw new Error('Resend not configured. Run "quallaa setup resend" first.'); } const fromEmail = from || `onboarding@${credentials.domain || 'resend.dev'}`; const response = await axios_1.default.post(`${RESEND_API_BASE}/emails`, { from: fromEmail, to: [to], subject: 'Test Email from Quallaa CLI', html: ` <h1>Welcome to Quallaa!</h1> <p>Your email service is configured correctly.</p> <p>You're ready to build AI-native applications!</p> `, }, { headers: { Authorization: `Bearer ${credentials.apiKey}`, 'Content-Type': 'application/json', }, }); if (response.data.id) { console.log(chalk_1.default.green('āœ“ Test email sent successfully')); } } //# sourceMappingURL=resend.js.map