Description
Description
We have identified a memory leak in our application that appears to be related to the swagger-typescript-api package. After thorough investigation, we traced the issue to a change introduced in this commit, which was merged on September 5, 2024.
Problem
In the commit referenced above, the response of the auto-generated customFetch function is cloned before being returned. This clone operation is causing a memory leak in our application.
Observation
Without the clone operation, the memory leak does not occur.
The memory usage increases steadily when the clone method is used, indicating a potential problem with how the response is handled.
Steps to Reproduce
Use the swagger-typescript-api package version that includes the commit ac99885.
Generate API client code using swagger-typescript-api.
Make API requests using the generated client.
Observe memory usage over time with and without the response being cloned.
Expected Behavior
The response should be returned without causing a memory leak, and the memory usage should remain stable.
Actual Behavior
The memory usage increases steadily, leading to a memory leak when the response is cloned.
Additional Context
Here's a snippet of the auto-generated code that causes the issue:
return this.customFetch(`${baseUrl || this.baseUrl || ''}${path}${queryString ? `?${queryString}` : ''}`, {
...requestParams,
headers: {
...(requestParams.headers || {}),
...(type && type !== ContentType.FormData ? { 'Content-Type': type } : {}),
},
signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null,
body: typeof body === 'undefined' || body === null ? null : payloadFormatter(body),
}).then(async (response) => {
const r = response.clone() as HttpResponse<T, E>;
r.data = null as unknown as T;
r.error = null as unknown as E;
const data = !responseFormat
? r
: await response[responseFormat]()
.then((data) => {
if (r.ok) {
r.data = data;
} else {
r.error = data;
}
return r;
})
.catch((e) => {
r.error = e;
return r;
});
if (cancelToken) {
this.abortControllers.delete(cancelToken);
}
if (!response.ok) throw data;
return data;
});
};
}