UNPKG

lightning-auth-and-payment

Version:

Lightning Network authentication and payment processing library for modern web applications

385 lines (361 loc) • 13.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setupLightning = setupLightning; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const child_process_1 = require("child_process"); async function setupLightning(options) { const { database, port, skipDeps, skipEnv, projectInfo } = options; const projectRoot = process.cwd(); console.log('šŸš€ Setting up Lightning Network integration...\n'); // Step 1: Install dependencies if (!skipDeps) { console.log('šŸ“¦ Installing dependencies...'); await installDependencies(projectInfo); } // Step 2: Setup Next.js configuration console.log('āš™ļø Configuring Next.js...'); await setupNextConfig(projectRoot, projectInfo); // Step 3: Setup environment variables if (!skipEnv) { console.log('šŸ”§ Setting up environment variables...'); await setupEnvironment(projectRoot, port); } // Step 4: Setup database if (database !== 'none') { console.log('šŸ—„ļø Setting up database...'); await setupDatabase(projectRoot, database, projectInfo); } // Step 5: Add development scripts console.log('šŸ“ Adding development scripts...'); await addScripts(projectRoot); console.log('\nāœ… Setup completed successfully!'); } async function installDependencies(projectInfo) { const dependencies = ['lightning-auth-and-payment']; const devDependencies = []; // Add Prisma if not present if (!projectInfo.hasPrisma) { dependencies.push('@prisma/client'); devDependencies.push('prisma'); } // Add TypeScript types if using TypeScript if (projectInfo.hasTypeScript) { devDependencies.push('@types/node'); } try { // Install main dependencies if (dependencies.length > 0) { (0, child_process_1.execSync)(`npm install ${dependencies.join(' ')}`, { stdio: 'inherit' }); } // Install dev dependencies if (devDependencies.length > 0) { (0, child_process_1.execSync)(`npm install --save-dev ${devDependencies.join(' ')}`, { stdio: 'inherit' }); } console.log('āœ… Dependencies installed'); } catch (error) { console.warn('āš ļø Failed to install some dependencies. You may need to install them manually.'); } } async function setupNextConfig(projectRoot, projectInfo) { const nextConfigPath = path_1.default.join(projectRoot, 'next.config.js'); const nextConfigMjsPath = path_1.default.join(projectRoot, 'next.config.mjs'); let configPath = nextConfigPath; let isMjs = false; // Check which config file exists if (fs_1.default.existsSync(nextConfigMjsPath)) { configPath = nextConfigMjsPath; isMjs = true; } else if (!fs_1.default.existsSync(nextConfigPath)) { // Create new config file const configContent = generateNextConfig(isMjs); fs_1.default.writeFileSync(configPath, configContent); console.log('āœ… Created next.config.js'); return; } // Read existing config let existingConfig = ''; if (fs_1.default.existsSync(configPath)) { existingConfig = fs_1.default.readFileSync(configPath, 'utf-8'); } // Check if Lightning is already configured if (existingConfig.includes('withLightning')) { console.log('āœ… Lightning already configured in Next.js'); return; } // Add Lightning configuration const updatedConfig = addLightningToConfig(existingConfig, isMjs); fs_1.default.writeFileSync(configPath, updatedConfig); console.log('āœ… Updated Next.js configuration'); } function generateNextConfig(isMjs) { const importStatement = isMjs ? `import { withLightning } from 'lightning-auth-and-payment/nextjs';` : `const { withLightning } = require('lightning-auth-and-payment/nextjs');`; const exportStatement = isMjs ? `export default withLightning()(nextConfig);` : `module.exports = withLightning()(nextConfig);`; return `${importStatement} /** @type {import('next').NextConfig} */ const nextConfig = { // Your existing configuration }; ${exportStatement} `; } function addLightningToConfig(existingConfig, isMjs) { const importStatement = isMjs ? `import { withLightning } from 'lightning-auth-and-payment/nextjs';` : `const { withLightning } = require('lightning-auth-and-payment/nextjs');`; // Add import if not present if (!existingConfig.includes('withLightning')) { const lines = existingConfig.split('\n'); const importIndex = lines.findIndex(line => line.includes('import') || line.includes('require')); if (importIndex >= 0) { lines.splice(importIndex, 0, importStatement); } else { lines.unshift(importStatement); } existingConfig = lines.join('\n'); } // Wrap export with withLightning if (isMjs) { if (existingConfig.includes('export default')) { existingConfig = existingConfig.replace(/export default (.+);/, 'export default withLightning()($1);'); } else { existingConfig += '\n\nexport default withLightning()(nextConfig);'; } } else { if (existingConfig.includes('module.exports')) { existingConfig = existingConfig.replace(/module\.exports = (.+);/, 'module.exports = withLightning()($1);'); } else { existingConfig += '\n\nmodule.exports = withLightning()(nextConfig);'; } } return existingConfig; } async function setupEnvironment(projectRoot, port) { const envPath = path_1.default.join(projectRoot, '.env.local'); let envContent = ''; if (fs_1.default.existsSync(envPath)) { envContent = fs_1.default.readFileSync(envPath, 'utf-8'); } // Generate session secret const sessionSecret = generateSessionSecret(); // Environment variables to add const newEnvVars = { SESSION_SECRET: sessionSecret, NEXT_PUBLIC_APP_URL: `https://localhost:${port}`, NODE_ENV: 'development', DATABASE_URL: '"file:./prisma/dev.db"', }; // Add missing environment variables let updated = false; for (const [key, value] of Object.entries(newEnvVars)) { if (!envContent.includes(`${key}=`)) { envContent += `\n# Lightning Network Configuration\n${key}=${value}\n`; updated = true; } } if (updated) { fs_1.default.writeFileSync(envPath, envContent); console.log('āœ… Environment variables configured'); } else { console.log('āœ… Environment variables already configured'); } } async function setupDatabase(projectRoot, database, projectInfo) { if (projectInfo.hasPrisma) { console.log('āœ… Prisma already configured'); return; } // Create Prisma directory const prismaDir = path_1.default.join(projectRoot, 'prisma'); if (!fs_1.default.existsSync(prismaDir)) { fs_1.default.mkdirSync(prismaDir, { recursive: true }); } // Generate Prisma schema const schemaContent = generatePrismaSchema(database); const schemaPath = path_1.default.join(prismaDir, 'schema.prisma'); fs_1.default.writeFileSync(schemaPath, schemaContent); console.log('āœ… Prisma schema created'); // Generate Prisma client try { (0, child_process_1.execSync)('npx prisma generate', { stdio: 'inherit' }); console.log('āœ… Prisma client generated'); } catch (error) { console.warn('āš ļø Failed to generate Prisma client. Run "npx prisma generate" manually.'); } } function generatePrismaSchema(database) { const provider = database === 'postgresql' ? 'postgresql' : 'sqlite'; const url = database === 'postgresql' ? 'env("DATABASE_URL")' : 'env("DATABASE_URL")'; return `// This file is automatically generated by the lightning-auth-and-payment CLI // It includes all necessary models for Lightning authentication and payments generator client { provider = "prisma-client-js" } datasource db { provider = "${provider}" url = ${url} } // User model for Lightning Network authentication model User { id String @id @default(cuid()) lnPubkey String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations orders Order[] payments Payment[] invoices Invoice[] @@map("users") } // LNURL challenge model for Lightning Network authentication model LnurlChallenge { id String @id @default(cuid()) k1 String @unique createdAt DateTime @default(now()) expiresAt DateTime isAuthorized Boolean @default(false) linkingKey String? authorizedAt DateTime? @@map("lnurl_challenges") } // LNURL login model for tracking successful logins model LnurlLogin { id String @id @default(cuid()) k1 String @unique userId String token String createdAt DateTime @default(now()) expiresAt DateTime @@map("lnurl_logins") } // Order model for tracking purchases model Order { id String @id @default(cuid()) userId String status OrderStatus @default(PENDING) totalSats Int // Total amount in satoshis createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) items OrderItem[] payment Payment? @@map("orders") } // Order items for individual purchases model OrderItem { id String @id @default(cuid()) orderId String productId String // Generic product ID - can be bookId, courseId, etc. quantity Int @default(1) priceSats Int // Price at time of purchase metadata String? // JSON string for product-specific data // Relations order Order @relation(fields: [orderId], references: [id], onDelete: Cascade) @@map("order_items") } // Payment model for Lightning Network payments model Payment { id String @id @default(cuid()) userId String orderId String? @unique invoiceId String? @unique // BTCPay Server invoice ID bolt11 String? // Lightning invoice amountSats Int status PaymentStatus @default(PENDING) description String? expiresAt DateTime? paidAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) order Order? @relation(fields: [orderId], references: [id]) @@map("payments") } // Invoice model for Lightning Network payments model Invoice { id String @id @default(cuid()) btcpayInvoiceId String @unique userId String? user User? @relation(fields: [userId], references: [id], onDelete: SetNull) amountSats Int status String // NEW, SETTLED, EXPIRED clientSeed String createdAt DateTime @default(now()) settledAt DateTime? claimToken String? @unique claimedByUserId String? metadata String? // JSON string for additional data @@map("invoices") } // Enums enum OrderStatus { PENDING PAID CANCELLED REFUNDED } enum PaymentStatus { PENDING PAID FAILED CANCELLED REFUNDED }`; } async function addScripts(projectRoot) { const packageJsonPath = path_1.default.join(projectRoot, 'package.json'); if (!fs_1.default.existsSync(packageJsonPath)) { return; } const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8')); if (!packageJson.scripts) { packageJson.scripts = {}; } // Add Lightning development scripts const newScripts = { 'dev:lightning': 'lightning-dev-server', 'dev:https': 'lightning-dev-server', 'db:generate': 'npx prisma generate', 'db:migrate': 'npx prisma migrate dev', 'db:reset': 'npx prisma migrate reset --force', 'db:studio': 'npx prisma studio', }; let updated = false; for (const [script, command] of Object.entries(newScripts)) { if (!packageJson.scripts[script]) { packageJson.scripts[script] = command; updated = true; } } if (updated) { fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); console.log('āœ… Development scripts added'); } else { console.log('āœ… Development scripts already configured'); } } function generateSessionSecret() { const crypto = require('crypto'); return crypto.randomBytes(32).toString('hex'); } //# sourceMappingURL=setup.js.map