import { createServer } from "http"; import app from "./app.js"; import { attachWebSocketServer } from "./routes/events.js"; import { rootLogger } from "./lib/logger.js"; import { timmyIdentityService } from "./lib/timmy-identity.js"; import { startEngagementEngine } from "./lib/engagement.js"; import { relayAccountService } from "./lib/relay-accounts.js"; import { moderationService } from "./lib/moderation.js"; const rawPort = process.env["PORT"]; if (!rawPort) { throw new Error("PORT environment variable is required but was not provided."); } const port = Number(rawPort); if (Number.isNaN(port) || port <= 0) { throw new Error(`Invalid PORT value: "${rawPort}"`); } const server = createServer(app); attachWebSocketServer(server); server.listen(port, () => { rootLogger.info("server started", { port }); rootLogger.info("timmy identity", { npub: timmyIdentityService.npub }); const domain = process.env["REPLIT_DEV_DOMAIN"]; if (domain) { rootLogger.info("public url", { url: `https://${domain}/api/ui` }); rootLogger.info("tower url", { url: `https://${domain}/tower` }); rootLogger.info("ws url", { url: `wss://${domain}/api/ws` }); } startEngagementEngine(); // ── Moderation poll loop ───────────────────────────────────────────────── // Processes up to 10 pending relay events every 30 seconds via Claude haiku. const MODERATION_POLL_MS = parseInt(process.env["MODERATION_POLL_MS"] ?? "", 10) || 30_000; setInterval(() => { moderationService.processPending(10).catch((err) => rootLogger.error("moderation poll error", { err }), ); }, MODERATION_POLL_MS); rootLogger.info("moderation poll loop started", { intervalMs: MODERATION_POLL_MS }); // Seed Timmy's own pubkey with elite identity + relay write access. // Resolves pubkey from TIMMY_NOSTR_PUBKEY env var if set (explicit override), // otherwise falls back to the hex pubkey derived from TIMMY_NOSTR_NSEC. // Idempotent — safe to run on every startup. const timmyPubkey = process.env["TIMMY_NOSTR_PUBKEY"] ?? timmyIdentityService.pubkeyHex; relayAccountService .seedElite(timmyPubkey, "Timmy's own pubkey — elite access seeded at startup") .then(() => rootLogger.info("relay: Timmy's pubkey seeded with elite access", { pubkey: timmyPubkey.slice(0, 8), source: process.env["TIMMY_NOSTR_PUBKEY"] ? "TIMMY_NOSTR_PUBKEY env" : "timmyIdentityService", }), ) .catch((err) => rootLogger.warn("relay: failed to seed Timmy's pubkey", { err }), ); });