import { Hono } from "hono"; import { configure, getConsoleSink, getLogger, Logger } from "@logtape/logtape"; import { getPrettyFormatter } from "@logtape/pretty"; import { Database } from "./db/connection.ts"; import { DidResolver } from "@atp/identity"; import { AuthVerifier } from "./utils/auth.ts"; import { createServer } from "./lex/index.ts"; import { env } from "./utils/env.ts"; import describeFeedGenerator from "./api/describeFeedGenerator.ts"; import getFeedSkeleton from "./api/getFeedSkeleton.ts"; import wellKnown from "./api/well-known.ts"; import health from "./api/health.ts"; import { Ingester } from "./ingester/index.ts"; await configure({ sinks: { console: getConsoleSink({ formatter: getPrettyFormatter({ properties: true, categoryStyle: "underline", messageColor: "rgb(255, 255, 255)", categoryColor: "rgb(255, 255, 255)", messageStyle: "reset", }), }), }, loggers: [ { category: "feedgen", lowestLevel: "info", sinks: ["console"] }, { category: ["logtape", "meta"], lowestLevel: "error", sinks: ["console"] }, ], }); const logger = getLogger("feedgen"); const ownDid = `did:web:${env.SPRK_FEEDGEN_DOMAIN}`; const didResolver = new DidResolver({}); const authVerifier = new AuthVerifier(ownDid, didResolver); const db = new Database(); const ctx = { db, logger, ownDid, didResolver, authVerifier, }; export type AppContext = { db: Database; logger: Logger; ownDid: string; didResolver: DidResolver; authVerifier: AuthVerifier; }; export type AppEnv = { Bindings: AppContext; }; const app = new Hono(); const server = createServer(); describeFeedGenerator(server, ctx); getFeedSkeleton(server, ctx); app.route("/", server.xrpc.app); app.use("*", async (c, next) => { // Initialize c.env if it doesn't exist (for testing compatibility) if (!c.env) { c.env = {} as AppContext; } c.env.ownDid = ownDid; c.env.didResolver = didResolver; c.env.authVerifier = authVerifier; c.env.logger = logger; await next(); }); app.get("/", (c) => { return c.text( "This is a Feed Generation service! Most endpoints are under /xrpc", ); }); // Initialize database connection when server starts export async function startServer() { logger.info("Starting Feed Generator service"); try { await db.connect(); } catch (err) { logger.error("Failed to connect to database", { err }); Deno.exit(1); } const ingester = new Ingester(db); ingester.firehose.start(); const { SPRK_HOST, SPRK_PORT } = env; Deno.serve({ hostname: SPRK_HOST, port: SPRK_PORT, onListen: (info) => { logger.info(`Server listening on http://${info.hostname}:${info.port}`); }, }, app.fetch); // Handle shutdown gracefully const shutdown = async () => { logger.info("Shutting down..."); await db.disconnect(); Deno.exit(0); }; Deno.addSignalListener("SIGINT", shutdown); Deno.addSignalListener("SIGTERM", shutdown); logger.info("Feed Generator service is running"); app.route("/.well-known", wellKnown); app.route("/", health); return app; } // For development and testing if (import.meta.main) { startServer(); }