From 3f71943196b08e333f4d3ebcb45fc538385ddbf5 Mon Sep 17 00:00:00 2001 From: tianxingleo Date: Fri, 13 Mar 2026 14:29:19 +0800 Subject: [PATCH] fix(feishu): unwrap axios-style http responses for token auth --- extensions/feishu/src/client.test.ts | 17 ++++++++++++++++ extensions/feishu/src/client.ts | 29 ++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/extensions/feishu/src/client.test.ts b/extensions/feishu/src/client.test.ts index ccaf6ea6d0d..987ea585260 100644 --- a/extensions/feishu/src/client.test.ts +++ b/extensions/feishu/src/client.test.ts @@ -166,6 +166,23 @@ describe("createFeishuClient HTTP timeout", () => { ); }); + it("normalizes axios-style response wrappers to raw payload objects", async () => { + mockBaseHttpInstance.post.mockResolvedValueOnce({ + data: { tenant_access_token: "tenant_token", expire: 7200 }, + }); + + createFeishuClient({ appId: "app_3b", appSecret: "secret_3b", accountId: "timeout-shape" }); // pragma: allowlist secret + + const calls = (LarkClient as unknown as ReturnType).mock.calls; + const lastCall = calls[calls.length - 1][0] as { + httpInstance: { post: (...args: unknown[]) => Promise }; + }; + const httpInstance = lastCall.httpInstance; + const res = await httpInstance.post("https://example.com/api", { data: 1 }); + + expect(res).toEqual({ tenant_access_token: "tenant_token", expire: 7200 }); + }); + it("uses config-configured default timeout when provided", async () => { createFeishuClient({ appId: "app_4", diff --git a/extensions/feishu/src/client.ts b/extensions/feishu/src/client.ts index d9fdde7f059..5b307f64062 100644 --- a/extensions/feishu/src/client.ts +++ b/extensions/feishu/src/client.ts @@ -48,15 +48,28 @@ function createTimeoutHttpInstance(defaultTimeoutMs: number): Lark.HttpInstance return { timeout: defaultTimeoutMs, ...opts } as Lark.HttpRequestOptions; } + function normalizeResponse(value: T): T { + if (value && typeof value === "object" && "data" in (value as Record)) { + const data = (value as { data?: unknown }).data; + if (data !== undefined) { + return data as T; + } + } + return value; + } + return { - request: (opts) => base.request(injectTimeout(opts)), - get: (url, opts) => base.get(url, injectTimeout(opts)), - post: (url, data, opts) => base.post(url, data, injectTimeout(opts)), - put: (url, data, opts) => base.put(url, data, injectTimeout(opts)), - patch: (url, data, opts) => base.patch(url, data, injectTimeout(opts)), - delete: (url, opts) => base.delete(url, injectTimeout(opts)), - head: (url, opts) => base.head(url, injectTimeout(opts)), - options: (url, opts) => base.options(url, injectTimeout(opts)), + request: async (opts) => normalizeResponse(await base.request(injectTimeout(opts))), + get: async (url, opts) => normalizeResponse(await base.get(url, injectTimeout(opts))), + post: async (url, data, opts) => + normalizeResponse(await base.post(url, data, injectTimeout(opts))), + put: async (url, data, opts) => + normalizeResponse(await base.put(url, data, injectTimeout(opts))), + patch: async (url, data, opts) => + normalizeResponse(await base.patch(url, data, injectTimeout(opts))), + delete: async (url, opts) => normalizeResponse(await base.delete(url, injectTimeout(opts))), + head: async (url, opts) => normalizeResponse(await base.head(url, injectTimeout(opts))), + options: async (url, opts) => normalizeResponse(await base.options(url, injectTimeout(opts))), }; }