From 3964de4962b1e0a33a098296814ba8b140921686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sun, 3 May 2026 01:05:42 +0100 Subject: [PATCH] fix(api): use notInArray + inArray in unread-count subqueries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the sql.join() form of NOT IN crashed the route handler before it could respond — vercel surfaced the crash as a plaintext 404 instead of going through hono's exception handler. switching to drizzle's notInArray() / inArray() emits stable parameter bindings and resolves both /v1/me/topics (fresh endpoint) and /v1/topics (older endpoint with the same ANY() pattern bug). also cleans up debug instrumentation that was added while chasing the 404. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/cli/src/services/api/client.ts | 5 +++-- packages/api/src/modules/mesh/v1-router.ts | 9 +++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/cli/src/services/api/client.ts b/apps/cli/src/services/api/client.ts index 17de5d4..05b26c6 100644 --- a/apps/cli/src/services/api/client.ts +++ b/apps/cli/src/services/api/client.ts @@ -41,8 +41,9 @@ export async function request(opts: RequestOpts): Promise { }); if (!res.ok) { - let body: unknown; - try { body = await res.json(); } catch { body = await res.text(); } + const text = await res.text(); + let body: unknown = text; + try { body = JSON.parse(text); } catch { /* leave as text */ } throw new ApiError(res.status, res.statusText, body); } diff --git a/packages/api/src/modules/mesh/v1-router.ts b/packages/api/src/modules/mesh/v1-router.ts index d48c8d9..3f925c2 100644 --- a/packages/api/src/modules/mesh/v1-router.ts +++ b/packages/api/src/modules/mesh/v1-router.ts @@ -39,7 +39,7 @@ import { messageQueue, presence, } from "@turbostarter/db/schema/mesh"; -import { and, asc, count, desc, eq, gt, inArray, isNull, lt, sql } from "drizzle-orm"; +import { and, asc, count, desc, eq, gt, inArray, isNull, lt, notInArray, sql } from "drizzle-orm"; import { validate } from "../../middleware"; import { @@ -596,10 +596,7 @@ export const v1Router = new Hono() and( inArray(meshTopicMessage.topicId, topicIds), sql`${meshTopicMessage.createdAt} > COALESCE(${meshTopicMember.lastReadAt}, '1970-01-01'::timestamp)`, - sql`${meshTopicMessage.senderMemberId} NOT IN (${sql.join( - myMemberIds.map((id) => sql`${id}`), - sql`, `, - )})`, + notInArray(meshTopicMessage.senderMemberId, myMemberIds), ), ) .groupBy(meshTopicMessage.topicId); @@ -688,7 +685,7 @@ export const v1Router = new Hono() ) .where( and( - sql`${meshTopicMessage.topicId} = ANY(${topicIds})`, + inArray(meshTopicMessage.topicId, topicIds), sql`${meshTopicMessage.createdAt} > COALESCE(${meshTopicMember.lastReadAt}, '1970-01-01'::timestamp)`, sql`${meshTopicMessage.senderMemberId} <> ${key.issuedByMemberId}`, ),