#!/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 };