From e6391f15471e8befbe93f0b4f57794e4afce1992 Mon Sep 17 00:00:00 2001 From: Ricardo-M-L Date: Fri, 17 Apr 2026 16:21:19 +0800 Subject: [PATCH] fix(volcengine): remove duplicate camelCase keys in createSandbox/listSandboxes JSON body Both createSandbox and listSandboxes explicitly map snake_case parameter fields to PascalCase body keys (e.g. cpuMilli -> CpuMilli, pageSize -> PageSize), then spread `...kwargs[0]` on top. The spread re-adds the original camelCase keys, producing a JSON body that contains both PascalCase and camelCase duplicates for every user-supplied field. Removed the redundant spread so the body only contains the explicitly mapped PascalCase keys as intended. Co-Authored-By: Claude Opus 4.7 (1M context) --- sdk/js/__test__/providers/volcengine.test.ts | 82 ++++++++++++++++++++ sdk/js/src/providers/volcengine.ts | 2 - 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 sdk/js/__test__/providers/volcengine.test.ts diff --git a/sdk/js/__test__/providers/volcengine.test.ts b/sdk/js/__test__/providers/volcengine.test.ts new file mode 100644 index 0000000..3c72ebe --- /dev/null +++ b/sdk/js/__test__/providers/volcengine.test.ts @@ -0,0 +1,82 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// Mock the sign module before importing VolcengineProvider +vi.mock('../../src/providers/sign', () => ({ + request: vi.fn(), +})); + +import { VolcengineProvider } from '../../src/providers/volcengine.js'; +import { request } from '../../src/providers/sign'; + +const mockedRequest = vi.mocked(request); + +describe('VolcengineProvider', () => { + let provider: VolcengineProvider; + + beforeEach(() => { + vi.clearAllMocks(); + provider = new VolcengineProvider({ + accessKey: 'test-access-key', + secretKey: 'test-secret-key', + }); + }); + + describe('createSandbox - no duplicate keys from spread', () => { + it('should not include camelCase duplicates of PascalCase fields', async () => { + mockedRequest.mockResolvedValue({ Result: { SandboxId: 'sb-123' } }); + + await provider.createSandbox('func-123', 60, { + metadata: { key: 'val' }, + cpuMilli: 1000, + memoryMB: 512, + }); + + expect(mockedRequest).toHaveBeenCalledTimes(1); + const bodyStr = mockedRequest.mock.calls[0][8] as string; + const body = JSON.parse(bodyStr); + + // Should have PascalCase keys from explicit mapping + expect(body.FunctionId).toBe('func-123'); + expect(body.CpuMilli).toBe(1000); + expect(body.MemoryMB).toBe(512); + + // Should NOT have camelCase duplicates from spread + expect(body.cpuMilli).toBeUndefined(); + expect(body.memoryMB).toBeUndefined(); + expect(body.metadata).toBeUndefined(); + }); + }); + + describe('listSandboxes - no duplicate keys from spread', () => { + it('should not include camelCase duplicates of PascalCase fields', async () => { + // First call is listSandboxes, second is getApigDomains (ListTriggers) + mockedRequest + .mockResolvedValueOnce({ Result: { Sandboxes: [], Total: 0 } }) + .mockResolvedValueOnce({ Result: { Items: [] } }); + + await provider.listSandboxes('func-123', { + sandboxId: 'sb-456', + pageNumber: 2, + pageSize: 20, + status: 'running', + }); + + // First call is the actual listSandboxes request + const bodyStr = mockedRequest.mock.calls[0][8] as string; + const body = JSON.parse(bodyStr); + + // Should have PascalCase keys from explicit mapping + expect(body.FunctionId).toBe('func-123'); + expect(body.SandboxId).toBe('sb-456'); + expect(body.PageNumber).toBe(2); + expect(body.PageSize).toBe(20); + expect(body.Status).toBe('running'); + + // Should NOT have camelCase duplicates from spread + expect(body.sandboxId).toBeUndefined(); + expect(body.pageNumber).toBeUndefined(); + expect(body.pageSize).toBeUndefined(); + expect(body.status).toBeUndefined(); + }); + }); +}); diff --git a/sdk/js/src/providers/volcengine.ts b/sdk/js/src/providers/volcengine.ts index 27ea262..1b2f822 100644 --- a/sdk/js/src/providers/volcengine.ts +++ b/sdk/js/src/providers/volcengine.ts @@ -69,7 +69,6 @@ export class VolcengineProvider extends BaseProvider { MemoryMB: params.memoryMB, MaxConcurrency: params.maxConcurrency, RequestTimeout: params.requestTimeout, - ...kwargs[0] }); const response = await request( @@ -263,7 +262,6 @@ export class VolcengineProvider extends BaseProvider { PageSize: params.pageSize || 10, ImageUrl: params.imageUrl, Status: params.status, - ...kwargs[0] }); const response = await request(