From 473c46b840db85c2174934c9d47ba7059172664d Mon Sep 17 00:00:00 2001 From: lukasIO Date: Sat, 25 Jan 2025 20:29:36 +0100 Subject: [PATCH] Improve error insight for twirp related requests (#390) * Improve error insight for twirp related requests * account for non json response * rename status * catch parsing errors * Create gentle-panthers-guess.md * cleanup --- .changeset/gentle-panthers-guess.md | 5 +++ packages/livekit-server-sdk/src/TwirpRPC.ts | 35 ++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 .changeset/gentle-panthers-guess.md diff --git a/.changeset/gentle-panthers-guess.md b/.changeset/gentle-panthers-guess.md new file mode 100644 index 00000000..0d946e06 --- /dev/null +++ b/.changeset/gentle-panthers-guess.md @@ -0,0 +1,5 @@ +--- +"livekit-server-sdk": minor +--- + +Improve error insight for twirp related requests, changes the error signature to custom TwirpError diff --git a/packages/livekit-server-sdk/src/TwirpRPC.ts b/packages/livekit-server-sdk/src/TwirpRPC.ts index aa14c0ef..e02694d1 100644 --- a/packages/livekit-server-sdk/src/TwirpRPC.ts +++ b/packages/livekit-server-sdk/src/TwirpRPC.ts @@ -13,6 +13,18 @@ export interface Rpc { request(service: string, method: string, data: JsonValue, headers?: any): Promise; } +export class TwirpError extends Error { + status: number; + code?: string; + + constructor(name: string, message: string, status: number, code?: string) { + super(message); + this.name = name; + this.status = status; + this.code = code; + } +} + /** * JSON based Twirp V7 RPC */ @@ -47,9 +59,30 @@ export class TwirpRpc { }); if (!response.ok) { - throw new Error(`Request failed with status ${response.status}: ${response.statusText}`); + const isJson = response.headers.get('content-type') === 'application/json'; + let errorMessage = 'Unknown internal error'; + let errorCode: string | undefined = undefined; + try { + if (isJson) { + const parsedError = (await response.json()) as Record; + if ('msg' in parsedError) { + errorMessage = parsedError.msg; + } + if ('code' in parsedError) { + errorCode = parsedError.code; + } + } else { + errorMessage = await response.text(); + } + } catch (e) { + // parsing went wrong, no op and we keep default error message + console.debug(`Error when trying to parse error message, using defaults`, e); + } + + throw new TwirpError(response.statusText, errorMessage, response.status, errorCode); } const parsedResp = (await response.json()) as Record; + const camelcaseKeys = await import('camelcase-keys').then((mod) => mod.default); return camelcaseKeys(parsedResp, { deep: true }); }