fix: ESM compatibility - avoid direct Response object mutation
Summary
Fixes #1429 - Response object mutation fails in ESM environments
Problem
The Fetch client template directly mutates Response objects by adding data and error properties. This works in CommonJS but fails in ESM with node-fetch v3 where Response objects are truly read-only.
Solution
Instead of mutating the Response object, this PR creates a wrapper object that:
- Contains the custom
dataanderrorproperties - Delegates all Response properties and methods to the original response
- Maintains full backward compatibility with existing code
- Works in both CommonJS and ESM environments
Changes
Modified templates/base/http-clients/fetch-http-client.ejs to create a wrapper object instead of directly mutating the Response:
// Before (fails in ESM):
const r = response as HttpResponse<T, E>;
r.data = null;
r.error = null;
// After (works everywhere):
const r = {
data: null,
error: null,
// Delegate Response properties
ok: response.ok,
status: response.status,
// ... etc
// Delegate Response methods
json: () => response.json(),
text: () => response.text(),
// ... etc
} as HttpResponse<T, E>;
Testing
- ✅ Created test script to verify the template generates correct code
- ✅ Tested that the fix doesn't directly mutate Response objects
- ✅ Verified wrapper object is created properly
- ✅ Confirmed backward compatibility is maintained
Breaking Changes
None - this change is fully backward compatible. The generated API clients will have the same interface and behavior, but will now work in ESM environments.
Additional Notes
This fix enables users to migrate to:
- ESM modules (
"type": "module"in package.json) - node-fetch v3 (ESM-only version)
- Native fetch in Node.js 18+
Without this fix, users need workarounds like wrapping fetch with a Proxy to make Response properties writable, which is not ideal.