From 9f2809e89be02206bc34928b75881cef75edc9cb Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Thu, 21 May 2026 10:31:43 +0000 Subject: [PATCH 1/3] fix(GRO-1441): remove duplicate coatType/petSizeCategory from buildPet Lines 108-109 were duplicates of lines 102-103 from the PR #12 merge. Removing the duplicate pair resolves the TS1117 error on dev. Co-Authored-By: Paperclip --- packages/db/src/factories.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/db/src/factories.ts b/packages/db/src/factories.ts index cac71f7..c91f34a 100644 --- a/packages/db/src/factories.ts +++ b/packages/db/src/factories.ts @@ -105,8 +105,6 @@ export function buildPet(overrides: Partial & { clientId: string }): Pet photoKey: null, photoUploadedAt: null, image: null, - coatType: null, - petSizeCategory: null, createdAt: new Date("2025-01-01T00:00:00Z"), updatedAt: new Date("2025-01-01T00:00:00Z"), }; From 49f70eb74bcbad4182309da57f1c9923aec17f85 Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Fri, 22 May 2026 22:18:52 +0000 Subject: [PATCH 2/3] fix(GRO-1544): restore /health alongside /api/health endpoint The previous GRO-1544 PR changed /health to /api/health but removed the /health endpoint entirely. This breaks: - Dockerfile HEALTHCHECK (curl -f http://localhost:3000/health) - K8s readinessProbe/livenessProbe (httpGet: path: /health, port: 3000) Both paths are registered before auth middleware so both remain publicly accessible without authentication. Co-Authored-By: Claude Opus 4.7 --- src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.ts b/src/index.ts index 9ae50b8..2abf712 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,6 +59,9 @@ app.use( ); // Health check — no auth required, registered on app at full path before auth middleware +// /health: used by Dockerfile HEALTHCHECK and K8s readinessProbe/livenessProbe (port 3000 direct) +app.get("/health", (c) => c.json({ status: "ok" })); +// /api/health: used by Gateway HTTPRoute (/api/* → API pod) app.get("/api/health", (c) => c.json({ status: "ok" })); // Public booking routes — no auth required, must be registered before auth middleware From b486c44a82b99d9ac8592407d19f91331ab4994c Mon Sep 17 00:00:00 2001 From: Scrubs McBarkley <18+gb_scrubs@noreply.git.farh.net> Date: Sun, 24 May 2026 20:11:44 +0000 Subject: [PATCH 3/3] fix(api): add timeouts for OIDC discovery fetch and DB connection (#66) --- packages/db/src/index.ts | 2 +- src/index.ts | 10 ++++++---- src/lib/auth.ts | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 8b3b01f..e3bc914 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -12,7 +12,7 @@ export function getDb() { if (_db) return _db; const url = process.env.DATABASE_URL; if (!url) throw new Error("DATABASE_URL is not set"); - const client = postgres(url, { max: 10 }); + const client = postgres(url, { max: 10, connect_timeout: 5 }); _db = drizzle(client, { schema }); return _db; } diff --git a/src/index.ts b/src/index.ts index 2abf712..3dd8921 100644 --- a/src/index.ts +++ b/src/index.ts @@ -285,14 +285,16 @@ startReminderScheduler(); function shutdown() { console.log("Shutting down gracefully..."); + // SIGTERM/SIGINT → server.close() → callback → process.exit(0) + // If graceful close takes >8s, force-exit to avoid being killed undrained + setTimeout(() => { + console.error("Graceful close timeout — forcing exit"); + process.exit(1); + }, 8_000); server.close(() => { console.log("HTTP server closed"); process.exit(0); }); - setTimeout(() => { - console.error("Forced shutdown after timeout"); - process.exit(1); - }, 10_000); } process.on("SIGTERM", shutdown); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 9e78740..da2b2d1 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -186,7 +186,9 @@ export async function initAuth(): Promise { const discoveryUrlStr = `${providerConfig.issuerUrl}/.well-known/openid-configuration`; let oidcConfig: Record = {}; try { - const discoveryRes = await fetch(discoveryUrlStr); + const discoveryRes = await fetch(discoveryUrlStr, { + signal: AbortSignal.timeout(5000), + }); if (discoveryRes.ok) { const discovery = await discoveryRes.json() as { authorization_endpoint?: string;