lightning-auth-and-payment
Version:
Lightning Network authentication and payment processing library for modern web applications
385 lines (361 loc) ⢠13.1 kB
JavaScript
"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
lnPubkey String
createdAt DateTime
updatedAt DateTime
// Relations
orders Order[]
payments Payment[]
invoices Invoice[]
@
}
// LNURL challenge model for Lightning Network authentication
model LnurlChallenge {
id String
k1 String
createdAt DateTime
expiresAt DateTime
isAuthorized Boolean
linkingKey String?
authorizedAt DateTime?
@
}
// LNURL login model for tracking successful logins
model LnurlLogin {
id String
k1 String
userId String
token String
createdAt DateTime
expiresAt DateTime
@
}
// Order model for tracking purchases
model Order {
id String
userId String
status OrderStatus
totalSats Int // Total amount in satoshis
createdAt DateTime
updatedAt DateTime
// Relations
user User
items OrderItem[]
payment Payment?
@
}
// Order items for individual purchases
model OrderItem {
id String
orderId String
productId String // Generic product ID - can be bookId, courseId, etc.
quantity Int
priceSats Int // Price at time of purchase
metadata String? // JSON string for product-specific data
// Relations
order Order
@
}
// Payment model for Lightning Network payments
model Payment {
id String
userId String
orderId String?
invoiceId String? // BTCPay Server invoice ID
bolt11 String? // Lightning invoice
amountSats Int
status PaymentStatus
description String?
expiresAt DateTime?
paidAt DateTime?
createdAt DateTime
updatedAt DateTime
// Relations
user User
order Order?
@
}
// Invoice model for Lightning Network payments
model Invoice {
id String
btcpayInvoiceId String
userId String?
user User?
amountSats Int
status String // NEW, SETTLED, EXPIRED
clientSeed String
createdAt DateTime
settledAt DateTime?
claimToken String?
claimedByUserId String?
metadata String? // JSON string for additional data
@
}
// 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