#!/usr/bin/env node /** * DeafFounders Hub - Universal Server * Compatible with Node.js and Deno * ES Modules, Modern Architecture, Clean Modules */ import { createServer } from 'http'; import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join, extname } from 'path'; import { spawn } from 'child_process'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Configuration Manager class ConfigManager { constructor() { this.configPath = join(__dirname, 'config', 'api.json'); this.config = this.load(); } load() { try { if (existsSync(this.configPath)) { return JSON.parse(readFileSync(this.configPath, 'utf8')); } } catch (e) { console.log('⚠️ No existing config found, using defaults'); } return { port: process.env.PORT || 3000, env: process.env.NODE_ENV || 'development', cors: { origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] }, modules: { auth: true, api: true, admin: true, static: true }, redirects: { '/business-magician': 'https://pinkycollie.github.io/Business-Magician/', '/docs': 'https://docs.deaffoundershub.com', '/support': 'https://support.deaffoundershub.com' }, database: { type: 'json', path: './data' } }; } save(config) { const dir = dirname(this.configPath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } writeFileSync(this.configPath, JSON.stringify(config, null, 2)); this.config = config; } get() { return this.config; } update(updates) { const newConfig = { ...this.config, ...updates }; this.save(newConfig); return newConfig; } } // Module System class ModuleLoader { constructor() { this.modules = new Map(); this.routes = new Map(); } async load(name, path) { try { const module = await import(path); this.modules.set(name, module); if (module.routes) { this.routes.set(name, module.routes); } console.log(`✅ Module loaded: ${name}`); return true; } catch (e) { console.error(`❌ Failed to load module ${name}:`, e.message); return false; } } getRoutes() { const allRoutes = {}; for (const [name, routes] of this.routes) { allRoutes[name] = routes; } return allRoutes; } async initializeAll(config) { const modules = [ { name: 'api', path: './routes/api.js' }, { name: 'auth', path: './routes/auth.js' }, { name: 'admin', path: './routes/admin.js' }, { name: 'static', path: './routes/static.js' } ]; for (const mod of modules) { if (config.modules[mod.name] !== false) { await this.load(mod.name, mod.path); } } } } // Scaffold Generator class ScaffoldGenerator { constructor() { this.templates = { page: ` {Name} | DeafFounders Hub

{Name}

This is the {name} page.

Visit Resource
`, route: `// {Name} Route Module import { Router } from './router.js'; export const routes = { '/api/{name}': { GET: (req, res) => { res.json({ success: true, data: [], message: '{Name} endpoint' }); }, POST: (req, res) => { res.json({ success: true, message: 'Created in {name}' }); } } }; export default routes;`, component: `// {Name} Component export class {Name}Component { constructor(selector) { this.element = document.querySelector(selector); this.init(); } init() { console.log('{Name} component initialized'); } render(data) { this.element.innerHTML = \\`

\\${data.title}

\\${data.content}

