diff --git a/.changeset/calm-panda-handle.md b/.changeset/calm-panda-handle.md new file mode 100644 index 000000000..ad4b5e9e7 --- /dev/null +++ b/.changeset/calm-panda-handle.md @@ -0,0 +1,5 @@ +--- +"@exactly/server": patch +--- + +🥅 handle expected bridge pairing errors diff --git a/server/hooks/bridge.ts b/server/hooks/bridge.ts index e7c34f69d..cf4a0262b 100644 --- a/server/hooks/bridge.ts +++ b/server/hooks/bridge.ts @@ -3,6 +3,7 @@ import { captureEvent, captureException, setUser } from "@sentry/core"; import createDebug from "debug"; import { and, DrizzleQueryError, eq, isNull } from "drizzle-orm"; import { Hono } from "hono"; +import { HTTPException } from "hono/http-exception"; import { validator } from "hono/validator"; import { createHash, createVerify } from "node:crypto"; import { literal, object, parse, picklist, string, unknown, variant } from "valibot"; @@ -128,7 +129,7 @@ export default new Hono().post( .where(and(eq(credentials.id, referenceId), isNull(credentials.bridgeId))) .returning({ account: credentials.account, source: credentials.source }) .then(([updated]) => { - if (!updated) throw new Error("no match found when pairing bridge id"); + if (!updated) throw new HTTPException(409, { message: "credential pairing failed" }); captureEvent({ message: "bridge credential paired", level: "warning", diff --git a/server/test/hooks/bridge.test.ts b/server/test/hooks/bridge.test.ts index 9141defb6..0d6d81701 100644 --- a/server/test/hooks/bridge.test.ts +++ b/server/test/hooks/bridge.test.ts @@ -285,7 +285,7 @@ describe("bridge hook", () => { }); }); - it("returns 500 when fallback credential already paired", async () => { + it("returns 409 when fallback credential already paired", async () => { vi.spyOn(database.query.credentials, "findFirst").mockResolvedValueOnce(undefined); // eslint-disable-line unicorn/no-useless-undefined vi.spyOn(bridge, "getCustomer").mockResolvedValue({ id: "conflict-bridge-id", @@ -303,7 +303,7 @@ describe("bridge hook", () => { json: payload as never, }); - expect(response.status).toBe(500); + expect(response.status).toBe(409); expect(captureEvent).not.toHaveBeenCalled(); expect(captureException).not.toHaveBeenCalled(); }); @@ -361,7 +361,7 @@ describe("bridge hook", () => { ); }); - it("returns 500 when fallback reference-id has no credential", async () => { + it("returns 409 when fallback reference-id has no credential", async () => { vi.spyOn(bridge, "getCustomer").mockResolvedValue({ id: "orphan-bridge-id", email: "orphan@example.com", @@ -380,7 +380,7 @@ describe("bridge hook", () => { json: payload as never, }); - expect(response.status).toBe(500); + expect(response.status).toBe(409); expect(captureEvent).not.toHaveBeenCalled(); expect(captureException).not.toHaveBeenCalled(); });