Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@hono/zod-validator": "^0.7.0",
"@llmgateway/auth": "workspace:*",
"@llmgateway/db": "workspace:*",
"@llmgateway/logger": "workspace:*",
"bcrypt-ts": "7.0.0",
"better-auth": "1.2.7",
"drizzle-zod": "0.7.1",
Expand Down
13 changes: 10 additions & 3 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { swaggerUI } from "@hono/swagger-ui";
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { db } from "@llmgateway/db";
import { logger } from "@llmgateway/logger";
import "dotenv/config";
import { cors } from "hono/cors";
import { HTTPException } from "hono/http-exception";
Expand Down Expand Up @@ -45,7 +46,7 @@ app.onError((error, c) => {
const status = error.status;

if (status >= 500) {
console.log("HTTPException", error);
logger.error("HTTPException", error);
}

return c.json(
Expand All @@ -60,7 +61,10 @@ app.onError((error, c) => {
}

// For any other errors (non-HTTPException), return 500 Internal Server Error
console.error("Unhandled error:", error);
logger.error(
"Unhandled error",
error instanceof Error ? error : new Error(String(error)),
);
return c.json(
{
error: true,
Expand Down Expand Up @@ -112,7 +116,10 @@ app.openapi(root, async (c) => {
} catch (error) {
health.status = "error";
health.database.error = "Database connection failed";
console.error("Database healthcheck failed:", error);
logger.error(
"Database healthcheck failed",
error instanceof Error ? error : new Error(String(error)),
);
}

return c.json({
Expand Down
16 changes: 8 additions & 8 deletions apps/api/src/lib/beacon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { db, tables } from "@llmgateway/db";
import { logger } from "@llmgateway/logger";
import { randomUUID } from "crypto";

interface BeaconData {
Expand Down Expand Up @@ -39,11 +40,8 @@ export async function sendInstallationBeacon(): Promise<void> {
return;
}

console.log(
"Sending installation beacon (for anonymous tracking of self-hosted installs.",
);
console.log(
"To disable, set TELEMETRY_ACTIVE=false in your environment variables.",
logger.info(
"Sending installation beacon (for anonymous tracking of self-hosted installs. To disable, set TELEMETRY_ACTIVE=false in your environment variables.",
);

try {
Expand All @@ -65,7 +63,7 @@ export async function sendInstallationBeacon(): Promise<void> {
})
.returning();
installation = newInstallation;
console.log("Created new self-hosted installation record");
logger.info("Created new self-hosted installation record");
}

await sendBeacon({
Expand All @@ -75,8 +73,10 @@ export async function sendInstallationBeacon(): Promise<void> {
version: process.env.APP_VERSION || "v0.0.0-unknown",
});

console.log("Installation beacon sent successfully");
logger.info("Installation beacon sent successfully");
} catch (error) {
console.warn("Failed to send installation beacon:", error);
logger.warn("Failed to send installation beacon", {
error: error instanceof Error ? error : new Error(String(error)),
});
}
}
11 changes: 8 additions & 3 deletions apps/api/src/routes/beacon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { logger } from "@llmgateway/logger";
import { z } from "zod";

import { posthog } from "../posthog";
Expand Down Expand Up @@ -126,9 +127,13 @@ beacon.openapi(beaconRoute, async (c) => {
},
});

console.log(
`Received beacon from installation ${beaconData.uuid} (${beaconData.type}) - IP: ${clientIP}, Country: ${regionInfo.country}, Provider: ${cloudProvider}`,
);
logger.info("Received installation beacon", {
uuid: beaconData.uuid,
type: beaconData.type,
clientIP,
country: regionInfo.country,
cloudProvider,
});

return c.json({
success: true,
Expand Down
11 changes: 9 additions & 2 deletions apps/api/src/routes/chat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { logger } from "@llmgateway/logger";
import { streamSSE } from "hono/streaming";
import { z } from "zod";

Expand Down Expand Up @@ -123,7 +124,10 @@ chat.openapi(completionRoute, async (c) => {
}
}
} catch (error) {
console.error("Streaming error:", error);
logger.error(
"Streaming error",
error instanceof Error ? error : new Error(String(error)),
);
await stream.writeSSE({
data: JSON.stringify({ error: "Streaming failed" }),
event: "error",
Expand Down Expand Up @@ -154,7 +158,10 @@ chat.openapi(completionRoute, async (c) => {
return c.json(responseObject);
}
} catch (error) {
console.error("Chat completion error:", error);
logger.error(
"Chat completion error",
error instanceof Error ? error : new Error(String(error)),
);
return c.json({ error: "Failed to get chat completion" }, 500);
}
});
Expand Down
26 changes: 21 additions & 5 deletions apps/api/src/routes/subscriptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { db } from "@llmgateway/db";
import { logger } from "@llmgateway/logger";
import { HTTPException } from "hono/http-exception";
import { z } from "zod";

Expand Down Expand Up @@ -130,7 +131,10 @@ subscriptions.openapi(createProSubscription, async (c) => {
checkoutUrl: session.url,
});
} catch (error) {
console.error("Stripe checkout session error:", error);
logger.error(
"Stripe checkout session error",
error instanceof Error ? error : new Error(String(error)),
);
throw new HTTPException(500, {
message: `Failed to create checkout session: ${error}`,
});
Expand Down Expand Up @@ -202,7 +206,10 @@ subscriptions.openapi(cancelProSubscription, async (c) => {
success: true,
});
} catch (error) {
console.error("Stripe subscription cancellation error:", error);
logger.error(
"Stripe subscription cancellation error",
error instanceof Error ? error : new Error(String(error)),
);
throw new HTTPException(500, {
message: "Failed to cancel subscription",
});
Expand Down Expand Up @@ -285,7 +292,10 @@ subscriptions.openapi(resumeProSubscription, async (c) => {
success: true,
});
} catch (error) {
console.error("Stripe subscription resume error:", error);
logger.error(
"Stripe subscription resume error",
error instanceof Error ? error : new Error(String(error)),
);
throw new HTTPException(500, {
message: "Failed to resume subscription",
});
Expand Down Expand Up @@ -382,7 +392,10 @@ subscriptions.openapi(upgradeToYearlyPlan, async (c) => {
success: true,
});
} catch (error) {
console.error("Stripe subscription upgrade error:", error);
logger.error(
"Stripe subscription upgrade error",
error instanceof Error ? error : new Error(String(error)),
);
throw new HTTPException(500, {
message: "Failed to upgrade subscription to yearly plan",
});
Expand Down Expand Up @@ -456,7 +469,10 @@ subscriptions.openapi(getSubscriptionStatus, async (c) => {
}
billingCycle = currentPriceId === yearlyPriceId ? "yearly" : "monthly";
} catch (error) {
console.error("Error fetching subscription details:", error);
logger.error(
"Error fetching subscription details",
error instanceof Error ? error : new Error(String(error)),
);
}
}

Expand Down
8 changes: 6 additions & 2 deletions apps/api/src/scripts/generate-openapi.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { logger } from "@llmgateway/logger";
import { writeFileSync } from "fs";

import { app, config } from "..";
Expand All @@ -6,11 +7,14 @@ async function generateOpenAPI() {
const spec = app.getOpenAPIDocument(config);

writeFileSync("openapi.json", JSON.stringify(spec, null, 2));
console.log("✅ openapi.json has been generated");
logger.info("openapi.json has been generated");
process.exit(0);
}

void generateOpenAPI().catch((err) => {
console.error(err);
logger.error(
"Failed to generate OpenAPI",
err instanceof Error ? err : new Error(String(err)),
);
process.exit(1);
});
36 changes: 23 additions & 13 deletions apps/api/src/serve.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { serve } from "@hono/node-server";
import { closeDatabase, runMigrations } from "@llmgateway/db";
import { logger } from "@llmgateway/logger";

import { app } from "./index";
import { sendInstallationBeacon } from "./lib/beacon";
Expand All @@ -12,7 +13,10 @@ async function startServer() {
try {
await runMigrations();
} catch (error) {
console.error("Failed to run migrations, exiting...", error);
logger.error(
"Failed to run migrations, exiting",
error instanceof Error ? error : new Error(String(error)),
);
process.exit(1);
}
}
Expand All @@ -21,7 +25,7 @@ async function startServer() {
// This runs in the background and won't block startup
void sendInstallationBeacon();

console.log("listening on port", port);
logger.info("Server listening", { port });

return serve({
port,
Expand All @@ -45,26 +49,29 @@ const closeServer = (server: any): Promise<void> => {

const gracefulShutdown = async (signal: string, server: any) => {
if (isShuttingDown) {
console.log("Shutdown already in progress, ignoring signal:", signal);
logger.info("Shutdown already in progress, ignoring signal", { signal });
return;
}

isShuttingDown = true;
console.log(`Received ${signal}, starting graceful shutdown...`);
logger.info("Starting graceful shutdown", { signal });

try {
console.log("Closing HTTP server...");
logger.info("Closing HTTP server");
await closeServer(server);
console.log("HTTP server closed");
logger.info("HTTP server closed");

console.log("Closing database connection...");
logger.info("Closing database connection");
await closeDatabase();
console.log("Database connection closed");
logger.info("Database connection closed");

console.log("Graceful shutdown completed");
logger.info("Graceful shutdown completed");
process.exit(0);
} catch (error) {
console.error("Error during graceful shutdown:", error);
logger.error(
"Error during graceful shutdown",
error instanceof Error ? error : new Error(String(error)),
);
process.exit(1);
}
};
Expand All @@ -76,16 +83,19 @@ startServer()
process.on("SIGINT", () => gracefulShutdown("SIGINT", server));

process.on("uncaughtException", (error) => {
console.error("Uncaught exception:", error);
logger.error("Uncaught exception", error);
process.exit(1);
});

process.on("unhandledRejection", (reason, promise) => {
console.error("Unhandled rejection at:", promise, "reason:", reason);
logger.error("Unhandled rejection", { promise, reason });
process.exit(1);
});
Comment on lines 85 to 93

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Type event handler params; avoid implicit any

Strengthens typing and aligns with repo rules.

-process.on("uncaughtException", (error) => {
+process.on("uncaughtException", (error: Error) => {
   logger.error("Uncaught exception", error);
   process.exit(1);
 });
 
-process.on("unhandledRejection", (reason, promise) => {
-  logger.error("Unhandled rejection", { promise, reason });
+process.on(
+  "unhandledRejection",
+  (reason: unknown, promise: Promise<unknown>) => {
+    logger.error("Unhandled rejection", { promise, reason });
+    process.exit(1);
+  },
+);
-  process.exit(1);
-});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
process.on("uncaughtException", (error) => {
console.error("Uncaught exception:", error);
logger.error("Uncaught exception", error);
process.exit(1);
});
process.on("unhandledRejection", (reason, promise) => {
console.error("Unhandled rejection at:", promise, "reason:", reason);
logger.error("Unhandled rejection", { promise, reason });
process.exit(1);
});
process.on("uncaughtException", (error: Error) => {
logger.error("Uncaught exception", error);
process.exit(1);
});
process.on(
"unhandledRejection",
(reason: unknown, promise: Promise<unknown>) => {
logger.error("Unhandled rejection", { promise, reason });
process.exit(1);
},
);
🤖 Prompt for AI Agents
In apps/api/src/serve.ts around lines 85 to 93, the process event handler
parameters are implicitly any; add explicit types: declare the uncaughtException
handler parameter as (error: Error) and the unhandledRejection handler
parameters as (reason: unknown, promise: Promise<unknown>), and update the
logger calls if needed (e.g., pass error directly and serialize/inspect reason)
so TypeScript no longer reports implicit any and typings align with repo rules.

})
.catch((error) => {
console.error("Failed to start server:", error);
logger.error(
"Failed to start server",
error instanceof Error ? error : new Error(String(error)),
);
process.exit(1);
});
Loading
Loading