// ========================================== // ๐ฆ TITAN NEXUS SERVER v14.1 - TIME-AWARE ROYAL AI EDITION // ๐ก๏ธ SENTINEL MK2 ACTIVE | โก SOCKET.IO RELAY | ๐๏ธ ADMIN COMMAND CENTER // ๐ ROYAL IMMUNITY SYSTEM | ๐ง GEMMA 4 AI | ๐ฐ๏ธ TIME-AWARE ENGINE // ๐ AUTOMATED CONTENT GENERATION & ROYAL REPORTS // ๐งฉ ANTI-DUPLICATE RIDDLE SYSTEM (riddle_history collection) // ========================================== const admin = require("firebase-admin"); const express = require("express"); const helmet = require("helmet"); const cors = require("cors"); const natural = require("natural"); const http = require("http"); const { Server } = require("socket.io"); const os = require("os"); const cron = require("node-cron"); const { GoogleGenerativeAI } = require("@google/generative-ai"); const https = require("https"); const { pipeline } = require("stream"); const { promisify } = require("util"); const streamPipeline = promisify(pipeline); const initExtensions = require('./server-extensions'); // ๐ช Wallet + new admin endpoints // 1. CORE CONFIGURATION const app = express(); app.set('trust proxy', 2); const PORT = process.env.PORT || 7860; // ========================================== // ๐ ENVIRONMENT VARIABLES โ Hugging Face Secrets // Required secrets in HF Space settings: // FIREBASE_SERVICE_ACCOUNT โ full serviceAccountKey.json content (JSON string) // GEMINI_API_KEY โ Gemini API key // GROQ_API_KEY โ Groq API key // ADMIN_ID โ Firebase UID of the admin user // ========================================== // Validate all required secrets on startup const REQUIRED_ENV = ['FIREBASE_SERVICE_ACCOUNT', 'GEMINI_API_KEY', 'GROQ_API_KEY', 'ADMIN_ID', 'TITAN_GATEWAY_KEY', 'TITAN_RELAY_KEY']; const missingEnv = REQUIRED_ENV.filter(k => !process.env[k]); if (missingEnv.length > 0) { console.error(`\x1b[31m[FATAL] Missing required environment variables: ${missingEnv.join(', ')}\x1b[0m`); console.error('\x1b[31m[FATAL] Set them in Hugging Face Space โ Settings โ Repository secrets\x1b[0m'); process.exit(1); } // ๐ SECURITY & AUTHENTICATION let SERVICE_ACCOUNT; try { SERVICE_ACCOUNT = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT); } catch (e) { console.error('\x1b[31m[FATAL] FIREBASE_SERVICE_ACCOUNT is not valid JSON. Paste the full serviceAccountKey.json content.\x1b[0m'); process.exit(1); } const ADMIN_ID = process.env.ADMIN_ID; // ๐ ROYAL IMMUNITY SYSTEM const ROYAL_FAMILY = [ process.env.ADMIN_ID, "jcVOBGfUpkVnZOI8CQ0HRelRsed2" ]; // ๐ง GEMINI AI CONFIGURATION const GEMINI_API_KEY = process.env.GEMINI_API_KEY; const genAI = new GoogleGenerativeAI(GEMINI_API_KEY); const geminiModel = genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" }); // ๐ GROQ โ for news/stocks only const GROQ_API_KEY = process.env.GROQ_API_KEY; const GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"; const GROQ_MARKET_MODEL = "compound-beta"; // ๐ง EMAIL via Resend API (works on HF Spaces โ no SMTP blocking) // ๐ง EMAIL via Google Apps Script Mailer Bridge // HF Secrets required: MAILER_URL, MAILER_TOKEN const MAILER_URL = process.env.MAILER_URL; const MAILER_TOKEN = process.env.MAILER_TOKEN; async function sendTitanEmail(to, subject, htmlBody) { if (!MAILER_URL) throw new Error('MAILER_URL not set in HF Secrets'); if (!MAILER_TOKEN) throw new Error('MAILER_TOKEN not set in HF Secrets'); const toStr = Array.isArray(to) ? to.join(',') : to; const payload = JSON.stringify({ token: MAILER_TOKEN, to: toStr, subject, htmlBody }); // Google Apps Script redirects POST to GET โ use native https to handle this return new Promise((resolve, reject) => { const url = new URL(MAILER_URL); const options = { hostname: url.hostname, path: url.pathname + url.search, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } }; function makeRequest(reqOptions, body, redirectCount = 0) { if (redirectCount > 5) return reject(new Error('Too many redirects')); const req = https.request(reqOptions, (res) => { // Handle Google's redirect (302/301) if ((res.statusCode === 301 || res.statusCode === 302 || res.statusCode === 307) && res.headers.location) { const redirectUrl = new URL(res.headers.location); res.resume(); // drain response // Follow redirect โ for 302 use GET (standard behavior) const newOpts = { hostname: redirectUrl.hostname, path: redirectUrl.pathname + redirectUrl.search, method: res.statusCode === 307 ? reqOptions.method : 'GET', headers: { 'Content-Type': 'application/json' } }; return makeRequest(newOpts, res.statusCode === 307 ? body : null, redirectCount + 1); } let d = ''; res.on('data', c => d += c); res.on('end', () => { try { // Try JSON parse first const parsed = JSON.parse(d); if (parsed.status !== 'success') reject(new Error(parsed.message || 'Non-success status')); else resolve(parsed); } catch { // If we get HTML but status is 2xx, treat as success (Google sometimes returns HTML on success) if (res.statusCode >= 200 && res.statusCode < 300) { resolve({ status: 'success', note: 'HTML response treated as success' }); } else { reject(new Error(`Non-JSON response (${res.statusCode}): ${d.slice(0, 100)}`)); } } }); }); req.setTimeout(20000, () => { req.destroy(); reject(new Error('Mailer timeout')); }); req.on('error', reject); if (body) req.write(body); req.end(); } makeRequest(options, payload); }); } // Server start time for uptime calculation const SERVER_START_TIME = Date.now(); // 2. FIREBASE INIT if (!admin.apps.length) { admin.initializeApp({ credential: admin.credential.cert(SERVICE_ACCOUNT), databaseURL: `https://${SERVICE_ACCOUNT.project_id}.firebaseio.com` }); } const db = admin.firestore(); // 3. MIDDLEWARE (Security first) app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], fontSrc: ["'self'", "https://fonts.gstatic.com"], scriptSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:"], connectSrc: ["'self'"] } }, crossOriginEmbedderPolicy: false, hsts: { maxAge: 31536000, includeSubDomains: true } })); app.use(cors({ origin: true, credentials: true })); app.use(express.json({ limit: '30mb' })); app.use(express.urlencoded({ extended: true, limit: '30mb' })); // 4. HELPER: CONSOLE-ONLY LOGGING (no Firestore writes) async function logSys(mod, msg, type = 'info') { const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19); const colors = { info: '\x1b[36m', success: '\x1b[32m', warning: '\x1b[33m', error: '\x1b[31m', system: '\x1b[35m', cyber: '\x1b[34m', royal: '\x1b[95m', ai: '\x1b[96m' }; const reset = '\x1b[0m'; const color = colors[type] || colors.info; console.log(`${color}[${timestamp}] [${mod}]${reset} ${msg}`); } // ๐ UID MASKER โ hides Firebase UIDs in public logs (shows first 4 + last 4 chars) function maskUid(uid) { if (!uid || uid.length < 10) return '****'; return uid.substring(0, 4) + 'โขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข' + uid.substring(uid.length - 4); } // 5. SENTIMENT ANALYSIS async function analyzeSentiment(text) { try { const analyzer = new natural.SentimentAnalyzer('English', natural.PorterStemmer, 'afinn'); const tokenizer = new natural.WordTokenizer(); const tokens = tokenizer.tokenize(text); const sentiment = analyzer.getSentiment(tokens); return { score: sentiment, category: sentiment > 0.5 ? 'positive' : sentiment < -0.5 ? 'negative' : 'neutral', confidence: Math.abs(sentiment) }; } catch (e) { return { score: 0, category: 'neutral', confidence: 0 }; } } // 6. SENTINEL MK2 WITH ROYAL IMMUNITY class SentinelMK2 { constructor() { this.bannedPatterns = [ /hack(er|ing)?\s*guide/i, /crack\s*software/i, /bypass\s*security/i, /ddos\s*tool/i, /virus\s*generator/i, /credit\s*card\s*generator/i ]; this.suspiciousKeywords = ['password', 'login', 'admin', 'root', 'exploit', 'vulnerability']; this.userReputation = new Map(); this.reportPenalties = { 'spam': -5, 'harassment': -15, 'fake_identity': -10, 'fake identity': -10 }; } async analyzeComment(comment) { const analysis = { riskLevel: 'low', flags: [], action: 'none', confidence: 0 }; this.bannedPatterns.forEach(pattern => { if (pattern.test(comment.text)) { analysis.flags.push('banned_pattern'); analysis.riskLevel = 'critical'; analysis.confidence += 0.7; } }); const links = (comment.text.match(/https?:\/\/[^\s]+/g) || []).length; if (links > 2) { analysis.flags.push('excessive_links'); analysis.riskLevel = Math.max(analysis.riskLevel, 'high'); analysis.confidence += 0.3; } const sentiment = await analyzeSentiment(comment.text); if (sentiment.category === 'negative' && sentiment.confidence > 0.6) { analysis.flags.push('negative_sentiment'); analysis.riskLevel = Math.max(analysis.riskLevel, 'medium'); analysis.confidence += 0.2; } const userRep = this.userReputation.get(comment.userId) || 0; if (userRep < -5) { analysis.flags.push('low_reputation_user'); analysis.riskLevel = 'high'; analysis.confidence += 0.4; } if (analysis.riskLevel === 'critical') { analysis.action = 'delete_ban'; } else if (analysis.riskLevel === 'high') { analysis.action = 'delete_warn'; } else if (analysis.riskLevel === 'medium') { analysis.action = 'flag_review'; } return analysis; } async monitorComments() { logSys('SENTINEL_MK2', '๐ก๏ธ Advanced comment monitoring activated', 'system'); db.collectionGroup('comments').onSnapshot(async (snapshot) => { snapshot.docChanges().forEach(async (change) => { if (change.type === 'added') { const comment = change.doc.data(); const commentId = change.doc.id; // ๐ ROYAL IMMUNITY CHECK if (ROYAL_FAMILY.includes(comment.userId)) { logSys('SENTINEL_MK2', `๐ Royal user ${maskUid(comment.userId)} - Immunity shield active`, 'royal'); return; } if (comment.userId === ADMIN_ID) return; const analysis = await this.analyzeComment(comment); if (analysis.action !== 'none') { await this.handleViolation(comment, commentId, analysis); } await this.updateUserReputation(comment.userId, analysis); } }); }, (error) => { logSys('SENTINEL_MK2', `โ ๏ธ Listener Error (Backoff/Connection): ${error.message}`, 'error'); }); } async monitorReports() { logSys('SENTINEL_MK2', 'โ๏ธ Real-Time Report & Ban System activated', 'system'); db.collection('reports') .where('status', '==', 'pending') .onSnapshot(async (snapshot) => { snapshot.docChanges().forEach(async (change) => { if (change.type === 'added') { const report = change.doc.data(); const reportId = change.doc.id; // ๐ ROYAL IMMUNITY CHECK if (ROYAL_FAMILY.includes(report.reportedUserId)) { logSys('SENTINEL_MK2', `๐ Report rejected - Royal immunity for ${maskUid(report.reportedUserId)}`, 'royal'); await db.collection('reports').doc(reportId).update({ status: 'rejected', reviewedAt: admin.firestore.FieldValue.serverTimestamp(), rejection_reason: 'Immunity Shield - Royal Family member', processedBy: 'SENTINEL_MK2_ROYAL_GUARD' }); return; } await this.processReport(report, reportId); } }); }, (error) => { logSys('SENTINEL_MK2', `โ ๏ธ Report Listener Error (Backoff/Connection): ${error.message}`, 'error'); }); } async processReport(report, reportId) { try { logSys('SENTINEL_MK2', `โ๏ธ Processing report ${reportId} for user ${maskUid(report.reportedUserId)}`, 'info'); const reportType = (report.reason || report.type || 'spam').toLowerCase(); const penalty = this.reportPenalties[reportType] || -5; let reputation = this.userReputation.get(report.reportedUserId) || 100; reputation += penalty; this.userReputation.set(report.reportedUserId, reputation); await db.collection('user_reputation').doc(report.reportedUserId).set({ userId: report.reportedUserId, score: reputation, updatedAt: admin.firestore.FieldValue.serverTimestamp(), lastPenalty: { amount: penalty, reason: reportType, reportId } }, { merge: true }); logSys('SENTINEL_MK2', `๐ User ${maskUid(report.reportedUserId)} reputation: ${reputation} (${penalty} penalty)`, 'warning'); let aiVerdict = `Reputation updated: ${reputation} points`; let actionsTaken = []; if (reputation <= 50 && reputation > 0) { await db.collection('users').doc(report.reportedUserId).set({ isShadowBanned: true, shadowBanReason: `Low reputation (${reputation}) from report ${reportId}`, shadowBannedAt: admin.firestore.FieldValue.serverTimestamp() }, { merge: true }); aiVerdict = `SHADOW BAN applied. User reputation: ${reputation}`; actionsTaken.push('shadow_ban'); logSys('SENTINEL_MK2', `๐ค User ${maskUid(report.reportedUserId)} shadow banned (reputation: ${reputation})`, 'warning'); } if (reputation <= 0) { try { await admin.auth().revokeRefreshTokens(report.reportedUserId); await db.collection('users').doc(report.reportedUserId).set({ banned: true, bannedAt: admin.firestore.FieldValue.serverTimestamp(), banReason: `Automatic ban: Reputation dropped to ${reputation}`, bannedBy: 'SENTINEL_MK2_AUTOMOD', reportId }, { merge: true }); await db.collection('banned_users').doc(report.reportedUserId).set({ userId: report.reportedUserId, bannedAt: admin.firestore.FieldValue.serverTimestamp(), reason: 'automatic_ban_reputation', finalReputation: reputation, reportId, violations: [reportType] }); aiVerdict = `PERMABAN applied. Reputation dropped to ${reputation}. Firebase token revoked.`; actionsTaken.push('permaban', 'token_revoked'); logSys('SENTINEL_MK2', `๐จ PERMABAN user ${maskUid(report.reportedUserId)} (reputation: ${reputation})`, 'error'); } catch (authError) { logSys('SENTINEL_MK2', `Failed to revoke tokens for ${maskUid(report.reportedUserId)}: ${authError.message}`, 'error'); } } await db.collection('reports').doc(reportId).update({ status: 'reviewed', reviewedAt: admin.firestore.FieldValue.serverTimestamp(), ai_verdict: aiVerdict, actions_taken: actionsTaken, reputation_after: reputation, penalty_applied: penalty, processedBy: 'SENTINEL_MK2_AUTOMOD' }); logSys('SENTINEL_MK2', `โ Report ${reportId} processed. Verdict: ${aiVerdict}`, 'success'); } catch (error) { logSys('SENTINEL_MK2', `โ Failed to process report ${reportId}: ${error.message}`, 'error'); await db.collection('reports').doc(reportId).update({ status: 'error', error: error.message, processedAt: admin.firestore.FieldValue.serverTimestamp() }); } } async handleViolation(comment, commentId, analysis) { const commentRef = db.collection('comments').doc(commentId); switch (analysis.action) { case 'delete_ban': await commentRef.delete(); await db.collection('banned_users').doc(comment.userId).set({ userId: comment.userId, bannedAt: admin.firestore.FieldValue.serverTimestamp(), reason: 'automatic_ban', violation: analysis.flags.join(', '), commentPreview: comment.text.substring(0, 100) }); logSys('SENTINEL_MK2', `๐จ BANNED user ${maskUid(comment.userId)} for critical violation`, 'error'); break; case 'delete_warn': await commentRef.delete(); await db.collection('user_warnings').doc(`${comment.userId}_${Date.now()}`).set({ userId: comment.userId, warnedAt: admin.firestore.FieldValue.serverTimestamp(), reason: analysis.flags.join(', '), commentId, action: 'comment_deleted' }); logSys('SENTINEL_MK2', `โ ๏ธ Warned user ${maskUid(comment.userId)}`, 'warning'); break; case 'flag_review': await commentRef.update({ flagged: true, flagReason: analysis.flags.join(', ') }); logSys('SENTINEL_MK2', `๐ฉ Flagged comment for review`, 'warning'); break; } await db.collection('security_logs').add({ action: analysis.action, userId: comment.userId, commentId, analysis, timestamp: admin.firestore.FieldValue.serverTimestamp() }); } async updateUserReputation(userId, analysis) { let reputation = this.userReputation.get(userId) || 0; switch (analysis.action) { case 'delete_ban': reputation -= 10; break; case 'delete_warn': reputation -= 3; break; case 'flag_review': reputation -= 1; break; default: reputation += 1; } this.userReputation.set(userId, reputation); if (reputation < -5) { await db.collection('user_reputation').doc(userId).set({ userId, score: reputation, updatedAt: admin.firestore.FieldValue.serverTimestamp() }, { merge: true }); } } } // 7. JANITOR MK2 WITH ROYAL IMMUNITY class JanitorMK2 { constructor() { this.messageRetentionDays = 30; } async cleanOldMessages() { const cutoff = new Date(Date.now() - this.messageRetentionDays * 24 * 60 * 60 * 1000); try { const snapshot = await db.collection('titan_news') .where('timestamp', '<', cutoff) .get(); if (!snapshot.empty) { const batch = db.batch(); snapshot.docs.forEach(doc => { const data = doc.data(); // ๐ ROYAL IMMUNITY: Skip deletion if message is from royal family if (data.userId && ROYAL_FAMILY.includes(data.userId)) { logSys('JANITOR_MK2', `๐ Preserving royal message from ${maskUid(data.userId)}`, 'royal'); return; } batch.delete(doc.ref); }); await batch.commit(); logSys('JANITOR_MK2', `๐งน Deleted ${snapshot.size} old messages (older than ${this.messageRetentionDays} days)`, 'info'); } } catch (error) { logSys('JANITOR_MK2', `โ Cleanup error: ${error.message}`, 'error'); } } } // 8. ๐ฐ๏ธ TIME-AWARE AI CONTENT GENERATOR (v14.0 Engine) /** * Calculates the exact Gregorian date string (long format). */ function getGregorianDateString(date) { return date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } /** * Calculates the exact Hijri date string using the Umm al-Qura calendar * via the native Intl API โ no external libraries required. */ function getHijriDateString(date) { try { return new Intl.DateTimeFormat('en-US-u-ca-islamic-umalqura', { day: 'numeric', month: 'long', year: 'numeric' }).format(date); } catch (e) { // Fallback if the locale is not supported in this Node.js build return 'Hijri date unavailable'; } } /** * ๐งฉ DAILY RIDDLE GENERATOR (Lightweight & Interactive) * v14.1 โ Anti-duplicate system: tracks last 30 riddles in Firestore */ async function generateRiddleContent() { try { logSys('TIME_AWARE_AI', '๐งฉ Generating daily riddle...', 'ai'); const today = new Date(); const gregorianDate = getGregorianDateString(today); const hijriDate = getHijriDateString(today); // โ FIX: Fetch last 30 riddles to avoid repetition let recentRiddles = []; try { const recentSnap = await db.collection('riddle_history') .orderBy('timestamp', 'desc') .limit(30) .get(); recentRiddles = recentSnap.docs.map(d => d.data().riddleEn || ''); logSys('TIME_AWARE_AI', `๐ Loaded ${recentRiddles.length} past riddles for dedup check`, 'info'); } catch (e) { logSys('TIME_AWARE_AI', 'โ ๏ธ Could not load riddle history (continuing anyway)', 'warning'); } const avoidSection = recentRiddles.length > 0 ? `\n- DO NOT repeat or closely resemble any of these recent riddles:\n${recentRiddles.map((r, i) => ` ${i + 1}. "${r}"`).join('\n')}` : ''; const categories = ['nature', 'technology', 'food', 'animals', 'everyday objects', 'science', 'history', 'mathematics', 'human body', 'space']; const category = categories[Math.floor(Math.random() * categories.length)]; const prompt = `You are Titan Nexus AI. Create ONE original, clever riddle about "${category}". Rules: - Must be genuinely clever and creative โ not a common or well-known riddle - Suitable for all ages - Include the answer clearly at the end after " โ answer: " - Avoid ANY special characters that break JSON (no quotes, apostrophes inside strings) - Date context: ${gregorianDate} / ${hijriDate}${avoidSection} Reply with ONLY valid JSON, nothing else: {"riddle":{"en":"[Write a creative riddle about ${category}] โ answer: [the answer]","ar":"[ุงูุชุจ ูุฒูุฑุฉ ู ุจุชูุฑุฉ ุนู ${category}] โ ุงูุฅุฌุงุจุฉ: [ุงูุฌูุงุจ]"}}`.trim(); const result = await geminiModel.generateContent(prompt); const response = await result.response; let text = response.text().trim(); // Aggressively clean the response text = text .replace(/^```json\s*/i, '') .replace(/^```\s*/i, '') .replace(/```\s*$/i, '') // Normalize Arabic/smart quotes to standard ASCII quotes .replace(/[\u201C\u201D\u201E\u201F\u2033\u2036\u00AB\u00BB]/g, '"') .replace(/[\u2018\u2019\u201A\u201B\u2032\u2035]/g, "'") .trim(); // Find the outermost JSON object const start = text.indexOf('{'); const end = text.lastIndexOf('}'); if (start === -1 || end === -1) throw new Error(`No JSON object found in: ${text.substring(0, 120)}`); let jsonStr = text.slice(start, end + 1).replace(/[\x00-\x1F\x7F]/g, ' '); let content; try { content = JSON.parse(jsonStr); } catch (pe) { const enM = jsonStr.match(/"en"\s*:\s*"((?:[^"\\]|\\.)*)"/); const arM = jsonStr.match(/"ar"\s*:\s*"((?:[^"\\]|\\.)*)"/); if (enM && arM) content = { riddle: { en: enM[1], ar: arM[1] } }; else throw new Error(`JSON parse failed: ${pe.message}`); } if (!content.riddle || !content.riddle.en || !content.riddle.ar) { throw new Error('Invalid riddle format from AI'); } // โ FIX: Save new riddle to history to prevent future duplicates try { await db.collection('riddle_history').add({ riddleEn: content.riddle.en, riddleAr: content.riddle.ar, timestamp: admin.firestore.FieldValue.serverTimestamp(), gregorianDate, hijriDate }); logSys('TIME_AWARE_AI', `๐พ Riddle saved to history`, 'info'); } catch (e) { logSys('TIME_AWARE_AI', 'โ ๏ธ Could not save riddle to history', 'warning'); } logSys('TIME_AWARE_AI', `โ Riddle generated successfully.`, 'success'); return content; } catch (error) { logSys('TIME_AWARE_AI', `โ Riddle generation failed: ${error.message}`, 'error'); // โ FIX: Fallback pool of 10 varied riddles instead of 1 hardcoded const fallbackRiddles = [ { en: "I have cities, but no houses. Mountains, but no trees. Water, but no fish. What am I? (A map)", ar: "ูุฏู ู ุฏู ุจูุง ู ูุงุฒูุ ูุฌุจุงู ุจูุง ุฃุดุฌุงุฑุ ูู ูุงู ุจูุง ุฃุณู ุงู. ู ู ุฃูุงุ (ุงูุฎุฑูุทุฉ)" }, { en: "The more you take, the more you leave behind. What am I? (Footsteps)", ar: "ููู ุง ุฃุฎุฐุช ู ูู ุงุฒุฏุฏุช. ู ุง ุฃูุงุ (ุงูุฎุทูุงุช)" }, { en: "I speak without a mouth and hear without ears. I have no body, but I come alive with wind. What am I? (An echo)", ar: "ุฃุชููู ุจูุง ูู ูุฃุณู ุน ุจูุง ุฃุฐููู. ู ุง ุฃูุงุ (ุงูุตุฏู)" }, { en: "I can fly without wings. I can cry without eyes. Wherever I go, darkness flies. What am I? (A cloud)", ar: "ุฃุทูุฑ ุจูุง ุฃุฌูุญุฉ ูุฃุจูู ุจูุง ุนููู. ู ุง ุฃูุงุ (ุงูุณุญุงุจุฉ)" }, { en: "I run, but I have no legs. I have a mouth, but I never talk. What am I? (A river)", ar: "ุฃุฌุฑู ููุง ุฃู ูู ูุฏู ููุ ููุฏู ูู ููููู ูุง ุฃุชููู . ู ุง ุฃูุงุ (ุงูููุฑ)" }, { en: "What has hands but cannot clap? (A clock)", ar: "ู ุง ุงูุฐู ูู ูุฏุงู ููู ูุง ูุตููุ (ุงูุณุงุนุฉ)" }, { en: "I get shorter as I grow older. What am I? (A candle)", ar: "ุฃุตูุฑ ุฃูุตุฑ ููู ุง ูุจุฑุช. ู ุง ุฃูุงุ (ุงูุดู ุนุฉ)" }, { en: "I have a neck but no head, and I wear a cap. What am I? (A bottle)", ar: "ูุฏู ุนูู ุจูุง ุฑุฃุณ ูุฃุฑุชุฏู ุบุทุงุกู. ู ุง ุฃูุงุ (ุงูุฒุฌุงุฌุฉ)" }, { en: "What can you catch but not throw? (A cold)", ar: "ู ุงุฐุง ูู ููู ุฃู ุชูุชูุท ููู ูุง ุชุฑู ูุ (ูุฒูุฉ ุงูุจุฑุฏ)" }, { en: "I have teeth but cannot eat. What am I? (A comb)", ar: "ูุฏู ุฃุณูุงู ููููู ูุง ุขูู. ู ุง ุฃูุงุ (ุงูู ุดุท)" } ]; const pick = fallbackRiddles[Math.floor(Math.random() * fallbackRiddles.length)]; return { riddle: pick }; } } // 9. ROYAL REPORT GENERATOR async function generateRoyalReport(stats) { try { logSys('GEMINI_AI', '๐ Generating royal report...', 'ai'); const prompt = `You are generating a professional daily report for the administrators of Titan Nexus platform. Server Statistics: - Uptime: ${stats.uptime} - Memory Usage: ${stats.memory.percentage} - Online Users: ${stats.connections.registered} - Total Connections: ${stats.connections.total} - Platform: ${stats.platform} - Sentinel Status: ${stats.sentinel} Generate a concise, professional summary report. Respond ONLY with valid JSON โ no markdown, no backticks, no extra text. Required format: {"en":"English summary (2-3 sentences, professional tone)","ar":"ู ูุฎุต ุจุงูุนุฑุจูุฉ"} Make it sound like a human executive summary, not a robot report.`; const result = await geminiModel.generateContent(prompt); const response = await result.response; let text = response.text().trim(); text = text .replace(/```json\s*/gi, '').replace(/```\s*/gi, '') .replace(/[\u201C\u201D\u201E\u201F\u2033\u2036\u00AB\u00BB]/g, '"') .replace(/[\u2018\u2019\u201A\u201B\u2032\u2035]/g, "'") .trim(); const start = text.indexOf('{'); const end = text.lastIndexOf('}'); if (start === -1 || end === -1) throw new Error('No JSON object found in AI response'); let rJson = text.slice(start, end + 1).replace(/[\x00-\x1F\x7F]/g, ' '); let report; try { report = JSON.parse(rJson); } catch (pe) { const enM = rJson.match(/"en"\s*:\s*"((?:[^"\\]|\\.)*)"/); const arM = rJson.match(/"ar"\s*:\s*"((?:[^"\\]|\\.)*)"/); if (enM && arM) report = { en: enM[1], ar: arM[1] }; else throw new Error(`Parse failed: ${pe.message}`); } if (!report.en || !report.ar) throw new Error('Missing en/ar fields in report'); logSys('GEMINI_AI', 'โ Royal report generated successfully', 'success'); return report; } catch (error) { logSys('GEMINI_AI', `โ Failed to generate royal report: ${error.message}`, 'error'); return { en: `Daily Report: Server uptime ${stats.uptime}. ${stats.connections.registered} users online. All systems operational.`, ar: `ุชูุฑูุฑ ููู ู: ููุช ุชุดุบูู ุงูุฎุงุฏู ${stats.uptime}. ${stats.connections.registered} ู ุณุชุฎุฏู ู ุชุตู. ุฌู ูุน ุงูุฃูุธู ุฉ ุชุนู ู.` }; } } // ========================================== // ๐ MARKET INTELLIGENCE ENGINE v2 (Split Requests) // Request 1: Gold + FX | Request 2: Stocks + Oil + BTC // ========================================== async function groqFetch(userPrompt, maxTokens = 150) { const body = JSON.stringify({ model: GROQ_MARKET_MODEL, messages: [{ role: "user", content: userPrompt }], temperature: 0.1, max_tokens: maxTokens }); return new Promise((resolve, reject) => { const url = new URL(GROQ_API_URL); const req = https.request({ hostname: url.hostname, path: url.pathname, method: 'POST', headers: { 'Authorization': `Bearer ${GROQ_API_KEY}`, 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } }, (res) => { let d = ''; res.on('data', c => d += c); res.on('end', () => res.statusCode >= 200 && res.statusCode < 300 ? resolve(d) : reject(new Error(`${res.statusCode}: ${d.slice(0, 200)}`))); }); req.setTimeout(40000, () => { req.destroy(); reject(new Error('Timeout')); }); req.on('error', reject); req.write(body); req.end(); }); } function parseJSON(raw) { const parsed = JSON.parse(raw); let text = (parsed.choices?.[0]?.message?.content || '') .replace(/```json\s*/gi, '').replace(/```\s*/gi, '') .replace(/[\u201C\u201D\u00AB\u00BB]/g, '"') .replace(/[\x00-\x1F\x7F]/g, ' ').trim(); const s = text.indexOf('{'), e = text.lastIndexOf('}'); if (s === -1 || e === -1) throw new Error('No JSON'); return JSON.parse(text.slice(s, e + 1)); } async function fetchMarketData() { logSys('MARKET_AI', '๐ก Fetching market data...', 'ai'); const ozToGram = 0.0321507; let goldUsdOz = 0, usdEgp = 50.9, eurEgp = 55.0, gbpEgp = 64.0, sarEgp = 13.6; let stocks = {}; // โโ Step 1: Exchange rates โโ try { const raw = await new Promise((resolve, reject) => { const req = https.request({ hostname: 'open.er-api.com', path: '/v6/latest/USD', method: 'GET' }, (res) => { let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d)); }); req.setTimeout(8000, () => { req.destroy(); reject(new Error('Timeout')); }); req.on('error', reject); req.end(); }); const fx = JSON.parse(raw); if (fx.rates?.EGP) { usdEgp = fx.rates.EGP; eurEgp = usdEgp / fx.rates.EUR; gbpEgp = usdEgp / fx.rates.GBP; sarEgp = usdEgp / fx.rates.SAR; logSys('MARKET_AI', `โ FX: 1 USD = ${usdEgp.toFixed(2)} EGP`, 'success'); } } catch (e) { logSys('MARKET_AI', `โ ๏ธ FX: ${e.message.slice(0,50)}`, 'warning'); } // โโ Step 2: Gold spot โ try multiple free APIs โโ const goldAPIs = [ { host: 'api.gold-api.com', path: '/price/XAU' }, { host: 'api.metals.live', path: '/v1/spot/gold' }, { host: 'data.fixer.io', path: '/api/latest?access_key=free&symbols=XAU,USD' }, ]; for (const api of goldAPIs) { if (goldUsdOz > 0) break; try { const raw = await new Promise((resolve, reject) => { const req = https.request({ hostname: api.host, path: api.path, method: 'GET' }, (res) => { let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(d)); }); req.setTimeout(7000, () => { req.destroy(); reject(new Error('Timeout')); }); req.on('error', reject); req.end(); }); const g = JSON.parse(raw); // Handle different API response formats const candidate = parseFloat( g.price || g.gold || g.XAU || (g.rates?.XAU ? 1 / g.rates.XAU : 0) || (Array.isArray(g) ? (g[0]?.price || Object.values(g[0])[0]) : 0) ) || 0; if (candidate > 1000 && candidate < 10000) { // sanity check: gold is between $1000-$10000/oz goldUsdOz = candidate; logSys('MARKET_AI', `โ Gold spot: $${goldUsdOz.toFixed(2)}/oz (${api.host})`, 'success'); } } catch (e) { logSys('MARKET_AI', `โ ๏ธ Gold API ${api.host}: ${e.message.slice(0,40)}`, 'warning'); } } // โโ Step 3: Stocks via Groq llama (no web search = no 413) โโ try { const body = JSON.stringify({ model: 'llama-3.3-70b-versatile', messages: [{ role: 'user', content: 'Give approximate current market values: S&P500 index, NASDAQ composite, Dow Jones, EGX30 Egypt stock exchange, Bitcoin USD price, Brent crude oil USD/barrel. Reply JSON only: {"sp":"","nq":"","dj":"","eg":"","bt":"","br":""}' }], temperature: 0.1, max_tokens: 100 }); const raw = await new Promise((resolve, reject) => { const url = new URL(GROQ_API_URL); const req = https.request({ hostname: url.hostname, path: url.pathname, method: 'POST', headers: { 'Authorization': `Bearer ${GROQ_API_KEY}`, 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } }, (res) => { let d = ''; res.on('data', c => d += c); res.on('end', () => res.statusCode < 300 ? resolve(d) : reject(new Error(`${res.statusCode}: ${d.slice(0,100)}`))); }); req.setTimeout(15000, () => { req.destroy(); reject(new Error('Timeout')); }); req.on('error', reject); req.write(body); req.end(); }); stocks = parseJSON(raw); logSys('MARKET_AI', `โ Stocks: SP500=${stocks.sp} BTC=${stocks.bt}`, 'success'); } catch (e) { logSys('MARKET_AI', `โ ๏ธ Stocks: ${e.message.slice(0,80)}`, 'warning'); } // โโ Calculate gold prices โโ // Egypt local market: ~6-8% premium over international price const localPremium = 1.07; const g24Egp = goldUsdOz ? Math.round(goldUsdOz * usdEgp * ozToGram * localPremium) : 0; const g21Egp = g24Egp ? Math.round(g24Egp * 21 / 24) : 0; const g18Egp = g24Egp ? Math.round(g24Egp * 18 / 24) : 0; const g21Sar = goldUsdOz ? Math.round(goldUsdOz * 3.75 * ozToGram * 21 / 24) : 0; const g24Aed = goldUsdOz ? Math.round(goldUsdOz * 3.674 * ozToGram) : 0; return { gold: { egypt_21k: g21Egp ? g21Egp.toString() : 'N/A', egypt_24k: g24Egp ? g24Egp.toString() : 'N/A', egypt_18k: g18Egp ? g18Egp.toString() : 'N/A', global_usd_oz: goldUsdOz ? goldUsdOz.toFixed(2) : 'N/A', saudi_21k: g21Sar ? g21Sar.toString() : 'N/A', uae_24k: g24Aed ? g24Aed.toString() : 'N/A', trend: 'stable', change_pct: 'N/A' }, markets: { sp500: { v: stocks.sp || 'N/A', c: 'N/A', t: 'โก๏ธ' }, nasdaq: { v: stocks.nq || 'N/A', c: 'N/A', t: 'โก๏ธ' }, dow: { v: stocks.dj || 'N/A', c: 'N/A', t: 'โก๏ธ' }, egx30: { v: stocks.eg || 'N/A', c: 'N/A', t: 'โก๏ธ' }, brent: { v: stocks.br || 'N/A', c: 'N/A', t: 'โก๏ธ' }, btc: { v: stocks.bt || 'N/A', c: 'N/A', t: 'โก๏ธ' } }, fx: { usd_egp: usdEgp.toFixed(2), eur_egp: eurEgp.toFixed(2), gbp_egp: gbpEgp.toFixed(2), sar_egp: sarEgp.toFixed(2) }, summary: { en: 'Market data updated.', ar: 'ุชู ุชุญุฏูุซ ุจูุงูุงุช ุงูุณูู.' } }; } // ========================================== // ๐ PRAYER TIMES NOTIFICATION (Cairo, Egypt) // ========================================== async function broadcastPrayerTimes() { try { const today = new Date(); const day = today.getDate(), month = today.getMonth() + 1, year = today.getFullYear(); // Aladhan API - free, no key needed const prayerData = await new Promise((resolve, reject) => { const req = https.request({ hostname: 'api.aladhan.com', path: `/v1/timingsByCity/${day}-${month}-${year}?city=Cairo&country=Egypt&method=5`, method: 'GET' }, (res) => { let d = ''; res.on('data', c => d += c); res.on('end', () => resolve(JSON.parse(d))); }); req.setTimeout(10000, () => { req.destroy(); reject(new Error('Timeout')); }); req.on('error', reject); req.end(); }); const t = prayerData.data?.timings; if (!t) throw new Error('No timings data'); const dateStr = getGregorianDateString(today); const hijriStr = getHijriDateString(today); const body = `๐ ู ูุงููุช ุงูุตูุงุฉ โ ุงููุงูุฑุฉ ๐ ${dateStr} | ๐ ${hijriStr} โโโโโโโโโโโโโโโโโโโโ ๐ ุงููุฌุฑ: ${t.Fajr} ๐ ุงูุดุฑูู: ${t.Sunrise} โ๏ธ ุงูุธูุฑ: ${t.Dhuhr} ๐ค๏ธ ุงูุนุตุฑ: ${t.Asr} ๐ ุงูู ุบุฑุจ: ${t.Maghrib} ๐ ุงูุนุดุงุก: ${t.Isha} โโโโโโโโโโโโโโโโโโโโ ุชูุจู ุงููู ุทุงุนุชูู ๐คฒ`; await db.collection('notifications').add({ title: `๐ ู ูุงููุช ุงูุตูุงุฉ โ ${dateStr}`, body, type: 'PRAYER_TIMES', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); io.emit('prayer_times', { title: `๐ ู ูุงููุช ุงูุตูุงุฉ`, body, timings: t }); logSys('PRAYER', 'โ Prayer times broadcast sent', 'success'); } catch (e) { logSys('PRAYER', `โ Prayer times failed: ${e.message}`, 'error'); } } // ========================================== // ๐ก DAILY QUOTE / MOTIVATION (Gemini) // ========================================== async function broadcastDailyQuote() { try { const today = new Date(); const dateStr = getGregorianDateString(today); const hijriStr = getHijriDateString(today); const hour = today.getHours(); const period = hour < 12 ? 'ุตุจุงุญูุฉ' : 'ู ุณุงุฆูุฉ'; const result = await geminiModel.generateContent( `ุงูุชุจ ุชุญูุฉ ${period} ุฌู ููุฉ ูุญูู ุฉ ุฅุณูุงู ูุฉ ู ููู ุฉ. ุฃุฌุจ ุจู JSON ููุท (ุจุฏูู ุฃู ูุต ุฎุงุฑุฌู): {"g":"[ุงูุชุจ ุงูุชุญูุฉ ููุง]","q":"[ุงูุชุจ ุงูุญูู ุฉ ููุง]","s":"[ุงูุชุจ ุงูู ุตุฏุฑ ููุง]"}` ); let text = result.response.text().trim() .replace(/```json\s*/gi, '').replace(/```\s*/gi, '') .replace(/[\u201C\u201D\u00AB\u00BB]/g, '"') .replace(/[\x00-\x1F\x7F]/g, ' '); const s = text.indexOf('{'), e = text.lastIndexOf('}'); if (s === -1) throw new Error('No JSON'); let q; try { q = JSON.parse(text.slice(s, e + 1)); } catch (pe) { // Regex fallback const gM = text.match(/"g"\s*:\s*"((?:[^"\\]|\\.)*)"/); const qM = text.match(/"q"\s*:\s*"((?:[^"\\]|\\.)*)"/); const sM = text.match(/"s"\s*:\s*"((?:[^"\\]|\\.)*)"/); q = { g: gM?.[1] || '', q: qM?.[1] || '', s: sM?.[1] || '' }; } const icon = hour < 12 ? '๐ ' : '๐'; const title = hour < 12 ? '๐ ุตุจุงุญ ุงูุฎูุฑ' : '๐ ู ุณุงุก ุงูุฎูุฑ'; const body = `${icon} ${q.g || ''}\n\nโจ "${q.q || ''}"\nโ ${q.s || ''}\n\n๐ ${dateStr} | ๐ ${hijriStr}`; await db.collection('notifications').add({ title, body, type: 'DAILY_QUOTE', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); io.emit('daily_quote', { title, body }); logSys('QUOTE', 'โ Daily quote broadcast sent', 'success'); } catch (e) { logSys('QUOTE', `โ Daily quote failed: ${e.message}`, 'error'); } } // ========================================== // ๐ฐ ARABIC NEWS SUMMARY (Groq) // ========================================== async function broadcastArabicNews() { try { const dateStr = getGregorianDateString(new Date()); // Very short prompt to avoid 413 const raw = await groqFetch( `Top 3 Arab world news today. JSON: {"n":[{"t":"headline","s":"summary"},{"t":"","s":""},{"t":"","s":""}]}`, 250 ); const parsed = parseJSON(raw); const news = parsed.n || parsed.news || []; if (!news.length) throw new Error('No news items'); const icons = ['1๏ธโฃ','2๏ธโฃ','3๏ธโฃ']; const body = `๐ฐ ุฃุจุฑุฒ ุงูุฃุฎุจุงุฑ โ ${dateStr}\nโโโโโโโโโโโโโโโโโโโโ\n` + news.slice(0, 3).map((n, i) => `${icons[i]} ${n.t || n.title || ''}\n ${n.s || n.summary || ''}`).join('\n\n') + '\nโโโโโโโโโโโโโโโโโโโโ\nTitan Nexus News'; await db.collection('notifications').add({ title: `๐ฐ ุฃุฎุจุงุฑ ุงูููู โ ${dateStr}`, body, type: 'NEWS_SUMMARY', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); io.emit('news_update', { title: `๐ฐ ุฃุฎุจุงุฑ ุงูููู `, body }); logSys('NEWS', 'โ Arabic news broadcast sent', 'success'); } catch (e) { logSys('NEWS', `โ News broadcast failed: ${e.message}`, 'error'); } } function formatMarketNotification(data, dateStr, hijriStr, timeStr) { const g = data.gold || {}; const m = data.markets || {}; const c = data.fx || {}; const ti = (t) => t === 'up' ? '๐' : t === 'down' ? '๐' : 'โก๏ธ'; const mRow = (label, obj) => `${label}: ${obj?.v || 'N/A'}`; const bodyEn = ` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๐ TITAN NEXUS MARKET REPORT โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ ${dateStr} ๐ ${hijriStr} โฐ ${timeStr} ๐ฅ โโ GOLD PRICES โโ ๐ช๐ฌ Egypt 21K โบ ${g.egypt_21k || 'N/A'} EGP/g ๐ช๐ฌ Egypt 24K โบ ${g.egypt_24k || 'N/A'} EGP/g ๐ช๐ฌ Egypt 18K โบ ${g.egypt_18k || 'N/A'} EGP/g ๐ Global โบ $${g.global_usd_oz || 'N/A'} USD/oz ๐ธ๐ฆ Saudi 21K โบ ${g.saudi_21k || 'N/A'} SAR/g ๐ฆ๐ช UAE 24K โบ ${g.uae_24k || 'N/A'} AED/g ๐ โโ GLOBAL MARKETS โโ ๐บ๐ธ S&P 500 โบ ${m.sp500?.v || 'N/A'} ๐บ๐ธ NASDAQ โบ ${m.nasdaq?.v || 'N/A'} ๐บ๐ธ Dow Jones โบ ${m.dow?.v || 'N/A'} ๐ช๐ฌ EGX 30 โบ ${m.egx30?.v || 'N/A'} ๐ข๏ธ Brent Oil โบ ${m.brent?.v || 'N/A'} USD/bbl โฟ Bitcoin โบ $${m.btc?.v || 'N/A'} ๐ฑ โโ EXCHANGE RATES โโ ๐ต USD โบ ${c.usd_egp || 'N/A'} EGP ๐ถ EUR โบ ${c.eur_egp || 'N/A'} EGP ๐ท GBP โบ ${c.gbp_egp || 'N/A'} EGP ๐ธ๐ฆ SAR โบ ${c.sar_egp || 'N/A'} EGP โก Titan Nexus Market Intelligence `.trim(); const bodyAr = ` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๐ ุชูุฑูุฑ ุงูุณูู ุงูููู ู โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐ ${dateStr} ๐ ${hijriStr} โฐ ${timeStr} ๐ฅ โโ ุฃุณุนุงุฑ ุงูุฐูุจ โโ ๐ช๐ฌ ู ุตุฑ ุนูุงุฑ 21 โบ ${g.egypt_21k || 'N/A'} ุฌููู/ุฌุฑุงู ๐ช๐ฌ ู ุตุฑ ุนูุงุฑ 24 โบ ${g.egypt_24k || 'N/A'} ุฌููู/ุฌุฑุงู ๐ช๐ฌ ู ุตุฑ ุนูุงุฑ 18 โบ ${g.egypt_18k || 'N/A'} ุฌููู/ุฌุฑุงู ๐ ุนุงูู ู โบ $${g.global_usd_oz || 'N/A'} ุฏููุงุฑ/ุฃูููุฉ ๐ธ๐ฆ ุงูุณุนูุฏูุฉ 21 โบ ${g.saudi_21k || 'N/A'} ุฑูุงู/ุฌุฑุงู ๐ฆ๐ช ุงูุฅู ุงุฑุงุช 24 โบ ${g.uae_24k || 'N/A'} ุฏุฑูู /ุฌุฑุงู ๐ โโ ุงูุฃุณูุงู ุงูุนุงูู ูุฉ โโ ๐บ๐ธ S&P 500 โบ ${m.sp500?.v || 'N/A'} ๐บ๐ธ NASDAQ โบ ${m.nasdaq?.v || 'N/A'} ๐บ๐ธ ุฏุงู ุฌููุฒ โบ ${m.dow?.v || 'N/A'} ๐ช๐ฌ EGX 30 โบ ${m.egx30?.v || 'N/A'} ๐ข๏ธ ุจุฑูุช โบ ${m.brent?.v || 'N/A'} ุฏููุงุฑ/ุจุฑู ูู โฟ ุจูุชูููู โบ $${m.btc?.v || 'N/A'} ๐ฑ โโ ุฃุณุนุงุฑ ุงูุตุฑู โโ ๐ต ุฏููุงุฑ โบ ${c.usd_egp || 'N/A'} ุฌููู ๐ถ ููุฑู โบ ${c.eur_egp || 'N/A'} ุฌููู ๐ท ุฅุณุชุฑูููู โบ ${c.gbp_egp || 'N/A'} ุฌููู ๐ธ๐ฆ ุฑูุงู โบ ${c.sar_egp || 'N/A'} ุฌููู โก Titan Nexus Market Intelligence `.trim(); return { bodyEn, bodyAr }; } /** * Main function: fetch + format + broadcast market notification */ async function broadcastMarketUpdate() { logSys('MARKET_AI', '๐ Starting morning market broadcast...', 'system'); const today = new Date(); const dateStr = getGregorianDateString(today); const hijriStr = getHijriDateString(today); const timeStr = today.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: true }); // Retry up to 3 times on failure, respecting 429 retry-after let data = null; for (let attempt = 1; attempt <= 3; attempt++) { data = await fetchMarketData(); if (data) break; if (attempt < 3) { // On 429 rate limit, wait longer (30s), otherwise 10s const waitMs = attempt === 1 ? 30000 : 60000; logSys('MARKET_AI', `โณ Waiting ${waitMs/1000}s before retry ${attempt + 1}...`, 'warning'); await new Promise(r => setTimeout(r, waitMs)); } } if (!data) { logSys('MARKET_AI', 'โ All attempts failed. Skipping market broadcast.', 'error'); return; } const { bodyEn, bodyAr } = formatMarketNotification(data, dateStr, hijriStr, timeStr); // Save to Firestore as broadcast notification await db.collection('notifications').add({ title: `๐ ุชูุฑูุฑ ุงูุณูู ุงูููู ู โ ${dateStr}`, titleEn: `๐ Daily Market Report โ ${dateStr}`, body: bodyEn, bodyAr: bodyAr, type: 'MARKET_REPORT', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false, marketData: data, meta: { gregorianDate: dateStr, hijriDate: hijriStr, fetchedAt: timeStr, engine: 'GROQ_COMPOUND_MARKET_v1' } }); // Real-time push via Socket.IO to all connected clients io.emit('market_update', { title: `๐ Daily Market Report โ ${dateStr}`, bodyEn, bodyAr, marketData: data, timestamp: new Date().toISOString() }); logSys('MARKET_AI', `โ Market report broadcast to ${io.sockets.sockets.size} connections`, 'success'); } // 10. ๐ CRON JOBS (v14.0 โ Lightweight Riddle Edition) function initCronJobs() { // โณ Every 6 hours โ Send a riddle only (lightweight, interactive) cron.schedule('0 */6 * * *', async () => { logSys('CRON', 'โณ 6-Hour cycle triggered โ Generating daily riddle...', 'system'); try { const content = await generateRiddleContent(); const riddleEn = content.riddle.en; const riddleAr = content.riddle.ar; // Save to Firestore notifications collection await db.collection('notifications').add({ title: `๐งฉ ูุฒูุฑุฉ Titan Nexus ุงูููู ูุฉ`, body: riddleEn, bodyAr: riddleAr, type: 'DAILY_RIDDLE', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false, meta: { gregorianDate: getGregorianDateString(new Date()), hijriDate: getHijriDateString(new Date()), engine: 'TIME_AWARE_v14_RIDDLE' } }); logSys('CRON', `โ Daily riddle broadcast sent.`, 'success'); } catch (error) { logSys('CRON', `โ 6-Hour riddle broadcast failed: ${error.message}`, 'error'); } }); // ๐ Night Royal Report (11:59 PM daily) cron.schedule('59 23 * * *', async () => { logSys('CRON', '๐ Royal report generation initiated', 'system'); try { const stats = getServerStats(); const report = await generateRoyalReport(stats); // Send to each royal family member for (const royalId of ROYAL_FAMILY) { await db.collection('notifications').add({ title: '๐ Daily Royal Report', body: report.en, bodyAr: report.ar, type: 'ROYAL_REPORT', userId: royalId, timestamp: admin.firestore.FieldValue.serverTimestamp(), stats: stats }); logSys('CRON', `๐ Royal report sent to ${royalId}`, 'royal'); } logSys('CRON', 'โ Royal reports sent to all family members', 'success'); } catch (error) { logSys('CRON', `โ Royal report failed: ${error.message}`, 'error'); } }); logSys('CRON', '๐ Automated schedules initialized (6h riddle + 11:59 PM royal report)', 'success'); // ๐ Morning Market Report โ 8:00 AM cron.schedule('0 8 * * *', async () => { logSys('CRON', '๐ Morning market broadcast triggered (08:00)', 'system'); try { await broadcastMarketUpdate(); } catch (e) { logSys('CRON', `โ Market: ${e.message}`, 'error'); } }); // ๐ Afternoon Market Update โ 3:00 PM cron.schedule('0 15 * * *', async () => { logSys('CRON', '๐ Afternoon market update triggered (15:00)', 'system'); try { await broadcastMarketUpdate(); } catch (e) { logSys('CRON', `โ Market: ${e.message}`, 'error'); } }); // ๐ Prayer Times โ 1:00 AM Cairo time (UTC+2) = 23:00 UTC previous day // If server runs on UTC: use '0 23 * * *' // If server runs on Cairo time: use '0 1 * * *' cron.schedule('0 1 * * *', async () => { logSys('CRON', '๐ Prayer times broadcast triggered (01:00 Cairo)', 'system'); try { await broadcastPrayerTimes(); } catch (e) { logSys('CRON', `โ Prayer: ${e.message}`, 'error'); } }); // ๐ Morning Quote โ Every day at 7:00 AM cron.schedule('0 7 * * *', async () => { logSys('CRON', '๐ก Morning quote triggered (07:00)', 'system'); try { await broadcastDailyQuote(); } catch (e) { logSys('CRON', `โ Quote: ${e.message}`, 'error'); } }); // ๐ Evening Quote โ Every day at 6:00 PM cron.schedule('0 18 * * *', async () => { logSys('CRON', '๐ก Evening quote triggered (18:00)', 'system'); try { await broadcastDailyQuote(); } catch (e) { logSys('CRON', `โ Quote: ${e.message}`, 'error'); } }); // ๐ฐ Arabic News โ Every day at 10:00 AM cron.schedule('0 10 * * *', async () => { logSys('CRON', '๐ฐ Arabic news broadcast triggered (10:00)', 'system'); try { await broadcastArabicNews(); } catch (e) { logSys('CRON', `โ News: ${e.message}`, 'error'); } }); } // ๐ GAME MASTER โ Titan Gravity Top Players (Daily at 10:00 PM) cron.schedule('0 22 * * *', async () => { logSys('GAME_MASTER', '๐ Calculating Titan Gravity top players...', 'system'); try { const snapshot = await db.collection('titan_ghosts') .orderBy('arcade_points', 'desc') .limit(3) .get(); if (snapshot.empty) { logSys('GAME_MASTER', 'โ ๏ธ No players found in rankings.', 'warning'); return; } const medals = ['๐ฅ', '๐ฅ', '๐ฅ']; const titles = ['ุณูุฏ ุงูุฌุงุฐุจูุฉ (ุงูู ุฑูุฒ ุงูุฃูู)', 'ุงููุตูู (ุงูู ุฑูุฒ ุงูุซุงูู)', 'ุงูู ุญุงุฑุจ (ุงูู ุฑูุฒ ุงูุซุงูุซ)']; const bonusPoints = [100, 50, 25]; const batch = db.batch(); let rank = 0; snapshot.forEach(doc => { const userId = doc.id; const userData = doc.data(); const currentPoints = userData.arcade_points || 0; if (currentPoints === 0) return; const msgEn = `Congratulations Champion! ๐ฅณ\nYou achieved rank #${rank + 1} in Titan Gravity with ${currentPoints} points.\nReward: +${bonusPoints[rank]} Bonus Points!`; const msgAr = `ู ุจุฑูู ูุง ุจุทู! ๐ฅณ\nููุฏ ุญููุช ${medals[rank]} ${titles[rank]} ูู ูุนุจุฉ Titan Gravity ุจุฑุตูุฏ ${currentPoints} ููุทุฉ.\nุงูุฌุงุฆุฒุฉ: +${bonusPoints[rank]} ููุทุฉ ุฅุถุงููุฉ!`; const notifRef = db.collection('notifications').doc(); batch.set(notifRef, { title: `${medals[rank]} ุชูุฑูู ุงูุฃูุงุฆู`, body: msgEn, bodyAr: msgAr, type: 'GAME_AWARD', userId: userId, timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false, rank: rank + 1 }); const userRef = db.collection('titan_ghosts').doc(userId); batch.update(userRef, { arcade_points: admin.firestore.FieldValue.increment(bonusPoints[rank]) }); logSys('GAME_MASTER', `๐ Award sent to Rank #${rank + 1}: ${maskUid(userId)} (${currentPoints} pts)`, 'success'); rank++; }); await batch.commit(); logSys('GAME_MASTER', 'โ Top 3 players awarded & bonuses added.', 'success'); } catch (error) { logSys('GAME_MASTER', `โ Failed to award players: ${error.message}`, 'error'); } }); // 11. SOCKET.IO REAL-TIME RELAY const server = http.createServer(app); const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"] } }); const onlineUsers = new Map(); async function sendPushNotification(targetId, payload) { try { if (!targetId || !payload) return; const userDoc = await db.collection('users').doc(targetId).get(); const fcmToken = userDoc.exists ? userDoc.data().fcmToken : null; if (!fcmToken) { logSys('PUSH', `No FCM token for user ${targetId}`, 'warning'); return; } const message = { token: fcmToken, notification: { title: payload.title || 'New message', body: payload.body || payload.msg || '' }, data: payload.data || {} }; await admin.messaging().send(message); logSys('PUSH', `๐ฒ Push sent to user ${targetId}`, 'success'); } catch (error) { logSys('PUSH', `โ Failed to send push to ${targetId}: ${error.message}`, 'error'); } } // 12. HELPER: Get Server Statistics function getServerStats() { const uptimeMs = Date.now() - SERVER_START_TIME; const uptimeHours = Math.floor(uptimeMs / (1000 * 60 * 60)); const uptimeMinutes = Math.floor((uptimeMs % (1000 * 60 * 60)) / (1000 * 60)); const memUsage = process.memoryUsage(); const heapUsedMB = (memUsage.heapUsed / 1024 / 1024).toFixed(2); const heapTotalMB = (memUsage.heapTotal / 1024 / 1024).toFixed(2); const cpuLoad = os.loadavg(); const totalSocketConnections = io.sockets.sockets.size; return { uptime: `${uptimeHours}h ${uptimeMinutes}m`, uptimeMs, memory: { heapUsed: `${heapUsedMB} MB`, heapTotal: `${heapTotalMB} MB`, percentage: ((memUsage.heapUsed / memUsage.heapTotal) * 100).toFixed(1) + '%' }, connections: { registered: onlineUsers.size, total: totalSocketConnections }, cpuLoad: { '1min': cpuLoad[0].toFixed(2), '5min': cpuLoad[1].toFixed(2), '15min': cpuLoad[2].toFixed(2) }, sentinel: 'Active', platform: os.platform(), nodeVersion: process.version }; } // 13. FIRESTORE DEAD DROP COMMAND SYSTEM async function writeBlackboxResponse(message, level = 'SUCCESS', data = null) { try { await db.collection('titan_blackbox').add({ type: 'CMD_RES', message, level, data, ts: admin.firestore.FieldValue.serverTimestamp() }); logSys('BLACKBOX', `๐ Response written: ${message}`, 'info'); } catch (error) { logSys('BLACKBOX', `โ Failed to write response: ${error.message}`, 'error'); } } // ========================================== // ๐งน SWEEPER โ Orphaned Data Cleanup Engine // Paginates all Firebase Auth users, cross-references // titan_ghosts, then batch-deletes orphaned records // across 5 collections in safe โค450-op chunks. // ========================================== async function sweepOrphanedData() { logSys('SWEEPER', '๐ Starting orphaned data sweep...', 'system'); // โโ Step 1: Build the full valid-UID Set from Firebase Auth โโ const validUids = new Set(); let pageToken; try { do { const listResult = await admin.auth().listUsers(1000, pageToken); listResult.users.forEach(userRecord => validUids.add(userRecord.uid)); pageToken = listResult.pageToken; } while (pageToken); logSys('SWEEPER', `โ Loaded ${validUids.size} valid UIDs from Firebase Auth`, 'info'); } catch (e) { logSys('SWEEPER', `โ Failed to list Auth users: ${e.message}`, 'error'); throw new Error(`Auth pagination failed: ${e.message}`); } // โโ Step 2: Fetch titan_ghosts as the source-of-truth roster โโ let ghostsSnapshot; try { ghostsSnapshot = await db.collection('titan_ghosts').get(); logSys('SWEEPER', `๐ Fetched ${ghostsSnapshot.size} docs from titan_ghosts`, 'info'); } catch (e) { logSys('SWEEPER', `โ Failed to fetch titan_ghosts: ${e.message}`, 'error'); throw new Error(`Firestore read failed: ${e.message}`); } // โโ Step 3: Identify orphaned UIDs โโ const orphanedUids = []; ghostsSnapshot.forEach(doc => { if (!validUids.has(doc.id)) { orphanedUids.push(doc.id); } }); if (orphanedUids.length === 0) { logSys('SWEEPER', 'โ No orphaned records found. Database is clean.', 'success'); return { success: true, message: 'No orphaned records found. Database is clean.', orphansFound: 0, docsDeleted: 0 }; } logSys('SWEEPER', `โ ๏ธ Found ${orphanedUids.length} orphaned UID(s) โ beginning batch delete`, 'warning'); // โโ Step 4: Batch-delete across 5 collections with chunk safety โโ // Firestore hard limit: 500 ops/batch. We commit at 450 to stay well clear. const COLLECTIONS = ['titan_ghosts', 'titan_keys', 'users', 'user_reputation', 'welcome_sent']; const CHUNK_LIMIT = 450; let currentBatch = db.batch(); let opsInCurrentBatch = 0; let totalDocsDeleted = 0; let batchesCommitted = 0; try { for (const uid of orphanedUids) { for (const collectionName of COLLECTIONS) { const docRef = db.collection(collectionName).doc(uid); currentBatch.delete(docRef); opsInCurrentBatch++; totalDocsDeleted++; // Commit and start a fresh batch before hitting the 500-op wall if (opsInCurrentBatch >= CHUNK_LIMIT) { await currentBatch.commit(); batchesCommitted++; logSys('SWEEPER', `๐ฆ Committed batch #${batchesCommitted} (${opsInCurrentBatch} ops)`, 'info'); currentBatch = db.batch(); opsInCurrentBatch = 0; } } } // Commit any remaining operations in the final partial batch if (opsInCurrentBatch > 0) { await currentBatch.commit(); batchesCommitted++; logSys('SWEEPER', `๐ฆ Committed final batch #${batchesCommitted} (${opsInCurrentBatch} ops)`, 'info'); } } catch (e) { logSys('SWEEPER', `โ Batch delete failed: ${e.message}`, 'error'); throw new Error(`Batch delete failed: ${e.message}`); } const report = { success: true, message: `Sweep complete. Removed ${orphanedUids.length} orphaned user(s).`, orphansFound: orphanedUids.length, docsDeleted: totalDocsDeleted, batchesCommitted, collectionsSwept: COLLECTIONS, orphanedUids: orphanedUids.map(uid => maskUid(uid)) // masked for safe logging }; logSys('SWEEPER', `โ Sweep complete โ ${orphanedUids.length} orphans, ${totalDocsDeleted} docs deleted across ${batchesCommitted} batch(es)`, 'success'); return report; } async function processAdminCommand(docId, commandData) { try { const { adminKey, command } = commandData; if (adminKey !== ADMIN_ID) { await writeBlackboxResponse('Access denied. Invalid admin credentials.', 'HIGH'); logSys('DEAD_DROP', `โ Unauthorized access attempt (docId: ${docId})`, 'error'); return; } logSys('DEAD_DROP', `๐๏ธ Processing command: ${command}`, 'system'); const parts = command.trim().split(/\s+/); const cmd = parts[0].toLowerCase(); const args = parts.slice(1); switch (cmd) { case '/stats': { const stats = getServerStats(); const report = ` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๐๏ธ TITAN NEXUS SERVER STATISTICS โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โฑ๏ธ UPTIME: ${stats.uptime} ๐พ MEMORY USAGE: โข Heap Used: ${stats.memory.heapUsed} โข Heap Total: ${stats.memory.heapTotal} โข Usage: ${stats.memory.percentage} ๐ CONNECTIONS: โข Registered Users: ${stats.connections.registered} โข Total Sockets: ${stats.connections.total} โ๏ธ SYSTEM LOAD (CPU): โข 1 min: ${stats.cpuLoad['1min']} โข 5 min: ${stats.cpuLoad['5min']} โข 15 min: ${stats.cpuLoad['15min']} ๐ก๏ธ SECURITY: โข Sentinel MK2: ${stats.sentinel} ๐ ROYAL FAMILY: โข Protected Members: ${ROYAL_FAMILY.length} ๐ฅ๏ธ PLATFORM: โข OS: ${stats.platform} โข Node: ${stats.nodeVersion} ๐ฐ๏ธ TIME-AWARE ENGINE: โข Gregorian: ${getGregorianDateString(new Date())} โข Hijri: ${getHijriDateString(new Date())} Generated: ${new Date().toISOString()} `.trim(); await writeBlackboxResponse('Server statistics generated', 'SYSTEM', { report, stats }); logSys('DEAD_DROP', '๐ Stats report generated and written to blackbox', 'success'); break; } case '/notify': { if (args.length < 2) { await writeBlackboxResponse('Usage: /notify [uid] [message]', 'HIGH'); break; } const targetUid = args[0]; const message = args.slice(1).join(' '); await db.collection('notifications').add({ userId: targetUid, message, sentBy: 'ADMIN_SYSTEM', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('admin_notification', { message, timestamp: new Date().toISOString() }); } await sendPushNotification(targetUid, { title: 'Admin Notification', body: message, data: { type: 'admin_notification' } }); await writeBlackboxResponse( `Notification sent to user ${targetUid}`, 'SUCCESS', { online: !!targetSocketId, pushSent: true } ); logSys('DEAD_DROP', `๐ฌ Notification sent to ${maskUid(targetUid)}`, 'success'); break; } case '/ban': { if (args.length < 2) { await writeBlackboxResponse('Usage: /ban [uid] [reason]', 'HIGH'); break; } const targetUid = args[0]; const reason = args.slice(1).join(' '); // ๐ ROYAL IMMUNITY CHECK if (ROYAL_FAMILY.includes(targetUid)) { await writeBlackboxResponse( `Cannot ban user ${targetUid} - Royal Immunity Shield`, 'HIGH', { royalProtection: true } ); logSys('DEAD_DROP', `๐ Ban attempt blocked - Royal immunity for ${maskUid(targetUid)}`, 'royal'); break; } await admin.auth().updateUser(targetUid, { disabled: true }); await admin.auth().revokeRefreshTokens(targetUid); await db.collection('banned_users').doc(targetUid).set({ userId: targetUid, bannedAt: admin.firestore.FieldValue.serverTimestamp(), reason, bannedBy: ADMIN_ID, method: 'admin_command_deaddrop' }); await db.collection('users').doc(targetUid).set({ banned: true, bannedAt: admin.firestore.FieldValue.serverTimestamp(), banReason: reason, bannedBy: ADMIN_ID }, { merge: true }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('force_logout', { reason: 'Account has been banned', timestamp: new Date().toISOString() }); io.sockets.sockets.get(targetSocketId)?.disconnect(true); onlineUsers.delete(targetUid); } await writeBlackboxResponse( `User ${targetUid} banned successfully`, 'SUCCESS', { reason, wasOnline: !!targetSocketId, disconnected: !!targetSocketId } ); logSys('DEAD_DROP', `๐ซ User ${maskUid(targetUid)} banned: ${reason}`, 'warning'); break; } case '/clear': { if (args[0] !== 'logs') { await writeBlackboxResponse('Usage: /clear logs', 'HIGH'); break; } const cutoffDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); const snapshot = await db.collection('titan_blackbox') .where('ts', '<', cutoffDate) .limit(500) .get(); if (snapshot.empty) { await writeBlackboxResponse('No old logs found to clear', 'SYSTEM'); break; } const batch = db.batch(); snapshot.docs.forEach(doc => batch.delete(doc.ref)); await batch.commit(); await writeBlackboxResponse( `Cleared ${snapshot.size} old log entries`, 'SUCCESS', { deleted: snapshot.size, olderThan: '7 days' } ); logSys('DEAD_DROP', `๐๏ธ Cleared ${snapshot.size} old logs`, 'info'); break; } case '/broadcast': { if (args.length === 0) { await writeBlackboxResponse('Usage: /broadcast [message]', 'HIGH'); break; } const message = args.join(' '); await db.collection('notifications').add({ title: '๐ข ุชูุจูู ุนุงู ', body: message, bodyAr: message, type: 'SYSTEM_BROADCAST', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); io.emit('receive_direct', { from: 'SYSTEM', msg: message, isSystem: true, timestamp: new Date().toISOString() }); await writeBlackboxResponse( 'Broadcast sent to all users & saved to DB', 'SUCCESS', { recipients: io.sockets.sockets.size, message } ); logSys('DEAD_DROP', `๐ข Broadcast sent to ${io.sockets.sockets.size} connections`, 'success'); break; } case '/sweep-orphans': { logSys('DEAD_DROP', '๐งน /sweep-orphans triggered via Dead Drop', 'system'); const sweepResult = await sweepOrphanedData(); const sweepReport = ` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๐งน ORPHAN SWEEP REPORT โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ${sweepResult.orphansFound === 0 ? 'โ Database is clean โ no orphaned records found.' : `โ ๏ธ Orphaned UIDs found: ${sweepResult.orphansFound} ๐๏ธ Total docs deleted: ${sweepResult.docsDeleted} ๐ฆ Batches committed: ${sweepResult.batchesCommitted} ๐ Collections swept: ${sweepResult.collectionsSwept.join(', ')} Orphaned UIDs (masked): ${sweepResult.orphanedUids.map(u => ` โข ${u}`).join('\n')}`} Generated: ${new Date().toISOString()} `.trim(); await writeBlackboxResponse(sweepResult.message, 'SUCCESS', { ...sweepResult, report: sweepReport }); logSys('DEAD_DROP', `๐งน Sweep report written to blackbox`, 'success'); break; } default: { await writeBlackboxResponse( `Unknown command: ${cmd}`, 'HIGH', { availableCommands: ['/notify', '/ban', '/clear logs', '/broadcast', '/stats', '/sweep-orphans'] } ); logSys('DEAD_DROP', `โ Unknown command attempted: ${cmd}`, 'warning'); } } } catch (error) { logSys('DEAD_DROP', `โ Command error: ${error.message}`, 'error'); await writeBlackboxResponse( `Command execution failed: ${error.message}`, 'HIGH' ); } } async function initCommandReader() { logSys('DEAD_DROP', '๐ก Firestore Dead Drop Command Reader initialized', 'system'); db.collection('pending_bot_actions') .where('status', '==', 'pending') .onSnapshot(async (snapshot) => { snapshot.docChanges().forEach(async (change) => { if (change.type === 'added') { const docId = change.doc.id; const data = change.doc.data(); try { await db.collection('pending_bot_actions').doc(docId).update({ status: 'processing', processedAt: admin.firestore.FieldValue.serverTimestamp() }); logSys('DEAD_DROP', `๐ฅ New command received (docId: ${docId})`, 'info'); await processAdminCommand(docId, data); await db.collection('pending_bot_actions').doc(docId).delete(); logSys('DEAD_DROP', `โ Command processed and deleted (docId: ${docId})`, 'success'); } catch (error) { logSys('DEAD_DROP', `โ Failed to process command ${docId}: ${error.message}`, 'error'); await db.collection('pending_bot_actions').doc(docId).update({ status: 'error', error: error.message, errorAt: admin.firestore.FieldValue.serverTimestamp() }); } } }); }, (error) => { logSys('DEAD_DROP', `โ ๏ธ Listener Error: ${error.message}`, 'error'); }); } // 14. SOCKET.IO CONNECTION HANDLER io.on('connection', (socket) => { logSys('SOCKET', `๐ New connection: ${socket.id}`, 'cyber'); socket.on('register', (userId) => { if (!userId) return; onlineUsers.set(userId, socket.id); if (ROYAL_FAMILY.includes(userId)) { logSys('SOCKET', `๐ Royal user ${maskUid(userId)} registered (socket: ${socket.id})`, 'royal'); } else { logSys('SOCKET', `โ User ${maskUid(userId)} registered (socket: ${socket.id})`, 'success'); } }); socket.on('send_direct', async (data) => { const { to, msg } = data; if (!to || !msg) return; const targetSocketId = onlineUsers.get(to); if (targetSocketId) { io.to(targetSocketId).emit('receive_direct', { from: socket.id, msg, timestamp: new Date().toISOString() }); logSys('SOCKET', `๐จ Relayed DM to online user ${to}`, 'info'); } else { logSys('SOCKET', `๐ฒ User ${to} offline, sending push`, 'info'); await sendPushNotification(to, { title: 'New direct message', body: typeof msg === 'string' ? msg : JSON.stringify(msg), data: { sender: socket.id, ...msg } }); } }); socket.on('admin_cmd', async (payload) => { try { const { adminKey, command } = payload; if (adminKey !== ADMIN_ID) { socket.emit('cmd_res', { success: false, error: 'Access denied. Invalid admin credentials.', timestamp: new Date().toISOString() }); logSys('ADMIN_CMD', `โ Unauthorized access attempt from socket ${socket.id}`, 'error'); return; } logSys('ADMIN_CMD', `๐๏ธ Command received: ${command}`, 'system'); const parts = command.trim().split(/\s+/); const cmd = parts[0].toLowerCase(); const args = parts.slice(1); switch (cmd) { case '/notify': { if (args.length < 2) { socket.emit('cmd_res', { success: false, error: 'Usage: /notify [uid] [message]' }); break; } const targetUid = args[0]; const message = args.slice(1).join(' '); await db.collection('notifications').add({ userId: targetUid, message, sentBy: 'ADMIN_SYSTEM', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('admin_notification', { message, timestamp: new Date().toISOString() }); } await sendPushNotification(targetUid, { title: 'Admin Notification', body: message, data: { type: 'admin_notification' } }); socket.emit('cmd_res', { success: true, message: `Notification sent to user ${targetUid}`, details: { online: !!targetSocketId, pushSent: true } }); logSys('ADMIN_CMD', `๐ฌ Notification sent to ${maskUid(targetUid)}`, 'success'); break; } case '/ban': { if (args.length < 2) { socket.emit('cmd_res', { success: false, error: 'Usage: /ban [uid] [reason]' }); break; } const targetUid = args[0]; const reason = args.slice(1).join(' '); // ๐ ROYAL IMMUNITY CHECK if (ROYAL_FAMILY.includes(targetUid)) { socket.emit('cmd_res', { success: false, error: `Cannot ban user ${targetUid} - Royal Immunity Shield`, royalProtection: true }); logSys('ADMIN_CMD', `๐ Ban attempt blocked - Royal immunity for ${maskUid(targetUid)}`, 'royal'); break; } await admin.auth().updateUser(targetUid, { disabled: true }); await admin.auth().revokeRefreshTokens(targetUid); await db.collection('banned_users').doc(targetUid).set({ userId: targetUid, bannedAt: admin.firestore.FieldValue.serverTimestamp(), reason, bannedBy: ADMIN_ID, method: 'admin_command' }); await db.collection('users').doc(targetUid).set({ banned: true, bannedAt: admin.firestore.FieldValue.serverTimestamp(), banReason: reason, bannedBy: ADMIN_ID }, { merge: true }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('force_logout', { reason: 'Account has been banned', timestamp: new Date().toISOString() }); io.sockets.sockets.get(targetSocketId)?.disconnect(true); onlineUsers.delete(targetUid); } socket.emit('cmd_res', { success: true, message: `User ${targetUid} banned successfully`, details: { reason, wasOnline: !!targetSocketId, disconnected: !!targetSocketId } }); logSys('ADMIN_CMD', `๐ซ User ${maskUid(targetUid)} banned: ${reason}`, 'warning'); break; } case '/clear': { if (args[0] !== 'logs') { socket.emit('cmd_res', { success: false, error: 'Usage: /clear logs' }); break; } const cutoffDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); const snapshot = await db.collection('titan_blackbox') .where('timestamp', '<', cutoffDate) .limit(500) .get(); if (snapshot.empty) { socket.emit('cmd_res', { success: true, message: 'No old logs found to clear' }); break; } const batch = db.batch(); snapshot.docs.forEach(doc => batch.delete(doc.ref)); await batch.commit(); socket.emit('cmd_res', { success: true, message: `Cleared ${snapshot.size} old log entries`, details: { deleted: snapshot.size, olderThan: '7 days' } }); logSys('ADMIN_CMD', `๐๏ธ Cleared ${snapshot.size} old logs`, 'info'); break; } case '/broadcast': { if (args.length === 0) { socket.emit('cmd_res', { success: false, error: 'Usage: /broadcast [message]' }); break; } const message = args.join(' '); io.emit('receive_direct', { from: 'SYSTEM', msg: message, isSystem: true, timestamp: new Date().toISOString() }); socket.emit('cmd_res', { success: true, message: 'Broadcast sent to all users', details: { recipients: io.sockets.sockets.size, message } }); logSys('ADMIN_CMD', `๐ข Broadcast sent to ${io.sockets.sockets.size} connections`, 'success'); break; } case '/stats': { const stats = getServerStats(); const report = ` โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ ๐๏ธ TITAN NEXUS SERVER STATISTICS โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โฑ๏ธ UPTIME: ${stats.uptime} ๐พ MEMORY USAGE: โข Heap Used: ${stats.memory.heapUsed} โข Heap Total: ${stats.memory.heapTotal} โข Usage: ${stats.memory.percentage} ๐ CONNECTIONS: โข Registered Users: ${stats.connections.registered} โข Total Sockets: ${stats.connections.total} โ๏ธ SYSTEM LOAD (CPU): โข 1 min: ${stats.cpuLoad['1min']} โข 5 min: ${stats.cpuLoad['5min']} โข 15 min: ${stats.cpuLoad['15min']} ๐ก๏ธ SECURITY: โข Sentinel MK2: ${stats.sentinel} ๐ ROYAL FAMILY: โข Protected Members: ${ROYAL_FAMILY.length} ๐ฐ๏ธ TIME-AWARE ENGINE: โข Gregorian: ${getGregorianDateString(new Date())} โข Hijri: ${getHijriDateString(new Date())} ๐ฅ๏ธ PLATFORM: โข OS: ${stats.platform} โข Node: ${stats.nodeVersion} Generated: ${new Date().toISOString()} `.trim(); socket.emit('cmd_res', { success: true, message: 'Server statistics', report, data: stats }); logSys('ADMIN_CMD', '๐ Stats report generated', 'info'); break; } case '/sweep-orphans': { logSys('ADMIN_CMD', '๐งน /sweep-orphans triggered via Socket.IO', 'system'); const sweepResult = await sweepOrphanedData(); socket.emit('cmd_res', { success: true, message: sweepResult.message, details: sweepResult }); logSys('ADMIN_CMD', `๐งน Sweep complete โ ${sweepResult.orphansFound} orphans, ${sweepResult.docsDeleted} docs deleted`, 'success'); break; } default: { socket.emit('cmd_res', { success: false, error: `Unknown command: ${cmd}`, availableCommands: ['/notify', '/ban', '/clear logs', '/broadcast', '/stats', '/sweep-orphans'] }); logSys('ADMIN_CMD', `โ Unknown command attempted: ${cmd}`, 'warning'); } } } catch (error) { logSys('ADMIN_CMD', `โ Command error: ${error.message}`, 'error'); socket.emit('cmd_res', { success: false, error: `Command execution failed: ${error.message}`, timestamp: new Date().toISOString() }); } }); socket.on('disconnect', () => { let disconnectedUserId = null; for (const [userId, sockId] of onlineUsers.entries()) { if (sockId === socket.id) { disconnectedUserId = userId; onlineUsers.delete(userId); break; } } if (disconnectedUserId) { const logType = ROYAL_FAMILY.includes(disconnectedUserId) ? 'royal' : 'warning'; const icon = ROYAL_FAMILY.includes(disconnectedUserId) ? '๐' : '๐ด'; logSys('SOCKET', `${icon} User ${maskUid(disconnectedUserId)} disconnected`, logType); } else { logSys('SOCKET', `๐ด Socket ${socket.id} disconnected (unregistered)`, 'info'); } }); }); // ๐ ADMIN DASHBOARD (BUILT-IN) app.use(express.static('public')); // ูุฎุฏู ุฉ ุฃู ู ููุงุช ุฅุถุงููุฉ (ุงุฎุชูุงุฑู) app.get('/admin', (req, res) => { res.sendFile(__dirname + '/admin.html'); }); // 15. HEALTH & STATUS ENDPOINTS app.get('/', (req, res) => { const stats = getServerStats(); res.json({ service: 'TITAN NEXUS โ Time-Aware Royal AI Edition', status: 'operational', version: '14.0', security: 'Sentinel MK2 active', realtime: 'Socket.io relay active', adminCenter: 'Dead Drop Command System active', ai: 'Gemini AI + Time-Aware Engine active', royalFamily: ROYAL_FAMILY.length, onlineUsers: onlineUsers.size, uptime: stats.uptime, memory: stats.memory.percentage, timeAware: { gregorian: getGregorianDateString(new Date()), hijri: getHijriDateString(new Date()) } }); }); app.get('/ping', (req, res) => res.send('pong')); app.get('/stats', (req, res) => { const stats = getServerStats(); res.json({ ...stats, timeAware: { gregorian: getGregorianDateString(new Date()), hijri: getHijriDateString(new Date()) } }); }); // ๐ AUTH DEBUG โ checks if a key matches ADMIN_ID (temporary, remove after debugging) app.post('/admin/check-auth', (req, res) => { const { adminKey } = req.body; if (!adminKey) return res.json({ ok: false, reason: 'no_key' }); const match = adminKey === ADMIN_ID; const adminLen = ADMIN_ID ? ADMIN_ID.length : 0; const keyLen = adminKey.length; res.json({ ok: match, reason: match ? 'matched' : 'mismatch', keyLength: keyLen, adminIdLength: adminLen, adminIdSet: !!ADMIN_ID, firstFour: ADMIN_ID ? ADMIN_ID.substring(0, 4) : 'NOT_SET' }); }); // ๐ ADMIN COMMAND HTTP ENDPOINT (for web dashboard) app.post('/api/admin/command', async (req, res) => { try { const { adminKey, command } = req.body; if (!adminKey || !command) { return res.status(400).json({ success: false, error: 'Missing adminKey or command' }); } if (adminKey !== ADMIN_ID) { logSys('HTTP_ADMIN', `โ Auth failed โ key_len=${adminKey.length} admin_id_len=${ADMIN_ID ? ADMIN_ID.length : 'UNSET'} admin_id_set=${!!ADMIN_ID}`, 'error'); return res.status(403).json({ success: false, error: 'Invalid admin credentials' }); } logSys('HTTP_ADMIN', `๐๏ธ HTTP command received: ${command}`, 'system'); const parts = command.trim().split(/\s+/); const cmd = parts[0].toLowerCase(); const args = parts.slice(1); // Reuse same command logic as elsewhere const executeCommand = async () => { switch (cmd) { case '/stats': { const stats = getServerStats(); return { success: true, message: 'Server statistics retrieved', stats, report: ` Uptime: ${stats.uptime} Memory: ${stats.memory.percentage} Online Users: ${stats.connections.registered} CPU Load: ${stats.cpuLoad['1min']} / ${stats.cpuLoad['5min']} / ${stats.cpuLoad['15min']} Platform: ${stats.platform} `.trim() }; } case '/notify': { if (args.length < 2) throw new Error('Usage: /notify [uid] [message]'); const targetUid = args[0]; const message = args.slice(1).join(' '); await db.collection('notifications').add({ userId: targetUid, message, sentBy: 'ADMIN_SYSTEM', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('admin_notification', { message, timestamp: new Date().toISOString() }); } await sendPushNotification(targetUid, { title: 'Admin Notification', body: message, data: { type: 'admin_notification' } }); return { success: true, message: `Notification sent to user ${targetUid}`, details: { online: !!targetSocketId, pushSent: true } }; } case '/ban': { if (args.length < 2) throw new Error('Usage: /ban [uid] [reason]'); const targetUid = args[0]; const reason = args.slice(1).join(' '); if (ROYAL_FAMILY.includes(targetUid)) { return { success: false, error: `Cannot ban user ${targetUid} - Royal Immunity Shield`, royalProtection: true }; } await admin.auth().updateUser(targetUid, { disabled: true }); await admin.auth().revokeRefreshTokens(targetUid); await db.collection('banned_users').doc(targetUid).set({ userId: targetUid, bannedAt: admin.firestore.FieldValue.serverTimestamp(), reason, bannedBy: ADMIN_ID, method: 'admin_command_http' }); await db.collection('users').doc(targetUid).set({ banned: true, bannedAt: admin.firestore.FieldValue.serverTimestamp(), banReason: reason, bannedBy: ADMIN_ID }, { merge: true }); const targetSocketId = onlineUsers.get(targetUid); if (targetSocketId) { io.to(targetSocketId).emit('force_logout', { reason: 'Account has been banned', timestamp: new Date().toISOString() }); io.sockets.sockets.get(targetSocketId)?.disconnect(true); onlineUsers.delete(targetUid); } return { success: true, message: `User ${targetUid} banned successfully`, details: { reason, wasOnline: !!targetSocketId } }; } case '/clear': { if (args[0] !== 'logs') throw new Error('Usage: /clear logs'); const cutoffDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); const snapshot = await db.collection('titan_blackbox') .where('ts', '<', cutoffDate) .limit(500) .get(); if (snapshot.empty) { return { success: true, message: 'No old logs found to clear' }; } const batch = db.batch(); snapshot.docs.forEach(doc => batch.delete(doc.ref)); await batch.commit(); return { success: true, message: `Cleared ${snapshot.size} old log entries`, details: { deleted: snapshot.size, olderThan: '7 days' } }; } case '/broadcast': { if (args.length === 0) throw new Error('Usage: /broadcast [message]'); const message = args.join(' '); await db.collection('notifications').add({ title: '๐ข ุชูุจูู ุนุงู ', body: message, bodyAr: message, type: 'SYSTEM_BROADCAST', userId: 'BROADCAST', timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); io.emit('receive_direct', { from: 'SYSTEM', msg: message, isSystem: true, timestamp: new Date().toISOString() }); return { success: true, message: `Broadcast sent to ${io.sockets.sockets.size} connections`, details: { recipients: io.sockets.sockets.size } }; } case '/sweep-orphans': { logSys('HTTP_ADMIN', '๐งน /sweep-orphans triggered via HTTP', 'system'); const sweepResult = await sweepOrphanedData(); return { success: true, message: sweepResult.message, details: sweepResult }; } default: throw new Error(`Unknown command: ${cmd}. Available: /stats, /notify, /ban, /clear logs, /broadcast, /sweep-orphans`); } }; const result = await executeCommand(); res.json(result); } catch (error) { logSys('HTTP_ADMIN', `โ Command error: ${error.message}`, 'error'); res.status(500).json({ success: false, error: error.message }); } }); // ========================================== // ๐ WELCOME MANAGER โ Event-Driven via Firestore // Replaces the former POST /auth/welcome HTTP endpoint. // Listens on the `pending_welcomes` collection. The frontend // writes a document there on new-user registration; this // listener fires, processes the welcome, then deletes the doc // so the collection stays empty (zero ongoing read cost). // ========================================== function initWelcomeManager() { db.collection('pending_welcomes').onSnapshot(snapshot => { snapshot.docChanges().forEach(async change => { if (change.type !== 'added') return; const doc = change.doc; const uid = doc.id; const { email, displayName } = doc.data(); if (!uid || !email) { logSys('WELCOME', `โ ๏ธ Skipping malformed pending_welcomes doc (missing uid/email)`, 'warning'); await doc.ref.delete().catch(() => {}); return; } // โโ Dedup: skip if welcome already sent โโ try { const welcomeRef = db.collection('welcome_sent').doc(uid); const sent = await welcomeRef.get(); if (sent.exists) { logSys('WELCOME', `โญ๏ธ Welcome already sent for ${maskUid(uid)}, skipping`, 'info'); await doc.ref.delete().catch(() => {}); return; } // Mark as sent immediately to prevent any race condition await welcomeRef.set({ sentAt: admin.firestore.FieldValue.serverTimestamp(), email }); } catch (e) { logSys('WELCOME', `โ ๏ธ Firestore welcome_sent check failed: ${e.message}`, 'warning'); // Continue โ don't block the welcome on a metadata failure } const name = displayName || 'ุนุฒูุฒู ุงูู ุณุชุฎุฏู '; const today = new Date(); const dateStr = getGregorianDateString(today); const hijriStr = getHijriDateString(today); // โโ 1. In-app Notification โโ const notifBody = `ู ุฑุญุจุงู ุจู ูู Titan Connect ูุง ${name}! ๐ ุฃูุช ุงูุขู ุฌุฒุก ู ู ู ุฌุชู ุนูุง ุงูู ุชู ูุฒ. ุงูุชุดู ู ุง ููุชุธุฑู: ๐ ุดุงุช ูุฎุฒูุฉ ู ุดูุฑุฉ ุชู ุงู ุงู ๐ก ููู ู ููุงุช P2P ู ุจุงุดุฑ ุจุฏูู ุฎูุงุฏู ๐ฌ ุณููู ุง ู ุน ุชุฑุฌู ุฉ ุฐููุฉ ุจุงูุฐูุงุก ุงูุงุตุทูุงุนู ๐ ุงูุงูุบู ุงุณ โ ุชุนููู ุงูุฅูุฌููุฒู ุจุงููุตุต ๐ฅ ุฌุฑูุจุงุช ูู ุฌุชู ุนุงุช ุญูุฉ ูุชู ูู ูู ุชุฌุฑุจุฉ ู ู ุชุนุฉ! ๐`; try { await db.collection('notifications').add({ title: '๐ ุฃููุงู ุจู ูู Titan Connect!', body: notifBody, type: 'WELCOME', userId: uid, timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false }); // Real-time push to user's socket if online io.emit('welcome_notification', { uid, title: '๐ ุฃููุงู ุจู!', body: notifBody }); logSys('WELCOME', `โ In-app notification sent to ${maskUid(uid)}`, 'success'); } catch (e) { logSys('WELCOME', `โ ๏ธ Notification failed: ${e.message}`, 'warning'); } // โโ 2. Welcome Email โโ if (MAILER_URL && MAILER_TOKEN) { const htmlBody = `