From f216c1ece39d2471ccd392402b5e4fa71cf45534 Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Tue, 12 May 2026 22:36:40 -0700 Subject: [PATCH] fix(cost): remove deprecated device.heartbeat tRPC route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The renderer caller was removed in #2904 (2026-03-28) and the MINIMUM_DESKTOP_VERSION floor (1.5.0, 2026-04-11) blocks any client that predates the caller removal from using the app. The endpoint was kept "for backwards compat with shipped clients", but the only clients still polling are stuck behind the UpdateRequiredPage gate and their heartbeat traffic has no downstream consumer — heartbeat only updates devicePresence.lastSeenAt, which is purely cosmetic (MCP list-devices ORDER BY). Removing the route turns those stale-build calls into a silent tRPC NOT_FOUND. registerDevice stays — MCP's executeOnDevice still uses the row for ownership verification. Trims ~10% of /api log volume on Vercel. --- packages/trpc/src/router/device/device.ts | 48 ----------------------- 1 file changed, 48 deletions(-) diff --git a/packages/trpc/src/router/device/device.ts b/packages/trpc/src/router/device/device.ts index 3a2478252bb..cc5da7e7594 100644 --- a/packages/trpc/src/router/device/device.ts +++ b/packages/trpc/src/router/device/device.ts @@ -10,54 +10,6 @@ import { protectedProcedure } from "../../trpc"; * the rest of v1. */ export const deviceRouter = { - /** - * @deprecated Kept for backwards compat with shipped desktop/mobile clients - * that still call heartbeat on a 30s interval. Same logic as registerDevice. - */ - heartbeat: protectedProcedure - .input( - z.object({ - deviceId: z.string().min(1), - deviceName: z.string().min(1), - deviceType: z.enum(deviceTypeValues), - }), - ) - .mutation(async ({ ctx, input }) => { - const organizationId = ctx.activeOrganizationId; - if (!organizationId) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "No active organization selected", - }); - } - - const userId = ctx.session.user.id; - const now = new Date(); - - await db - .insert(devicePresence) - .values({ - userId, - organizationId, - deviceId: input.deviceId, - deviceName: input.deviceName, - deviceType: input.deviceType, - lastSeenAt: now, - createdAt: now, - }) - .onConflictDoUpdate({ - target: [devicePresence.userId, devicePresence.deviceId], - set: { - deviceName: input.deviceName, - deviceType: input.deviceType, - lastSeenAt: now, - organizationId, - }, - }); - - return { success: true }; - }), - /** * Register device presence (called once on app startup). * Upserts a row so MCP can verify device ownership.