\\`; } } export default {Name}Component;` }; } generate(type, name, options = {}) { const timestamp = new Date().toISOString().split('T')[0]; const template = this.templates[type]; if (!template) { throw new Error(`Unknown template type: ${type}`); } let content = template .replace(/{Name}/g, name) .replace(/{name}/g, name.toLowerCase()) .replace(/{link}/g, options.link || '#') .replace(/{timestamp}/g, timestamp); const filename = type === 'page' ? `${name.toLowerCase()}.html` : type === 'route' ? `${name.toLowerCase()}.js` : `${name.toLowerCase()}.${type}.js`; const filepath = type === 'page' ? join(process.cwd(), 'public', filename) : type === 'route' ? join(process.cwd(), 'routes', filename) : join(process.cwd(), 'components', filename); const dir = dirname(filepath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } writeFileSync(filepath, content); console.log(`📝 Generated ${type}: ${filepath}`); return filepath; } async interactive() { console.log(` 🛠️ DeafFounders Hub Scaffold Generator ===================================== 1. Generate Page (HTML) 2. Generate API Route 3. Generate Component 4. Generate Full Module (Page + Route + Component) 5. Exit `); // For now, auto-generate essential pages this.generate('page', 'Dashboard', { link: '/admin' }); this.generate('page', 'Resources', { link: 'https://pinkycollie.github.io/Business-Magician/' }); this.generate('route', 'resources'); this.generate('component', 'ResourceCard'); console.log('✅ Essential scaffolds generated!'); } } // Request Router class Router { constructor(config, modules) { this.config = config; this.modules = modules; this.middleware = []; } use(middleware) { this.middleware.push(middleware); } async handle(req, res) { // Apply middleware for (const mw of this.middleware) { await mw(req, res); } const url = new URL(req.url, `http://${req.headers.host}`); const pathname = url.pathname; // Check redirects first if (this.config.redirects[pathname]) { res.writeHead(302, { Location: this.config.redirects[pathname] }); res.end(); return; } // Check module routes const allRoutes = this.modules.getRoutes(); for (const [moduleName, routes] of Object.entries(allRoutes)) { for (const [routePath, handlers] of Object.entries(routes)) { if (pathname === routePath || pathname.startsWith(routePath)) { const method = req.method; if (handlers[method]) { // Enhance response res.json = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); }; res.redirect = (url, code = 302) => { res.writeHead(code, { Location: url }); res.end(); }; await handlers[method](req, res); return; } } } } // Static file serving fallback this.serveStatic(pathname, res); } serveStatic(pathname, res) { const publicPath = join(__dirname, 'public'); let filePath = pathname === '/' ? join(publicPath, 'index.html') : join(publicPath, pathname); // Security check if (!filePath.startsWith(publicPath)) { res.writeHead(403); res.end('Forbidden'); return; } if (existsSync(filePath)) { const ext = extname(filePath); const mimeTypes = { '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon' }; const contentType = mimeTypes[ext] || 'application/octet-stream'; const content = readFileSync(filePath); res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': 'public, max-age=3600' }); res.end(content); } else { // Try to serve index.html for SPA routing const indexPath = join(publicPath, 'index.html'); if (existsSync(indexPath)) { const content = readFileSync(indexPath); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(content); } else { res.writeHead(404); res.end(JSON.stringify({ error: 'Not Found', path: pathname })); } } } } // CORS Middleware const corsMiddleware = (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } }; // Body Parser Middleware const bodyParser = async (req, res) => { if (req.method === 'POST' || req.method === 'PUT') { return new Promise((resolve) => { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { try { req.body = body ? JSON.parse(body) : {}; } catch { req.body = {}; } resolve(); }); }); } }; // Main Server class DeafFoundersServer { constructor() { this.configManager = new ConfigManager(); this.moduleLoader = new ModuleLoader(); this.scaffold = new ScaffoldGenerator(); this.router = null; } async initialize() { console.log('🚀 Initializing DeafFounders Hub Server...'); // Ensure directories exist ['routes', 'components', 'config', 'public', 'data'].forEach(dir => { const path = join(__dirname, dir); if (!existsSync(path)) { mkdirSync(path, { recursive: true }); console.log(`📁 Created directory: ${dir}`); } }); // Load modules await this.moduleLoader.initializeAll(this.configManager.get()); // Setup router this.router = new Router(this.configManager.get(), this.moduleLoader); this.router.use(corsMiddleware); this.router.use(bodyParser); console.log('✅ Server initialized successfully'); } start() { const config = this.configManager.get(); const server = createServer((req, res) => { this.router.handle(req, res).catch(err => { console.error('❌ Router error:', err); res.writeHead(500); res.end(JSON.stringify({ error: 'Internal Server Error' })); }); }); server.listen(config.port, () => { console.log(` 🎉 DeafFounders Hub Server Running ================================ Port: ${config.port} Mode: ${config.env} Admin: http://localhost:${config.port}/admin API: http://localhost:${config.port}/api Deno: Compatible ✓ `); }); return server; } async generateScaffolds() { await this.scaffold.interactive(); } } // CLI Commands const args = process.argv.slice(2); const server = new DeafFoundersServer(); if (args.includes('--generate') || args.includes('-g')) { server.generateScaffolds(); } else if (args.includes('--admin')) { // Open admin in browser const url = `http://localhost:${process.env.PORT || 3000}/admin`; console.log(`🌐 Opening admin at ${url}`); const open = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open'; spawn(open, [url]); } else { // Start server await server.initialize(); server.start(); } export { DeafFoundersServer, ConfigManager, ModuleLoader, ScaffoldGenerator };