Fix Node.js SDK routes and multipart handling (#28573)

This commit is contained in:
yyh
2025-11-24 21:00:40 +08:00
committed by GitHub
parent aab95d0626
commit 034e3e85e9
5 changed files with 111 additions and 30 deletions

View File

@@ -0,0 +1,12 @@
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "current",
},
},
],
],
};

View File

@@ -71,7 +71,7 @@ export const routes = {
},
stopWorkflow: {
method: "POST",
url: (task_id) => `/workflows/${task_id}/stop`,
url: (task_id) => `/workflows/tasks/${task_id}/stop`,
}
};
@@ -94,11 +94,13 @@ export class DifyClient {
stream = false,
headerParams = {}
) {
const isFormData =
(typeof FormData !== "undefined" && data instanceof FormData) ||
(data && data.constructor && data.constructor.name === "FormData");
const headers = {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
...headerParams
Authorization: `Bearer ${this.apiKey}`,
...(isFormData ? {} : { "Content-Type": "application/json" }),
...headerParams,
};
const url = `${this.baseUrl}${endpoint}`;
@@ -152,12 +154,7 @@ export class DifyClient {
return this.sendRequest(
routes.fileUpload.method,
routes.fileUpload.url(),
data,
null,
false,
{
"Content-Type": 'multipart/form-data'
}
data
);
}
@@ -179,8 +176,8 @@ export class DifyClient {
getMeta(user) {
const params = { user };
return this.sendRequest(
routes.meta.method,
routes.meta.url(),
routes.getMeta.method,
routes.getMeta.url(),
null,
params
);
@@ -320,12 +317,7 @@ export class ChatClient extends DifyClient {
return this.sendRequest(
routes.audioToText.method,
routes.audioToText.url(),
data,
null,
false,
{
"Content-Type": 'multipart/form-data'
}
data
);
}

View File

@@ -1,9 +1,13 @@
import { DifyClient, BASE_URL, routes } from ".";
import { DifyClient, WorkflowClient, BASE_URL, routes } from ".";
import axios from 'axios'
jest.mock('axios')
afterEach(() => {
jest.resetAllMocks()
})
describe('Client', () => {
let difyClient
beforeEach(() => {
@@ -27,13 +31,9 @@ describe('Send Requests', () => {
difyClient = new DifyClient('test')
})
afterEach(() => {
jest.resetAllMocks()
})
it('should make a successful request to the application parameter', async () => {
const method = 'GET'
const endpoint = routes.application.url
const endpoint = routes.application.url()
const expectedResponse = { data: 'response' }
axios.mockResolvedValue(expectedResponse)
@@ -62,4 +62,80 @@ describe('Send Requests', () => {
errorMessage
)
})
it('uses the getMeta route configuration', async () => {
axios.mockResolvedValue({ data: 'ok' })
await difyClient.getMeta('end-user')
expect(axios).toHaveBeenCalledWith({
method: routes.getMeta.method,
url: `${BASE_URL}${routes.getMeta.url()}`,
params: { user: 'end-user' },
headers: {
Authorization: `Bearer ${difyClient.apiKey}`,
'Content-Type': 'application/json',
},
responseType: 'json',
})
})
})
describe('File uploads', () => {
let difyClient
const OriginalFormData = global.FormData
beforeAll(() => {
global.FormData = class FormDataMock {}
})
afterAll(() => {
global.FormData = OriginalFormData
})
beforeEach(() => {
difyClient = new DifyClient('test')
})
it('does not override multipart boundary headers for FormData', async () => {
const form = new FormData()
axios.mockResolvedValue({ data: 'ok' })
await difyClient.fileUpload(form)
expect(axios).toHaveBeenCalledWith({
method: routes.fileUpload.method,
url: `${BASE_URL}${routes.fileUpload.url()}`,
data: form,
params: null,
headers: {
Authorization: `Bearer ${difyClient.apiKey}`,
},
responseType: 'json',
})
})
})
describe('Workflow client', () => {
let workflowClient
beforeEach(() => {
workflowClient = new WorkflowClient('test')
})
it('uses tasks stop path for workflow stop', async () => {
axios.mockResolvedValue({ data: 'stopped' })
await workflowClient.stop('task-1', 'end-user')
expect(axios).toHaveBeenCalledWith({
method: routes.stopWorkflow.method,
url: `${BASE_URL}${routes.stopWorkflow.url('task-1')}`,
data: { user: 'end-user' },
params: null,
headers: {
Authorization: `Bearer ${workflowClient.apiKey}`,
'Content-Type': 'application/json',
},
responseType: 'json',
})
})
})

View File

@@ -0,0 +1,6 @@
module.exports = {
testEnvironment: "node",
transform: {
"^.+\\.[tj]sx?$": "babel-jest",
},
};

View File

@@ -18,11 +18,6 @@
"scripts": {
"test": "jest"
},
"jest": {
"transform": {
"^.+\\.[t|j]sx?$": "babel-jest"
}
},
"dependencies": {
"axios": "^1.3.5"
},