π³ 20/02 - 14:09 - built in full built in NODE server with all necessary tools that can be fulfilled by DENO at large, and easy backoffice for api configuration and esnrue aall are update to modern,
1902db7 verified | /** | |
| * 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} Page --> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>{Name} | DeafFounders Hub</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
| body { font-family: 'Inter', sans-serif; } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50"> | |
| <!-- Navigation --> | |
| <nav class="bg-white shadow-lg sticky top-0 z-50"> | |
| <div class="max-w-7xl mx-auto px-4"> | |
| <div class="flex justify-between h-16"> | |
| <div class="flex items-center"> | |
| <a href="/" class="text-xl font-bold text-gray-900"> | |
| <i class="fas fa-hands-helping text-indigo-600 mr-2"></i> | |
| DeafFounders <span class="text-indigo-600">Hub</span> | |
| </a> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <a href="/" class="text-gray-700 hover:text-indigo-600">Home</a> | |
| <a href="https://pinkycollie.github.io/Business-Magician/" target="_blank" | |
| class="text-indigo-600 hover:text-indigo-800 border border-indigo-600 px-3 py-1 rounded"> | |
| Business Magician | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <main class="max-w-7xl mx-auto py-12 px-4"> | |
| <h1 class="text-4xl font-bold text-gray-900 mb-6">{Name}</h1> | |
| <p class="text-lg text-gray-600">This is the {name} page.</p> | |
| <a href="{link}" target="_blank" class="mt-4 inline-block bg-indigo-600 text-white px-6 py-3 rounded hover:bg-indigo-700 transition"> | |
| Visit Resource <i class="fas fa-external-link-alt ml-2"></i> | |
| </a> | |
| </main> | |
| </body> | |
| </html>`, | |
| 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 = \\` | |
| <div class="{name}-container"> | |
| <h2>\\${data.title}</h2> | |
| <p>\\${data.content}</p> | |
| </div> | |
| \\`; | |
| } | |
| } | |
| 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 }; |