import { serve } from "@hono/node-server"; import { Effect, ManagedRuntime } from "effect"; import { NodeContext } from "@effect/platform-node"; import { createApp } from "./hono/app.js"; import { createAuthRoutes } from "./auth/routes/authRoutes.js"; import { createAuthMiddleware } from "./auth/middleware/authMiddleware.js"; import { createAppLayer } from "./auth/layers.js"; import type { AppRuntimeContext } from "./auth/middleware/authMiddleware.js"; import * as path from "node:path"; import { homedir } from "node:os"; const getDefaultDbPath = (): string => { const sqliteDbPath = process.env["SQLITE_DB_PATH"]; if (sqliteDbPath) { return sqliteDbPath; } if (process.env["SINGLE_USER_MODE"] === "true") { const home = homedir(); return path.join(home, ".myaidev-web", "users.db"); } return path.join(process.cwd(), "data", "users.db"); }; // Create the application layer with auth services const AppLayer = createAppLayer({ path: getDefaultDbPath(), timeout: 5000, verbose: false, // Disable verbose mode to prevent schema logging on every request }); // Build the managed runtime once at startup (memoization with automatic scope management) const AppRuntime = ManagedRuntime.make(AppLayer) as ManagedRuntime.ManagedRuntime; // Create middleware and routes with the memoized runtime const authMiddleware = createAuthMiddleware(AppRuntime); const authRouter = createAuthRoutes(AppRuntime, authMiddleware); const program = Effect.gen(function* () { const port = Number.parseInt(process.env["PORT"] ?? "3400", 10); const dbPath = getDefaultDbPath(); console.log(`šŸ”§ Initializing MyAIDev Method Web Server`); console.log(`šŸ“‚ Database path: ${dbPath}`); console.log(`🌐 Server port: ${port}`); console.log(`āœ… Application layer initialized successfully`); const app = createApp(); console.log(`šŸš€ Starting server on port ${port}...`); // Mount authentication routes (already created with AppLayer) app.route("/api/auth", authRouter); // Example protected route app.get("/api/protected", authMiddleware, (c) => { const user = c.get("user"); const session = c.get("session"); return c.json({ message: "This is a protected route", user: { id: user?.id, username: user?.username, email: user?.email, }, session: { id: session?.id, expiresAt: session?.expiresAt, }, }); }); console.log("āœ… Routes configured successfully"); console.log(" šŸ“ POST /api/auth/register - User registration"); console.log(" šŸ“ POST /api/auth/login - User login"); console.log(" šŸ“ POST /api/auth/logout - User logout (protected)"); console.log(" šŸ“ GET /api/auth/me - Current user info (protected)"); console.log(" šŸ“ GET /api/protected - Example protected route"); const server = serve({ fetch: app.fetch, port, }); console.log(`āœ… Server running at http://localhost:${port}`); console.log(`šŸ“Š Health check: http://localhost:${port}/health`); yield* Effect.async(() => { process.on("SIGTERM", () => { console.log("\nšŸ›‘ SIGTERM received, shutting down gracefully..."); server.close(() => { console.log("āœ… Server closed"); process.exit(0); }); }); process.on("SIGINT", () => { console.log("\nšŸ›‘ SIGINT received, shutting down gracefully..."); server.close(() => { console.log("āœ… Server closed"); process.exit(0); }); }); }); }); // Program only needs Node context Effect.runPromise( Effect.provide(program, NodeContext.layer) as Effect.Effect ).catch((error) => { console.error("āŒ Fatal error:", error); process.exit(1); });