pinkycollie's picture
🐳 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
#!/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} 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 };