Skip to content
Open
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
7 changes: 6 additions & 1 deletion apps/cli/templates/backend/server/elysia/src/index.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { createContext } from "./lib/context";
{{#if (eq auth "better-auth")}}
import { auth } from "./lib/auth";
{{/if}}
import { checkDatabaseHealth } from "./lib/health";

{{#if (eq api "orpc")}}
const rpcHandler = new RPCHandler(appRouter, {
Expand Down Expand Up @@ -111,7 +112,11 @@ const app = new Elysia()
return result.toUIMessageStreamResponse();
})
{{/if}}
.get("/", () => "OK")
.get("/", async ({ set }) => {
const health = await checkDatabaseHealth();
if (health.error) set.status = 500;
return health;
})
.listen(3000, () => {
console.log("Server is running on http://localhost:3000");
});
7 changes: 5 additions & 2 deletions apps/cli/templates/backend/server/express/src/index.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { google } from "@ai-sdk/google";
import { auth } from "./lib/auth";
import { toNodeHandler } from "better-auth/node";
{{/if}}
import { checkDatabaseHealth } from "./lib/health";

const app = express();

Expand Down Expand Up @@ -112,8 +113,10 @@ app.post("/ai", async (req, res) => {
});
{{/if}}

app.get("/", (_req, res) => {
res.status(200).send("OK");
app.get("/", async (_req, res) => {
const health = await checkDatabaseHealth();
const status = health.error ? 500 : 200;
res.status(status).json(health);
});

const port = process.env.PORT || 3000;
Expand Down
9 changes: 7 additions & 2 deletions apps/cli/templates/backend/server/fastify/src/index.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { google } from "@ai-sdk/google";
{{#if (eq auth "better-auth")}}
import { auth } from "./lib/auth";
{{/if}}
import { checkDatabaseHealth } from "./lib/health";

const baseCorsConfig = {
origin: process.env.CORS_ORIGIN || "",
Expand Down Expand Up @@ -169,8 +170,12 @@ fastify.post('/ai', async function (request) {
});
{{/if}}

fastify.get('/', async () => {
return 'OK';
fastify.get('/', async (request, reply) => {
const health = await checkDatabaseHealth();
if (health.error) {
reply.status(500);
}
return health;
});

fastify.listen({ port: 3000 }, (err) => {
Expand Down
7 changes: 5 additions & 2 deletions apps/cli/templates/backend/server/hono/src/index.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { appRouter } from "./routers/index";
{{#if (eq auth "better-auth")}}
import { auth } from "./lib/auth";
{{/if}}
import { checkDatabaseHealth } from "./lib/health";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
Expand Down Expand Up @@ -145,8 +146,10 @@ app.post("/ai", async (c) => {
});
{{/if}}

app.get("/", (c) => {
return c.text("OK");
app.get("/", async (c) => {
const health = await checkDatabaseHealth();
const status = health.error ? 500 : 200;
return c.json(health, status);
});

{{#if (eq runtime "node")}}
Expand Down
5 changes: 4 additions & 1 deletion apps/cli/templates/backend/server/next/src/app/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { NextResponse } from "next/server";
import { checkDatabaseHealth } from "../lib/health";

export async function GET() {
return NextResponse.json({ message: "OK" });
const health = await checkDatabaseHealth();
const status = health.error ? 500 : 200;
return NextResponse.json(health, { status });
}
41 changes: 41 additions & 0 deletions apps/cli/templates/backend/server/next/src/lib/health.ts.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{{#if orm}}
{{#if (eq orm "drizzle")}}
Comment on lines +1 to +2
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace the top-level generic Handlebars if with explicit eq branches to avoid false “connected” on unknown ORMs.

As written, any truthy orm value enters the main branch; if it’s an unsupported value, none of the inner checks run, yet the function still returns { status: "OK", database: "connected" }. Also, coding guidelines discourage generic if/else in templates.

Refactor to an explicit eq chain and unify the function/type shape across variants.

Apply this diff:

-{{#if orm}}
-{{#if (eq orm "drizzle")}}
-import { db } from "../../db";
-{{/if}}
-{{#if (eq orm "prisma")}}
-import prisma from "../../db";
-{{/if}}
-{{#if (eq orm "mongoose")}}
-import { client } from "../../db";
-{{/if}}
-
-export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
-  try {
-    {{#if (eq orm "drizzle")}}
-    {{#if (eq database "sqlite")}}
-    await db.get("SELECT 1");
-    {{else if (eq database "postgres")}}
-    await db.execute("SELECT 1");
-    {{else if (eq database "mysql")}}
-    await db.execute("SELECT 1");
-    {{/if}}
-    {{else if (eq orm "prisma")}}
-    await prisma.$queryRaw`SELECT 1`;
-    {{else if (eq orm "mongoose")}}
-    await client.admin().ping();
-    {{/if}}
-    return { status: "OK", database: "connected" };
-  } catch (error) {
-    console.error("Database connection error:", error);
-    return { 
-      status: "OK", 
-      database: "disconnected", 
-      error: error instanceof Error ? error.message : String(error) 
-    };
-  }
-}
-{{else}}
-export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
-  return { status: "OK", database: "none" };
-}
-{{/if}}
+{{!-- Keep a consistent shape across all variants --}}
+type Health = {
+  status: "OK" | "ERROR";
+  database: "connected" | "disconnected" | "none";
+  error?: string;
+};
+
+{{#if (eq orm "drizzle")}}
+import { db } from "../../db";
+import { sql } from "drizzle-orm";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    {{#if (eq database "sqlite")}}
+    await db.get(sql`SELECT 1`);
+    {{else if (eq database "postgres")}}
+    await db.execute(sql`SELECT 1`);
+    {{else if (eq database "mysql")}}
+    await db.execute(sql`SELECT 1`);
+    {{/if}}
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else if (eq orm "prisma")}}
+import prisma from "../../db";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    await prisma.$queryRaw`SELECT 1`;
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else if (eq orm "mongoose")}}
+import { client } from "../../db";
+
+export async function checkDatabaseHealth(): Promise<Health> {
+  try {
+    await client.admin().ping();
+    return { status: "OK", database: "connected" };
+  } catch (error) {
+    console.error("Database connection error:", error);
+    return {
+      status: "ERROR",
+      database: "disconnected",
+      error: error instanceof Error ? error.message : String(error),
+    };
+  }
+}
+{{else}}
+export async function checkDatabaseHealth(): Promise<Health> {
+  return { status: "OK", database: "none" };
+}
+{{/if}}

Also applies to: 37-41

🤖 Prompt for AI Agents
In apps/cli/templates/backend/server/next/src/lib/health.ts.hbs around lines 1-2
and 37-41, the template uses a top-level generic Handlebars {{#if orm}} which
allows any truthy orm value (including unsupported ones) to enter the branch and
produce a misleading `{ status: "OK", database: "connected" }`; replace the
generic if with explicit equality branches (e.g., {{#if (eq orm "drizzle")}}
{{else if (eq orm "prisma")}} ... {{else}}) so each supported ORM has its own
branch and the fallback returns a consistent shape indicating unknown/disabled
DB, and ensure the exported function/type shape is unified across all branches
(same return object keys) to avoid mismatches.

import { db } from "../../db";
{{/if}}
{{#if (eq orm "prisma")}}
import prisma from "../../db";
{{/if}}
{{#if (eq orm "mongoose")}}
import { client } from "../../db";
{{/if}}

export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
try {
{{#if (eq orm "drizzle")}}
{{#if (eq database "sqlite")}}
await db.get("SELECT 1");
{{else if (eq database "postgres")}}
await db.execute("SELECT 1");
{{else if (eq database "mysql")}}
await db.execute("SELECT 1");
{{/if}}
{{else if (eq orm "prisma")}}
await prisma.$queryRaw`SELECT 1`;
{{else if (eq orm "mongoose")}}
await client.admin().ping();
{{/if}}
return { status: "OK", database: "connected" };
} catch (error) {
console.error("Database connection error:", error);
return {
status: "OK",
database: "disconnected",
error: error instanceof Error ? error.message : String(error)
};
}
}
{{else}}
export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
return { status: "OK", database: "none" };
}
{{/if}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{{#if orm}}
{{#if (eq orm "drizzle")}}
import { db } from "../db";
{{/if}}
{{#if (eq orm "prisma")}}
import prisma from "../db";
{{/if}}
{{#if (eq orm "mongoose")}}
import { client } from "../db";
{{/if}}

export async function checkDatabaseHealth(): Promise<{ status: string; database: string; error?: string }> {
try {
{{#if (eq orm "drizzle")}}
{{#if (eq database "sqlite")}}
await db.get("SELECT 1");
{{else if (eq database "postgres")}}
await db.execute("SELECT 1");
{{else if (eq database "mysql")}}
await db.execute("SELECT 1");
{{/if}}
{{else if (eq orm "prisma")}}
await prisma.$queryRaw`SELECT 1`;
{{else if (eq orm "mongoose")}}
await client.admin().ping();
{{/if}}
return { status: "OK", database: "connected" };
} catch (error) {
console.error("Database connection error:", error);
return {
status: "OK",
database: "disconnected",
error: error instanceof Error ? error.message : String(error)
};
}
}
{{else}}
export async function checkDatabaseHealth(): Promise<{ status: string; database: string }> {
return { status: "OK", database: "none" };
}
{{/if}}